blob: 7c01d63fca03212a1ed2230671be9d2925789210 [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_ADJUST_BELOW_PERCEPTIBLE;
46import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
47import static android.content.Context.BIND_AUTO_CREATE;
48import static android.content.Context.BIND_FOREGROUND_SERVICE;
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
Adam Lesinski182f73f2013-12-05 16:48:06 -0800286 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
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;
Beverly5d463b62017-07-26 14:13:40 -0400400 protected boolean mInCall = 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) {
John Spurlocke6a7d932014-03-13 12:29:00 -0400895 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400896 REASON_ERROR, null);
Joe Onorato005847b2010-06-04 16:08:02 -0400897 }
John Spurlocke677d712014-02-13 12:52:19 -0500898
899 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400900 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
901 NotificationVisibility[] noLongerVisibleKeys) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500902 synchronized (mNotificationLock) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400903 for (NotificationVisibility nv : newlyVisibleKeys) {
904 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200905 if (r == null) continue;
Amith Yamasani803eab692017-11-09 17:47:04 -0800906 if (!r.isSeen()) {
907 // Report to usage stats that notification was made visible
908 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
909 reportSeen(r);
910 }
Dieter Hsud39f0d52018-04-14 02:08:30 +0800911 r.setVisibility(true, nv.rank, nv.count);
Gustav Senntonc7d0d322019-01-07 15:36:41 +0000912 boolean isHun = (nv.location
913 == NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP);
Gustav Sennton44dc5882018-12-13 14:38:50 +0000914 // hasBeenVisiblyExpanded must be called after updating the expansion state of
915 // the NotificationRecord to ensure the expansion state is up-to-date.
Gustav Senntonc7d0d322019-01-07 15:36:41 +0000916 if (isHun || r.hasBeenVisiblyExpanded()) {
917 logSmartSuggestionsVisible(r, nv.location.toMetricsEventEnum());
Gustav Sennton44dc5882018-12-13 14:38:50 +0000918 }
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400919 maybeRecordInterruptionLocked(r);
Chris Wrend1dbc922015-06-19 17:51:16 -0400920 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200921 }
922 // Note that we might receive this event after notifications
923 // have already left the system, e.g. after dismissing from the
924 // shade. Hence not finding notifications in
925 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400926 for (NotificationVisibility nv : noLongerVisibleKeys) {
927 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200928 if (r == null) continue;
Dieter Hsud39f0d52018-04-14 02:08:30 +0800929 r.setVisibility(false, nv.rank, nv.count);
Chris Wrend1dbc922015-06-19 17:51:16 -0400930 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200931 }
932 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200933 }
Chris Wren78403d72014-07-28 10:23:24 +0100934
935 @Override
936 public void onNotificationExpansionChanged(String key,
Gustav Senntona8e38aa2019-01-22 14:55:39 +0000937 boolean userAction, boolean expanded, int notificationLocation) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500938 synchronized (mNotificationLock) {
Chris Wren78403d72014-07-28 10:23:24 +0100939 NotificationRecord r = mNotificationsByKey.get(key);
940 if (r != null) {
941 r.stats.onExpansionChanged(userAction, expanded);
Gustav Sennton44dc5882018-12-13 14:38:50 +0000942 // hasBeenVisiblyExpanded must be called after updating the expansion state of
943 // the NotificationRecord to ensure the expansion state is up-to-date.
944 if (r.hasBeenVisiblyExpanded()) {
Gustav Senntonc7d0d322019-01-07 15:36:41 +0000945 logSmartSuggestionsVisible(r, notificationLocation);
Gustav Sennton44dc5882018-12-13 14:38:50 +0000946 }
Chris Wrenf7342712017-09-14 10:55:55 -0400947 if (userAction) {
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400948 MetricsLogger.action(r.getItemLogMaker()
Chris Wrenf7342712017-09-14 10:55:55 -0400949 .setType(expanded ? MetricsEvent.TYPE_DETAIL
950 : MetricsEvent.TYPE_COLLAPSE));
Chris Wren377ac6d2017-09-12 14:15:23 -0400951 }
Julia Reynolds84dc96b2017-11-14 09:51:01 -0500952 if (expanded && userAction) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400953 r.recordExpanded();
Esteban Talavera917a71d2018-11-13 07:55:08 +0000954 reportUserInteraction(r);
Julia Reynolds503ed942017-10-04 16:04:56 -0400955 }
Tony Makeda84a72018-11-19 17:01:32 +0000956 mAssistants.notifyAssistantExpansionChangedLocked(r.sbn, userAction, expanded);
Chris Wren78403d72014-07-28 10:23:24 +0100957 }
958 }
959 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400960
961 @Override
962 public void onNotificationDirectReplied(String key) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800963 exitIdle();
Julia Reynolds503ed942017-10-04 16:04:56 -0400964 synchronized (mNotificationLock) {
965 NotificationRecord r = mNotificationsByKey.get(key);
966 if (r != null) {
967 r.recordDirectReplied();
Esteban Talaveraf9c53b62018-11-14 18:20:29 +0000968 mMetricsLogger.write(r.getLogMaker()
969 .setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION)
970 .setType(MetricsEvent.TYPE_ACTION));
Amith Yamasani7ec89412018-02-07 08:48:49 -0800971 reportUserInteraction(r);
Tony Makeda84a72018-11-19 17:01:32 +0000972 mAssistants.notifyAssistantNotificationDirectReplyLocked(r.sbn);
Julia Reynolds503ed942017-10-04 16:04:56 -0400973 }
974 }
975 }
976
977 @Override
Gustav Senntond25a64d2018-12-07 10:58:39 +0000978 public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount,
Milo Sredkov13d88112019-02-01 12:23:24 +0000979 int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) {
Kenny Guy23991102018-04-05 21:18:38 +0100980 synchronized (mNotificationLock) {
981 NotificationRecord r = mNotificationsByKey.get(key);
982 if (r != null) {
Gustav Senntond25a64d2018-12-07 10:58:39 +0000983 r.setNumSmartRepliesAdded(smartReplyCount);
984 r.setNumSmartActionsAdded(smartActionCount);
985 r.setSuggestionsGeneratedByAssistant(generatedByAssistant);
Milo Sredkov13d88112019-02-01 12:23:24 +0000986 r.setEditChoicesBeforeSending(editBeforeSending);
Kenny Guy23991102018-04-05 21:18:38 +0100987 }
988 }
989 }
990
991 @Override
Tony Mak29996702018-11-26 16:23:34 +0000992 public void onNotificationSmartReplySent(String key, int replyIndex, CharSequence reply,
Milo Sredkov13d88112019-02-01 12:23:24 +0000993 int notificationLocation, boolean modifiedBeforeSending) {
Gustav Senntond25a64d2018-12-07 10:58:39 +0000994
Kenny Guy23991102018-04-05 21:18:38 +0100995 synchronized (mNotificationLock) {
996 NotificationRecord r = mNotificationsByKey.get(key);
997 if (r != null) {
998 LogMaker logMaker = r.getLogMaker()
999 .setCategory(MetricsEvent.SMART_REPLY_ACTION)
Gustav Sennton13edb492019-01-28 21:40:04 +00001000 .setSubtype(replyIndex)
1001 .addTaggedData(
1002 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
Milo Sredkov13d88112019-02-01 12:23:24 +00001003 r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
Gustav Sennton13edb492019-01-28 21:40:04 +00001004 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
Milo Sredkov13d88112019-02-01 12:23:24 +00001005 notificationLocation)
1006 .addTaggedData(
1007 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
1008 r.getEditChoicesBeforeSending() ? 1 : 0)
1009 .addTaggedData(
1010 MetricsEvent.NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING,
1011 modifiedBeforeSending ? 1 : 0);
Kenny Guy23991102018-04-05 21:18:38 +01001012 mMetricsLogger.write(logMaker);
1013 // Treat clicking on a smart reply as a user interaction.
1014 reportUserInteraction(r);
Tony Mak29996702018-11-26 16:23:34 +00001015 mAssistants.notifyAssistantSuggestedReplySent(
Milo Sredkov13d88112019-02-01 12:23:24 +00001016 r.sbn, reply, r.getSuggestionsGeneratedByAssistant());
Kenny Guy23991102018-04-05 21:18:38 +01001017 }
1018 }
1019 }
1020
1021 @Override
Julia Reynolds503ed942017-10-04 16:04:56 -04001022 public void onNotificationSettingsViewed(String key) {
1023 synchronized (mNotificationLock) {
1024 NotificationRecord r = mNotificationsByKey.get(key);
1025 if (r != null) {
1026 r.recordViewedSettings();
1027 }
1028 }
1029 }
Mady Mellora54e9fa2019-04-18 13:26:18 -07001030
1031 @Override
1032 public void onNotificationBubbleChanged(String key, boolean isBubble) {
1033 synchronized (mNotificationLock) {
1034 NotificationRecord r = mNotificationsByKey.get(key);
1035 if (r != null) {
1036 final StatusBarNotification n = r.sbn;
1037 final int callingUid = n.getUid();
1038 final String pkg = n.getPackageName();
Mady Mellor66efd5e2019-05-15 13:38:11 -07001039 final boolean wasBubble = r.getNotification().isBubbleNotification();
Mady Mellora54e9fa2019-04-18 13:26:18 -07001040 if (isBubble && isNotificationAppropriateToBubble(r, pkg, callingUid,
1041 null /* oldEntry */)) {
1042 r.getNotification().flags |= FLAG_BUBBLE;
1043 } else {
1044 r.getNotification().flags &= ~FLAG_BUBBLE;
1045 }
Mady Mellor66efd5e2019-05-15 13:38:11 -07001046 if (wasBubble != r.getNotification().isBubbleNotification()) {
1047 // Add the "alert only once" flag so that the notification won't HUN
1048 // unnecessarily just because the bubble flag was changed.
1049 r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
1050 mListeners.notifyPostedLocked(r, r);
1051 }
Mady Mellora54e9fa2019-04-18 13:26:18 -07001052 }
1053 }
1054 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 };
1056
Gustav Sennton44dc5882018-12-13 14:38:50 +00001057 @VisibleForTesting
Gustav Senntonc7d0d322019-01-07 15:36:41 +00001058 void logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation) {
Gustav Sennton44dc5882018-12-13 14:38:50 +00001059 // If the newly visible notification has smart suggestions
1060 // then log that the user has seen them.
1061 if ((r.getNumSmartRepliesAdded() > 0 || r.getNumSmartActionsAdded() > 0)
1062 && !r.hasSeenSmartReplies()) {
1063 r.setSeenSmartReplies(true);
1064 LogMaker logMaker = r.getLogMaker()
1065 .setCategory(MetricsEvent.SMART_REPLY_VISIBLE)
1066 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT,
1067 r.getNumSmartRepliesAdded())
1068 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_ACTION_COUNT,
1069 r.getNumSmartActionsAdded())
1070 .addTaggedData(
1071 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
Gustav Senntonc7d0d322019-01-07 15:36:41 +00001072 r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
1073 // The fields in the NotificationVisibility.NotificationLocation enum map
1074 // directly to the fields in the MetricsEvent.NotificationLocation enum.
Milo Sredkov13d88112019-02-01 12:23:24 +00001075 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, notificationLocation)
1076 .addTaggedData(
1077 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
1078 r.getEditChoicesBeforeSending() ? 1 : 0);
Gustav Sennton44dc5882018-12-13 14:38:50 +00001079 mMetricsLogger.write(logMaker);
1080 }
1081 }
1082
Julia Reynolds88860ce2017-06-01 16:55:49 -04001083 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04001084 private void clearSoundLocked() {
1085 mSoundNotificationKey = null;
1086 long identity = Binder.clearCallingIdentity();
1087 try {
1088 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
1089 if (player != null) {
1090 player.stopAsync();
1091 }
1092 } catch (RemoteException e) {
1093 } finally {
1094 Binder.restoreCallingIdentity(identity);
1095 }
1096 }
1097
Julia Reynolds88860ce2017-06-01 16:55:49 -04001098 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04001099 private void clearVibrateLocked() {
1100 mVibrateNotificationKey = null;
1101 long identity = Binder.clearCallingIdentity();
1102 try {
1103 mVibrator.cancel();
1104 } finally {
1105 Binder.restoreCallingIdentity(identity);
1106 }
1107 }
1108
Julia Reynolds88860ce2017-06-01 16:55:49 -04001109 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04001110 private void clearLightsLocked() {
1111 // light
1112 mLights.clear();
1113 updateLightsLocked();
1114 }
1115
Beverlyd4f96492017-08-02 13:36:11 -04001116 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
1117 @Override
1118 public void onReceive(Context context, Intent intent) {
1119 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
Beverly70dcd002018-03-29 17:09:16 -04001120 // update system notification channels
1121 SystemNotificationChannels.createAll(context);
Beverlyd4f96492017-08-02 13:36:11 -04001122 mZenModeHelper.updateDefaultZenRules();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001123 mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
Beverlyd4f96492017-08-02 13:36:11 -04001124 }
1125 }
1126 };
1127
Julia Reynoldsb852e562017-06-06 16:14:18 -04001128 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
1129 @Override
1130 public void onReceive(Context context, Intent intent) {
1131 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
1132 try {
1133 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
1134 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
Michal Karpinski6135a262017-08-11 10:45:58 +01001135 int restoredFromSdkInt = intent.getIntExtra(
1136 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
Julia Reynoldsfa206a42017-08-14 13:22:23 -04001137 mListeners.onSettingRestored(
1138 element, newValue, restoredFromSdkInt, getSendingUserId());
1139 mConditionProviders.onSettingRestored(
1140 element, newValue, restoredFromSdkInt, getSendingUserId());
Julia Reynoldsb852e562017-06-06 16:14:18 -04001141 } catch (Exception e) {
1142 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
1143 }
1144 }
1145 }
1146 };
1147
Julia Reynolds2a128742016-11-28 14:29:25 -05001148 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
1149 @Override
1150 public void onReceive(Context context, Intent intent) {
1151 String action = intent.getAction();
1152 if (action == null) {
1153 return;
1154 }
1155 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
1156 final NotificationRecord record;
1157 synchronized (mNotificationLock) {
1158 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
1159 }
1160 if (record != null) {
1161 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
1162 record.sbn.getPackageName(), record.sbn.getTag(),
1163 record.sbn.getId(), 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -04001164 FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
Julia Reynolds2a128742016-11-28 14:29:25 -05001165 REASON_TIMEOUT, null);
1166 }
1167 }
1168 }
1169 };
1170
Kenny Guy70058402014-10-28 20:45:06 +00001171 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 @Override
1173 public void onReceive(Context context, Intent intent) {
1174 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -08001175 if (action == null) {
1176 return;
1177 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001179 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -04001180 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -04001181 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -04001182 boolean cancelNotifications = true;
Beverly5a20a5e2018-03-06 15:02:44 -05001183 boolean hideNotifications = false;
1184 boolean unhideNotifications = false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001185 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -04001186
Chris Wren3da73022013-05-10 14:41:21 -04001187 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -04001188 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001189 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -04001190 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001191 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001192 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
Beverly5a20a5e2018-03-06 15:02:44 -05001193 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
Julia Reynolds0e5a3432019-01-17 09:40:46 -05001194 || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)
1195 || action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
Kenny Guy70058402014-10-28 20:45:06 +00001196 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1197 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001198 String pkgList[] = null;
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001199 int uidList[] = null;
Julia Reynolds6434eb22016-08-08 17:19:26 -04001200 boolean removingPackage = queryRemove &&
1201 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
1202 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001203 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001204 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001205 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001206 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
1207 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4bc42b92018-08-14 11:27:35 -04001208 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Beverly5a20a5e2018-03-06 15:02:44 -05001209 cancelNotifications = false;
1210 hideNotifications = true;
1211 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
1212 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4bc42b92018-08-14 11:27:35 -04001213 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Beverly5a20a5e2018-03-06 15:02:44 -05001214 cancelNotifications = false;
1215 unhideNotifications = true;
Julia Reynolds0e5a3432019-01-17 09:40:46 -05001216 } else if (action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
1217 final int distractionRestrictions =
1218 intent.getIntExtra(Intent.EXTRA_DISTRACTION_RESTRICTIONS,
1219 PackageManager.RESTRICTION_NONE);
1220 if ((distractionRestrictions
1221 & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0) {
1222 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1223 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1224 cancelNotifications = false;
1225 hideNotifications = true;
1226 } else {
1227 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1228 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1229 cancelNotifications = false;
1230 unhideNotifications = true;
1231 }
1232
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001233 } else if (queryRestart) {
1234 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001235 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001236 } else {
1237 Uri uri = intent.getData();
1238 if (uri == null) {
1239 return;
1240 }
1241 String pkgName = uri.getSchemeSpecificPart();
1242 if (pkgName == null) {
1243 return;
1244 }
Daniel Sandler26ece572012-06-01 15:38:46 -04001245 if (packageChanged) {
1246 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -07001247 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001248 final int enabled = mPackageManager.getApplicationEnabledSetting(
1249 pkgName,
Kenny Guy70058402014-10-28 20:45:06 +00001250 changeUserId != UserHandle.USER_ALL ? changeUserId :
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001251 USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -07001252 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1253 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
1254 cancelNotifications = false;
1255 }
1256 } catch (IllegalArgumentException e) {
1257 // Package doesn't exist; probably racing with uninstall.
1258 // cancelNotifications is already true, so nothing to do here.
1259 if (DBG) {
1260 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
1261 }
Kenny Guy70058402014-10-28 20:45:06 +00001262 } catch (RemoteException e) {
1263 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -04001264 }
1265 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001266 pkgList = new String[]{pkgName};
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001267 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001269 if (pkgList != null && (pkgList.length > 0)) {
1270 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -04001271 if (cancelNotifications) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001272 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
1273 !queryRestart, changeUserId, reason, null);
Beverly5a20a5e2018-03-06 15:02:44 -05001274 } else if (hideNotifications) {
1275 hideNotificationsForPackages(pkgList);
1276 } else if (unhideNotifications) {
1277 unhideNotificationsForPackages(pkgList);
John Spurlock79f78922013-05-16 09:10:05 -04001278 }
Beverly5a20a5e2018-03-06 15:02:44 -05001279
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 }
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001282
Julia Reynoldsb0405592018-11-26 17:01:13 -05001283 mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001284 handleSavePolicyFile();
Kenny Guy70058402014-10-28 20:45:06 +00001285 }
1286 }
1287 };
1288
1289 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1290 @Override
1291 public void onReceive(Context context, Intent intent) {
1292 String action = intent.getAction();
1293
1294 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001295 // Keep track of screen on/off state, but do not turn off the notification light
1296 // until user passes through the lock screen or views the notification.
1297 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +01001298 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001299 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1300 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +01001301 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001302 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -05001303 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
1304 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001305 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001306 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
1307 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1308 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001309 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001310 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001311 }
Rubin Xue95057a2016-04-01 16:49:25 +01001312 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001313 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +01001314 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001315 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001316 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001317 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001318 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1319 // turn off LED when user passes through lock screen
1320 mNotificationLight.turnOff();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001321 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Julia Reynolds4ff97492018-09-24 14:53:54 -04001322 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
John Spurlockb408e8e2014-04-23 21:12:45 -04001323 mUserProfiles.updateCache(context);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001324 if (!mUserProfiles.isManagedProfile(userId)) {
1325 // reload per-user settings
1326 mSettingsObserver.update(null);
1327 // Refresh managed services
1328 mConditionProviders.onUserSwitched(userId);
1329 mListeners.onUserSwitched(userId);
1330 mZenModeHelper.onUserSwitched(userId);
Beverly0479cde22018-11-09 11:05:34 -05001331 mPreferencesHelper.onUserSwitched(userId);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001332 }
1333 // assistant is the only thing that cares about managed profiles specifically
1334 mAssistants.onUserSwitched(userId);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001335 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001336 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1337 if (userId != USER_NULL) {
1338 mUserProfiles.updateCache(context);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001339 if (!mUserProfiles.isManagedProfile(userId)) {
1340 readDefaultApprovedServices(userId);
1341 }
Julia Reynolds88a879f2017-07-26 17:06:46 -04001342 }
John Spurlock21258a32015-05-27 18:22:55 -04001343 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
Julia Reynolds4ff97492018-09-24 14:53:54 -04001344 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001345 mUserProfiles.updateCache(context);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001346 mZenModeHelper.onUserRemoved(userId);
1347 mPreferencesHelper.onUserRemoved(userId);
1348 mListeners.onUserRemoved(userId);
1349 mConditionProviders.onUserRemoved(userId);
1350 mAssistants.onUserRemoved(userId);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001351 handleSavePolicyFile();
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001352 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
Julia Reynolds4ff97492018-09-24 14:53:54 -04001353 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1354 mUserProfiles.updateCache(context);
1355 mAssistants.onUserUnlocked(userId);
1356 if (!mUserProfiles.isManagedProfile(userId)) {
1357 mConditionProviders.onUserUnlocked(userId);
1358 mListeners.onUserUnlocked(userId);
1359 mZenModeHelper.onUserUnlocked(userId);
Beverly0479cde22018-11-09 11:05:34 -05001360 mPreferencesHelper.onUserUnlocked(userId);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001361 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362 }
1363 }
1364 };
1365
John Spurlock7c74f782015-06-04 13:01:42 -04001366 private final class SettingsObserver extends ContentObserver {
Chris Wren89aa2262017-05-05 18:05:56 -04001367 private final Uri NOTIFICATION_BADGING_URI
1368 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
Julia Reynolds4509ce72019-01-31 13:12:43 -05001369 private final Uri NOTIFICATION_BUBBLES_URI
1370 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BUBBLES);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001371 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1372 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wren763a9bb2016-05-31 17:14:12 -04001373 private final Uri NOTIFICATION_RATE_LIMIT_URI
1374 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001375
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001376 SettingsObserver(Handler handler) {
1377 super(handler);
1378 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001379
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001380 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001381 ContentResolver resolver = getContext().getContentResolver();
Chris Wren89aa2262017-05-05 18:05:56 -04001382 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1383 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001384 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -07001385 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -04001386 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1387 false, this, UserHandle.USER_ALL);
Julia Reynolds4509ce72019-01-31 13:12:43 -05001388 resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI,
1389 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001390 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001391 }
1392
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001393 @Override public void onChange(boolean selfChange, Uri uri) {
1394 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001395 }
1396
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001397 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001398 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001399 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
zhoulei7e376972017-05-17 18:41:25 +08001400 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
Julia Reynolds28149f62018-07-03 10:43:35 -04001401 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT)
1402 != 0;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001403 if (mNotificationPulseEnabled != pulseEnabled) {
1404 mNotificationPulseEnabled = pulseEnabled;
1405 updateNotificationPulse();
1406 }
1407 }
Chris Wren763a9bb2016-05-31 17:14:12 -04001408 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1409 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1410 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1411 }
Chris Wren89aa2262017-05-05 18:05:56 -04001412 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001413 mPreferencesHelper.updateBadgingEnabled();
Chris Wren89aa2262017-05-05 18:05:56 -04001414 }
Julia Reynolds4509ce72019-01-31 13:12:43 -05001415 if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) {
1416 mPreferencesHelper.updateBubblesEnabled();
1417 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001418 }
1419 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001420
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001421 private SettingsObserver mSettingsObserver;
Beverlyd4f96492017-08-02 13:36:11 -04001422 protected ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001423
Daniel Sandleredbb3802012-11-13 20:49:47 -08001424 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1425 int[] ar = r.getIntArray(resid);
1426 if (ar == null) {
1427 return def;
1428 }
1429 final int len = ar.length > maxlen ? maxlen : ar.length;
1430 long[] out = new long[len];
1431 for (int i=0; i<len; i++) {
1432 out[i] = ar[i];
1433 }
1434 return out;
1435 }
1436
Jeff Brownb880d882014-02-10 19:47:07 -08001437 public NotificationManagerService(Context context) {
1438 super(context);
Dianne Hackborn98305522017-05-05 17:53:53 -07001439 Notification.processWhitelistToken = WHITELIST_TOKEN;
Jeff Brownb880d882014-02-10 19:47:07 -08001440 }
1441
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001442 // TODO - replace these methods with a single VisibleForTesting constructor
Chris Wren93bb8b82016-03-29 14:35:05 -04001443 @VisibleForTesting
1444 void setAudioManager(AudioManager audioMananger) {
1445 mAudioManager = audioMananger;
1446 }
1447
1448 @VisibleForTesting
Julia Reynoldsdb7081e2019-01-03 14:35:38 -05001449 void setHints(int hints) {
1450 mListenerHints = hints;
1451 }
1452
1453 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001454 void setVibrator(Vibrator vibrator) {
1455 mVibrator = vibrator;
1456 }
1457
1458 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001459 void setLights(Light light) {
1460 mNotificationLight = light;
1461 mAttentionLight = light;
Julia Reynolds033a4122017-01-31 16:50:38 -05001462 mNotificationPulseEnabled = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001463 }
1464
1465 @VisibleForTesting
1466 void setScreenOn(boolean on) {
1467 mScreenOn = on;
1468 }
1469
1470 @VisibleForTesting
Julia Reynolds080361e2017-07-13 11:23:12 -04001471 int getNotificationRecordCount() {
1472 synchronized (mNotificationLock) {
1473 int count = mNotificationList.size() + mNotificationsByKey.size()
1474 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1475 // subtract duplicates
1476 for (NotificationRecord posted : mNotificationList) {
1477 if (mNotificationsByKey.containsKey(posted.getKey())) {
1478 count--;
1479 }
1480 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001481 count--;
Julia Reynolds080361e2017-07-13 11:23:12 -04001482 }
1483 }
1484
1485 return count;
1486 }
1487 }
1488
Julia Reynolds7380d872018-01-12 10:28:26 -05001489 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001490 void clearNotifications() {
1491 mEnqueuedNotifications.clear();
1492 mNotificationList.clear();
1493 mNotificationsByKey.clear();
1494 mSummaryByGroupKey.clear();
1495 }
1496
Julia Reynolds080361e2017-07-13 11:23:12 -04001497 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001498 void addNotification(NotificationRecord r) {
1499 mNotificationList.add(r);
1500 mNotificationsByKey.put(r.sbn.getKey(), r);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001501 if (r.sbn.isGroup()) {
1502 mSummaryByGroupKey.put(r.getGroupKey(), r);
1503 }
1504 }
1505
1506 @VisibleForTesting
1507 void addEnqueuedNotification(NotificationRecord r) {
1508 mEnqueuedNotifications.add(r);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001509 }
1510
1511 @VisibleForTesting
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001512 NotificationRecord getNotificationRecord(String key) {
1513 return mNotificationsByKey.get(key);
1514 }
1515
1516
1517 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001518 void setSystemReady(boolean systemReady) {
1519 mSystemReady = systemReady;
1520 }
1521
1522 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001523 void setHandler(WorkerHandler handler) {
Chris Wren93bb8b82016-03-29 14:35:05 -04001524 mHandler = handler;
1525 }
1526
Chris Wrend4054312016-06-24 17:07:40 -04001527 @VisibleForTesting
Julia Reynolds0c299d42016-11-15 14:37:04 -05001528 void setFallbackVibrationPattern(long[] vibrationPattern) {
1529 mFallbackVibrationPattern = vibrationPattern;
Chris Wrend4054312016-06-24 17:07:40 -04001530 }
1531
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001532 @VisibleForTesting
1533 void setPackageManager(IPackageManager packageManager) {
1534 mPackageManager = packageManager;
1535 }
1536
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001537 @VisibleForTesting
1538 void setRankingHelper(RankingHelper rankingHelper) {
1539 mRankingHelper = rankingHelper;
1540 }
1541
1542 @VisibleForTesting
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001543 void setPreferencesHelper(PreferencesHelper prefHelper) { mPreferencesHelper = prefHelper; }
1544
1545 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001546 void setRankingHandler(RankingHandler rankingHandler) {
1547 mRankingHandler = rankingHandler;
1548 }
1549
1550 @VisibleForTesting
Julia Reynolds4214da92019-04-10 15:04:06 -04001551 void setZenHelper(ZenModeHelper zenHelper) {
1552 mZenModeHelper = zenHelper;
1553 }
1554
1555 @VisibleForTesting
Adora Zhang963328f2018-11-15 18:17:19 -08001556 void setIsAutomotive(boolean isAutomotive) {
1557 mIsAutomotive = isAutomotive;
1558 }
1559
1560 @VisibleForTesting
Qiao (Adora) Zhang47b553c2019-04-15 20:42:57 +00001561 void setNotificationEffectsEnabledForAutomotive(boolean isEnabled) {
1562 mNotificationEffectsEnabledForAutomotive = isEnabled;
1563 }
1564
1565 @VisibleForTesting
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001566 void setIsTelevision(boolean isTelevision) {
1567 mIsTelevision = isTelevision;
1568 }
1569
Julia Reynolds76c096d2017-06-19 08:16:04 -04001570 @VisibleForTesting
1571 void setUsageStats(NotificationUsageStats us) {
1572 mUsageStats = us;
1573 }
1574
Julia Reynolds94187562017-10-10 13:58:49 -04001575 @VisibleForTesting
1576 void setAccessibilityManager(AccessibilityManager am) {
1577 mAccessibilityManager = am;
1578 }
1579
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001580 // TODO: All tests should use this init instead of the one-off setters above.
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001581 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001582 void init(Looper looper, IPackageManager packageManager,
1583 PackageManager packageManagerClient,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001584 LightsManager lightsManager, NotificationListeners notificationListeners,
Julia Reynoldsb852e562017-06-06 16:14:18 -04001585 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001586 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
Julia Reynolds68263d12017-06-21 14:21:19 -04001587 NotificationUsageStats usageStats, AtomicFile policyFile,
Julia Reynolds7217dc92018-03-07 12:12:09 -05001588 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001589 UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
Julia Reynolds0c245002019-03-27 16:10:11 -04001590 IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps,
1591 UserManager userManager) {
Chris Wren54bbef42014-07-09 18:37:56 -04001592 Resources resources = getContext().getResources();
Chris Wren763a9bb2016-05-31 17:14:12 -04001593 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1594 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1595 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1596
Julia Reynolds94187562017-10-10 13:58:49 -04001597 mAccessibilityManager =
1598 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001599 mAm = am;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001600 mUgm = ugm;
1601 mUgmInternal = ugmInternal;
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001602 mPackageManager = packageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001603 mPackageManagerClient = packageManagerClient;
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04001604 mAppOps = appOps;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001605 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Julia Reynolds7217dc92018-03-07 12:12:09 -05001606 mAppUsageStats = appUsageStats;
Julia Reynolds2a128742016-11-28 14:29:25 -05001607 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001608 mCompanionManager = companionManager;
Julia Reynolds68263d12017-06-21 14:21:19 -04001609 mActivityManager = activityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -08001610 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1611 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
Jason Parks50322ff2018-03-27 10:23:33 -05001612 mDpm = dpm;
Julia Reynolds0c245002019-03-27 16:10:11 -04001613 mUm = userManager;
Jason Parks50322ff2018-03-27 10:23:33 -05001614
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001615 mHandler = new WorkerHandler(looper);
Chris Wrenf9536642014-04-17 10:01:54 -04001616 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -04001617 String[] extractorNames;
1618 try {
1619 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1620 } catch (Resources.NotFoundException e) {
1621 extractorNames = new String[0];
1622 }
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001623 mUsageStats = usageStats;
Kenny Guy23991102018-04-05 21:18:38 +01001624 mMetricsLogger = new MetricsLogger();
Chris Wren51017d02015-12-15 15:34:46 -05001625 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Julia Reynoldsb852e562017-06-06 16:14:18 -04001626 mConditionProviders = conditionProviders;
John Spurlockb2278d62015-04-07 12:47:12 -04001627 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -04001628 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -04001629 @Override
1630 public void onConfigChanged() {
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001631 handleSavePolicyFile();
John Spurlock056c5192014-04-20 21:52:01 -04001632 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001633
1634 @Override
1635 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001636 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -05001637 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -05001638 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1639 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -05001640 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001641 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02001642 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001643 }
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001644 mRankingHandler.requestSort();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001645 }
John Spurlock1fc476d2015-04-14 16:05:20 -04001646
1647 @Override
1648 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001649 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001650 mRankingHandler.requestSort();
John Spurlock80774932015-05-07 17:38:50 -04001651 }
John Spurlock056c5192014-04-20 21:52:01 -04001652 });
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001653 mPreferencesHelper = new PreferencesHelper(getContext(),
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001654 mPackageManagerClient,
1655 mRankingHandler,
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001656 mZenModeHelper);
1657 mRankingHelper = new RankingHelper(getContext(),
1658 mRankingHandler,
1659 mPreferencesHelper,
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001660 mZenModeHelper,
1661 mUsageStats,
1662 extractorNames);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001663 mSnoozeHelper = snoozeHelper;
Julia Reynolds8aebf352017-06-26 11:35:33 -04001664 mGroupHelper = groupHelper;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04001665
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001666 // This is a ManagedServices object that keeps track of the listeners.
1667 mListeners = notificationListeners;
Chris Wren0efdb882016-03-01 17:17:47 -05001668
Julia Reynolds77b2cc92016-11-08 14:41:09 -05001669 // This is a MangedServices object that keeps track of the assistant.
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001670 mAssistants = notificationAssistants;
Julia Reynoldsb852e562017-06-06 16:14:18 -04001671
Kristian Monsen30f59b22018-04-09 10:27:16 +02001672 // Needs to be set before loadPolicyFile
1673 mAllowedManagedServicePackages = this::canUseManagedServices;
1674
Julia Reynoldsb852e562017-06-06 16:14:18 -04001675 mPolicyFile = policyFile;
1676 loadPolicyFile();
Chris Wren0efdb882016-03-01 17:17:47 -05001677
Adam Lesinski182f73f2013-12-05 16:48:06 -08001678 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -08001679 if (mStatusBar != null) {
1680 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1681 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001683 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1684 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001685
Daniel Sandleredbb3802012-11-13 20:49:47 -08001686 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001687 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001688 VIBRATE_PATTERN_MAXLEN,
1689 DEFAULT_VIBRATE_PATTERN);
Beverly5d463b62017-07-26 14:13:40 -04001690 mInCallNotificationUri = Uri.parse("file://" +
1691 resources.getString(R.string.config_inCallNotificationSound));
1692 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1693 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1694 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
Beverly5d463b62017-07-26 14:13:40 -04001695 .build();
1696 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1697
Chris Wren5116a822014-06-04 15:59:50 -04001698 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
Julia Reynolds28149f62018-07-03 10:43:35 -04001699 mHasLight =
1700 resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
Chris Wren5116a822014-06-04 15:59:50 -04001701
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001702 // Don't start allowing notifications until the setup wizard has run once.
1703 // After that, including subsequent boots, init with notifications turned on.
1704 // This works on the first boot because the setup wizard will toggle this
1705 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001706 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001707 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001708 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001709 }
John Spurlockb2278d62015-04-07 12:47:12 -04001710 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001711 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001712
John Spurlockb408e8e2014-04-23 21:12:45 -04001713 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001714 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001715
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001716 mSettingsObserver = new SettingsObserver(mHandler);
1717
1718 mArchive = new Archive(resources.getInteger(
1719 R.integer.config_notificationServiceArchiveSize));
1720
1721 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1722 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
Adora Zhang963328f2018-11-15 18:17:19 -08001723
1724 mIsAutomotive =
1725 mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0);
Qiao (Adora) Zhang47b553c2019-04-15 20:42:57 +00001726 mNotificationEffectsEnabledForAutomotive =
1727 resources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive);
Julia Reynolds413ba842019-01-11 10:38:08 -05001728
1729 mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray(
1730 com.android.internal.R.array.config_nonBlockableNotificationPackages));
Julia Reynoldse99db5a2019-04-16 12:50:04 -04001731
1732 mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray(
1733 com.android.internal.R.array.config_priorityOnlyDndExemptPackages));
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001734 }
1735
1736 @Override
1737 public void onStart() {
1738 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1739 @Override
1740 public void repost(int userId, NotificationRecord r) {
1741 try {
1742 if (DBG) {
1743 Slog.d(TAG, "Reposting " + r.getKey());
1744 }
1745 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1746 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1747 r.sbn.getNotification(), userId);
1748 } catch (Exception e) {
1749 Slog.e(TAG, "Cannot un-snooze notification", e);
1750 }
1751 }
1752 }, mUserProfiles);
1753
1754 final File systemDir = new File(Environment.getDataDirectory(), "system");
1755
1756 init(Looper.myLooper(),
1757 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1758 getLocalService(LightsManager.class),
1759 new NotificationListeners(AppGlobals.getPackageManager()),
Julia Reynolds7380d872018-01-12 10:28:26 -05001760 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
1761 AppGlobals.getPackageManager()),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001762 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1763 null, snoozeHelper, new NotificationUsageStats(getContext()),
Julia Reynolds0c245002019-03-27 16:10:11 -04001764 new AtomicFile(new File(
1765 systemDir, "notification_policy.xml"), "notification-policy"),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001766 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
Julia Reynolds7217dc92018-03-07 12:12:09 -05001767 getGroupHelper(), ActivityManager.getService(),
Jason Parks50322ff2018-03-27 10:23:33 -05001768 LocalServices.getService(UsageStatsManagerInternal.class),
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001769 LocalServices.getService(DevicePolicyManagerInternal.class),
1770 UriGrantsManager.getService(),
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04001771 LocalServices.getService(UriGrantsManagerInternal.class),
Julia Reynolds0c245002019-03-27 16:10:11 -04001772 (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE),
1773 getContext().getSystemService(UserManager.class));
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001774
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001775 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001776 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001777 filter.addAction(Intent.ACTION_SCREEN_ON);
1778 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001779 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001780 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001781 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001782 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001783 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001784 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001785 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001786 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001787 getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
Kenny Guy70058402014-10-28 20:45:06 +00001788
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001789 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001790 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001791 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001792 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001793 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1794 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1795 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001796 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1797 null);
1798
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001799 IntentFilter suspendedPkgFilter = new IntentFilter();
1800 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
Beverly5a20a5e2018-03-06 15:02:44 -05001801 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
Julia Reynolds0e5a3432019-01-17 09:40:46 -05001802 suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001803 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1804 suspendedPkgFilter, null, null);
1805
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001806 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001807 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1808 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001809
Julia Reynolds2a128742016-11-28 14:29:25 -05001810 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1811 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1812 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1813
Julia Reynoldsb852e562017-06-06 16:14:18 -04001814 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1815 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1816
Beverlyd4f96492017-08-02 13:36:11 -04001817 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1818 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1819
Vishnu Naire3e4d252018-03-01 11:26:57 -08001820 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
1821 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001822 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001823 }
1824
Tony Mak9a3c1f12019-03-04 16:04:42 +00001825 private void registerDeviceConfigChange() {
Matt Pape15769e22019-04-19 12:31:24 -07001826 DeviceConfig.addOnPropertiesChangedListener(
Tony Mak9a3c1f12019-03-04 16:04:42 +00001827 DeviceConfig.NAMESPACE_SYSTEMUI,
1828 getContext().getMainExecutor(),
Matt Pape15769e22019-04-19 12:31:24 -07001829 (properties) -> {
1830 if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) {
Tony Mak9a3c1f12019-03-04 16:04:42 +00001831 return;
1832 }
Matt Pape15769e22019-04-19 12:31:24 -07001833 if (properties.getKeyset()
1834 .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) {
Tony Mak9a3c1f12019-03-04 16:04:42 +00001835 mAssistants.resetDefaultAssistantsIfNecessary();
1836 }
1837 });
1838 }
1839
1840
Julia Reynolds8aebf352017-06-26 11:35:33 -04001841 private GroupHelper getGroupHelper() {
Adora Zhang48dd614a82018-06-25 19:18:41 -07001842 mAutoGroupAtCount =
1843 getContext().getResources().getInteger(R.integer.config_autoGroupAtCount);
1844 return new GroupHelper(mAutoGroupAtCount, new GroupHelper.Callback() {
Julia Reynolds8aebf352017-06-26 11:35:33 -04001845 @Override
1846 public void addAutoGroup(String key) {
1847 synchronized (mNotificationLock) {
1848 addAutogroupKeyLocked(key);
1849 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001850 }
1851
1852 @Override
1853 public void removeAutoGroup(String key) {
1854 synchronized (mNotificationLock) {
1855 removeAutogroupKeyLocked(key);
1856 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001857 }
1858
1859 @Override
1860 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1861 createAutoGroupSummary(userId, pkg, triggeringKey);
1862 }
1863
1864 @Override
1865 public void removeAutoGroupSummary(int userId, String pkg) {
1866 synchronized (mNotificationLock) {
1867 clearAutogroupSummaryLocked(userId, pkg);
1868 }
1869 }
1870 });
1871 }
1872
John Spurlocke7a835b2015-05-13 10:47:05 -04001873 private void sendRegisteredOnlyBroadcast(String action) {
Julia Reynolds4c456dd2019-01-07 12:22:00 -05001874 Intent intent = new Intent(action);
1875 getContext().sendBroadcastAsUser(intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
1876 UserHandle.ALL, null);
1877 // explicitly send the broadcast to all DND packages, even if they aren't currently running
1878 intent.setFlags(0);
1879 final Set<String> dndApprovedPackages = mConditionProviders.getAllowedPackages();
1880 for (String pkg : dndApprovedPackages) {
1881 intent.setPackage(pkg);
1882 getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
1883 }
John Spurlocke7a835b2015-05-13 10:47:05 -04001884 }
1885
Adam Lesinski182f73f2013-12-05 16:48:06 -08001886 @Override
1887 public void onBootPhase(int phase) {
1888 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1889 // no beeping until we're basically done booting
1890 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001891
Adam Lesinski182f73f2013-12-05 16:48:06 -08001892 // Grab our optional AudioService
1893 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001894 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001895 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001896 mZenModeHelper.onSystemReady();
Julia Reynolds0c245002019-03-27 16:10:11 -04001897 mRoleObserver = new RoleObserver(getContext().getSystemService(RoleManager.class),
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04001898 mPackageManager, getContext().getMainExecutor());
Julia Reynolds0c245002019-03-27 16:10:11 -04001899 mRoleObserver.init();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001900 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1901 // This observer will force an update when observe is called, causing us to
1902 // bind to listener services.
1903 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001904 mListeners.onBootPhaseAppsCanStart();
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001905 mAssistants.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001906 mConditionProviders.onBootPhaseAppsCanStart();
Tony Mak9a3c1f12019-03-04 16:04:42 +00001907 registerDeviceConfigChange();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 }
1909 }
1910
Julia Reynolds88860ce2017-06-01 16:55:49 -04001911 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04001912 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001913 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001914 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001915 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001916 mListenerHints = hints;
1917 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001918 }
1919
Julia Reynolds88860ce2017-06-01 16:55:49 -04001920 @GuardedBy("mNotificationLock")
John Spurlockb4782522014-08-22 14:54:46 -04001921 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001922 final long updatedSuppressedEffects = calculateSuppressedEffects();
1923 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1924 final List<ComponentName> suppressors = getSuppressors();
1925 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1926 mEffectsSuppressors = suppressors;
1927 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001928 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001929 }
1930
Amith Yamasani396a10c2018-01-19 10:58:07 -08001931 private void exitIdle() {
1932 try {
1933 if (mDeviceIdleController != null) {
1934 mDeviceIdleController.exitIdle("notification interaction");
1935 }
1936 } catch (RemoteException e) {
1937 }
1938 }
1939
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001940 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1941 boolean fromListener) {
Julia Reynolds924eed12017-01-19 09:52:07 -05001942 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1943 // cancel
1944 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001945 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
Julia Reynolds924eed12017-01-19 09:52:07 -05001946 null);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001947 if (isUidSystemOrPhone(uid)) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001948 IntArray profileIds = mUserProfiles.getCurrentProfileIds();
1949 int N = profileIds.size();
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001950 for (int i = 0; i < N; i++) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001951 int profileId = profileIds.get(i);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001952 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1953 profileId, REASON_CHANNEL_BANNED,
1954 null);
1955 }
1956 }
Julia Reynolds924eed12017-01-19 09:52:07 -05001957 }
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001958 final NotificationChannel preUpdate =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001959 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001960
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001961 mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001962 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
Julia Reynolds924eed12017-01-19 09:52:07 -05001963
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001964 if (!fromListener) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001965 final NotificationChannel modifiedChannel =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001966 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001967 mListeners.notifyNotificationChannelChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001968 pkg, UserHandle.getUserHandleForUid(uid),
1969 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001970 }
1971
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001972 handleSavePolicyFile();
Julia Reynolds924eed12017-01-19 09:52:07 -05001973 }
1974
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001975 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1976 NotificationChannel update) {
1977 try {
1978 if ((preUpdate.getImportance() == IMPORTANCE_NONE
1979 && update.getImportance() != IMPORTANCE_NONE)
1980 || (preUpdate.getImportance() != IMPORTANCE_NONE
1981 && update.getImportance() == IMPORTANCE_NONE)) {
1982 getContext().sendBroadcastAsUser(
1983 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001984 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001985 update.getId())
1986 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1987 update.getImportance() == IMPORTANCE_NONE)
1988 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1989 .setPackage(pkg),
1990 UserHandle.of(UserHandle.getUserId(uid)), null);
1991 }
1992 } catch (SecurityException e) {
1993 Slog.w(TAG, "Can't notify app about channel change", e);
1994 }
1995 }
1996
Julia Reynolds005c8b92017-08-24 10:35:53 -04001997 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
1998 boolean fromApp, boolean fromListener) {
1999 Preconditions.checkNotNull(group);
2000 Preconditions.checkNotNull(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002001
2002 final NotificationChannelGroup preUpdate =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002003 mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
2004 mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group,
Julia Reynolds005c8b92017-08-24 10:35:53 -04002005 fromApp);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002006 if (!fromApp) {
2007 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
2008 }
Julia Reynolds005c8b92017-08-24 10:35:53 -04002009 if (!fromListener) {
2010 mListeners.notifyNotificationChannelGroupChanged(pkg,
2011 UserHandle.of(UserHandle.getCallingUserId()), group,
2012 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
2013 }
2014 }
2015
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002016 private void maybeNotifyChannelGroupOwner(String pkg, int uid,
2017 NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
2018 try {
2019 if (preUpdate.isBlocked() != update.isBlocked()) {
2020 getContext().sendBroadcastAsUser(
2021 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05002022 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002023 update.getId())
2024 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
2025 update.isBlocked())
2026 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2027 .setPackage(pkg),
2028 UserHandle.of(UserHandle.getUserId(uid)), null);
2029 }
2030 } catch (SecurityException e) {
2031 Slog.w(TAG, "Can't notify app about group change", e);
2032 }
2033 }
2034
Bryce Lee7219ada2016-04-08 10:54:23 -07002035 private ArrayList<ComponentName> getSuppressors() {
2036 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
2037 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04002038 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07002039
Julia Reynolds4703bac2018-09-12 10:39:30 -04002040 for (ComponentName info : serviceInfoList) {
2041 names.add(info);
Bryce Lee7219ada2016-04-08 10:54:23 -07002042 }
2043 }
2044
2045 return names;
2046 }
2047
2048 private boolean removeDisabledHints(ManagedServiceInfo info) {
2049 return removeDisabledHints(info, 0);
2050 }
2051
2052 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
2053 boolean removed = false;
2054
2055 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
2056 final int hint = mListenersDisablingEffects.keyAt(i);
Julia Reynolds4703bac2018-09-12 10:39:30 -04002057 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07002058
2059 if (hints == 0 || (hint & hints) == hint) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04002060 removed |= listeners.remove(info.component);
Bryce Lee7219ada2016-04-08 10:54:23 -07002061 }
2062 }
2063
2064 return removed;
2065 }
2066
2067 private void addDisabledHints(ManagedServiceInfo info, int hints) {
2068 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2069 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
2070 }
2071
2072 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
2073 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
2074 }
2075
2076 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
2077 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
2078 }
2079 }
2080
2081 private void addDisabledHint(ManagedServiceInfo info, int hint) {
2082 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04002083 mListenersDisablingEffects.put(hint, new ArraySet<>());
Bryce Lee7219ada2016-04-08 10:54:23 -07002084 }
2085
Julia Reynolds4703bac2018-09-12 10:39:30 -04002086 ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint);
2087 hintListeners.add(info.component);
Bryce Lee7219ada2016-04-08 10:54:23 -07002088 }
2089
2090 private int calculateHints() {
2091 int hints = 0;
2092 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
2093 int hint = mListenersDisablingEffects.keyAt(i);
Julia Reynolds4703bac2018-09-12 10:39:30 -04002094 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07002095
2096 if (!serviceInfoList.isEmpty()) {
2097 hints |= hint;
2098 }
2099 }
2100
2101 return hints;
2102 }
2103
2104 private long calculateSuppressedEffects() {
2105 int hints = calculateHints();
2106 long suppressedEffects = 0;
2107
2108 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2109 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
2110 }
2111
2112 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
2113 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
2114 }
2115
2116 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
2117 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
2118 }
2119
2120 return suppressedEffects;
2121 }
2122
Julia Reynolds88860ce2017-06-01 16:55:49 -04002123 @GuardedBy("mNotificationLock")
Christoph Studer85a384b2014-08-27 20:16:15 +02002124 private void updateInterruptionFilterLocked() {
2125 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
2126 if (interruptionFilter == mInterruptionFilter) return;
2127 mInterruptionFilter = interruptionFilter;
2128 scheduleInterruptionFilterChanged(interruptionFilter);
2129 }
2130
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05002131 @VisibleForTesting
2132 INotificationManager getBinderService() {
2133 return INotificationManager.Stub.asInterface(mService);
2134 }
2135
Amith Yamasani7ec89412018-02-07 08:48:49 -08002136 /**
2137 * Report to usage stats that the notification was seen.
2138 * @param r notification record
2139 */
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002140 @GuardedBy("mNotificationLock")
Amith Yamasani803eab692017-11-09 17:47:04 -08002141 protected void reportSeen(NotificationRecord r) {
Julia Reynolds95334132018-12-19 11:15:35 -05002142 if (!r.isProxied()) {
2143 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2144 getRealUserId(r.sbn.getUserId()),
2145 UsageEvents.Event.NOTIFICATION_SEEN);
2146 }
Amith Yamasani803eab692017-11-09 17:47:04 -08002147 }
2148
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05002149 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
2150 int targetSdkVersion) {
2151 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
2152 return incomingPolicy.suppressedVisualEffects;
2153 }
2154 final int[] effectsIntroducedInP = {
2155 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
2156 SUPPRESSED_EFFECT_LIGHTS,
2157 SUPPRESSED_EFFECT_PEEK,
2158 SUPPRESSED_EFFECT_STATUS_BAR,
2159 SUPPRESSED_EFFECT_BADGE,
2160 SUPPRESSED_EFFECT_AMBIENT,
2161 SUPPRESSED_EFFECT_NOTIFICATION_LIST
2162 };
2163
2164 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06002165 if (targetSdkVersion < Build.VERSION_CODES.P) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05002166 // unset higher order bits introduced in P, maintain the user's higher order bits
2167 for (int i = 0; i < effectsIntroducedInP.length ; i++) {
2168 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
2169 newSuppressedVisualEffects |=
2170 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
2171 }
2172 // set higher order bits according to lower order bits
2173 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
2174 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
2175 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05002176 }
2177 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
2178 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
2179 }
2180 } else {
2181 boolean hasNewEffects = (newSuppressedVisualEffects
2182 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
2183 // if any of the new effects introduced in P are set
2184 if (hasNewEffects) {
2185 // clear out the deprecated effects
2186 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
2187 | SUPPRESSED_EFFECT_SCREEN_OFF);
2188
2189 // set the deprecated effects according to the new more specific effects
2190 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
2191 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
2192 }
2193 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
2194 && (newSuppressedVisualEffects
2195 & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
2196 && (newSuppressedVisualEffects
2197 & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
2198 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
2199 }
2200 } else {
2201 // set higher order bits according to lower order bits
2202 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
2203 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
2204 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
2205 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
2206 }
2207 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
2208 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
2209 }
2210 }
2211 }
2212
2213 return newSuppressedVisualEffects;
2214 }
2215
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002216 @GuardedBy("mNotificationLock")
2217 protected void maybeRecordInterruptionLocked(NotificationRecord r) {
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04002218 if (r.isInterruptive() && !r.hasRecordedInterruption()) {
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002219 mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
2220 r.getChannel().getId(),
2221 getRealUserId(r.sbn.getUserId()));
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04002222 r.setRecordedInterruption(true);
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002223 }
2224 }
2225
Amith Yamasani7ec89412018-02-07 08:48:49 -08002226 /**
Esteban Talavera917a71d2018-11-13 07:55:08 +00002227 * Report to usage stats that the user interacted with the notification.
Amith Yamasani7ec89412018-02-07 08:48:49 -08002228 * @param r notification record
2229 */
2230 protected void reportUserInteraction(NotificationRecord r) {
Amith Yamasani7ec89412018-02-07 08:48:49 -08002231 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002232 getRealUserId(r.sbn.getUserId()),
Amith Yamasani7ec89412018-02-07 08:48:49 -08002233 UsageEvents.Event.USER_INTERACTION);
2234 }
2235
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002236 private int getRealUserId(int userId) {
2237 return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
2238 }
2239
Geoffrey Pitsch415e4542017-04-10 13:12:58 -04002240 @VisibleForTesting
2241 NotificationManagerInternal getInternalService() {
2242 return mInternalService;
2243 }
2244
Beverly58b24532018-10-02 09:08:23 -04002245 @VisibleForTesting
2246 final IBinder mService = new INotificationManager.Stub() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002247 // Toasts
2248 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 @Override
Jeff Chang48ecef42018-08-09 16:31:59 +08002251 public void enqueueToast(String pkg, ITransientNotification callback, int duration,
2252 int displayId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002253 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002254 if (DBG) {
2255 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
Jeff Chang48ecef42018-08-09 16:31:59 +08002256 + " duration=" + duration + " displayId=" + displayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002257 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002258
2259 if (pkg == null || callback == null) {
Beverly58b24532018-10-02 09:08:23 -04002260 Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " callback=" + callback);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002261 return ;
2262 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002263
Beverly58b24532018-10-02 09:08:23 -04002264 final int callingUid = Binder.getCallingUid();
2265 final boolean isSystemToast = isCallerSystemOrPhone()
2266 || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg);
2267 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
2268 final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg,
2269 callingUid);
2270
2271 long callingIdentity = Binder.clearCallingIdentity();
2272 try {
2273 final boolean appIsForeground = mActivityManager.getUidImportance(callingUid)
2274 == IMPORTANCE_FOREGROUND;
2275 if (ENABLE_BLOCKED_TOASTS && !isSystemToast && ((notificationsDisabledForPackage
2276 && !appIsForeground) || isPackageSuspended)) {
2277 Slog.e(TAG, "Suppressing toast from package " + pkg
2278 + (isPackageSuspended ? " due to package suspended."
2279 : " by user request."));
2280 return;
2281 }
2282 } finally {
2283 Binder.restoreCallingIdentity(callingIdentity);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002284 }
2285
2286 synchronized (mToastQueue) {
2287 int callingPid = Binder.getCallingPid();
2288 long callingId = Binder.clearCallingIdentity();
2289 try {
2290 ToastRecord record;
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002291 int index = indexOfToastLocked(pkg, callback);
2292 // If it's already in the queue, we update it in place, we don't
2293 // move it to the end of the queue.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002294 if (index >= 0) {
2295 record = mToastQueue.get(index);
2296 record.update(duration);
2297 } else {
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002298 // Limit the number of toasts that any given package except the android
2299 // package can enqueue. Prevents DOS attacks and deals with leaks.
2300 if (!isSystemToast) {
2301 int count = 0;
2302 final int N = mToastQueue.size();
2303 for (int i=0; i<N; i++) {
2304 final ToastRecord r = mToastQueue.get(i);
2305 if (r.pkg.equals(pkg)) {
2306 count++;
2307 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2308 Slog.e(TAG, "Package has already posted " + count
2309 + " toasts. Not showing more. Package=" + pkg);
2310 return;
2311 }
2312 }
2313 }
2314 }
2315
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002316 Binder token = new Binder();
Jeff Chang48ecef42018-08-09 16:31:59 +08002317 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, displayId);
2318 record = new ToastRecord(callingPid, pkg, callback, duration, token,
2319 displayId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002320 mToastQueue.add(record);
2321 index = mToastQueue.size() - 1;
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002322 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002323 }
2324 // If it's at index 0, it's the current toast. It doesn't matter if it's
2325 // new or just been updated. Call back and tell it to show itself.
2326 // If the callback fails, this will remove it from the list, so don't
2327 // assume that it's valid after this.
2328 if (index == 0) {
2329 showNextToastLocked();
2330 }
2331 } finally {
2332 Binder.restoreCallingIdentity(callingId);
2333 }
2334 }
2335 }
2336
2337 @Override
2338 public void cancelToast(String pkg, ITransientNotification callback) {
2339 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
2340
2341 if (pkg == null || callback == null) {
2342 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
2343 return ;
2344 }
2345
2346 synchronized (mToastQueue) {
2347 long callingId = Binder.clearCallingIdentity();
2348 try {
2349 int index = indexOfToastLocked(pkg, callback);
2350 if (index >= 0) {
2351 cancelToastLocked(index);
2352 } else {
2353 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
2354 + " callback=" + callback);
2355 }
2356 } finally {
2357 Binder.restoreCallingIdentity(callingId);
2358 }
2359 }
2360 }
2361
2362 @Override
Robert Carr997427342018-02-28 18:06:10 -08002363 public void finishToken(String pkg, ITransientNotification callback) {
2364 synchronized (mToastQueue) {
2365 long callingId = Binder.clearCallingIdentity();
2366 try {
2367 int index = indexOfToastLocked(pkg, callback);
2368 if (index >= 0) {
2369 ToastRecord record = mToastQueue.get(index);
Jeff Chang48ecef42018-08-09 16:31:59 +08002370 finishTokenLocked(record.token, record.displayId);
Robert Carr997427342018-02-28 18:06:10 -08002371 } else {
2372 Slog.w(TAG, "Toast already killed. pkg=" + pkg
2373 + " callback=" + callback);
2374 }
2375 } finally {
2376 Binder.restoreCallingIdentity(callingId);
2377 }
2378 }
2379 }
2380
2381 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002382 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002383 Notification notification, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002384 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002385 Binder.getCallingPid(), tag, id, notification, userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002386 }
2387
2388 @Override
2389 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002390 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002391 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2392 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002393 // Don't allow client applications to cancel foreground service notis or autobundled
2394 // summaries.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002395 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
Mady Mellor49b1bf12019-03-29 12:00:02 -07002396 (FLAG_FOREGROUND_SERVICE | FLAG_AUTOGROUP_SUMMARY);
John Spurlocke6a7d932014-03-13 12:29:00 -04002397 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002398 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002399 }
2400
2401 @Override
2402 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002403 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002404
2405 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2406 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
2407
2408 // Calling from user space, don't allow the canceling of actively
2409 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04002410 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
Julia Reynoldse5c60452018-04-30 14:41:36 -04002411 pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05002412 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002413 }
2414
2415 @Override
2416 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
Rohan Shahca0447e2018-03-30 15:18:27 -07002417 enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002418
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002419 mPreferencesHelper.setEnabled(pkg, uid, enabled);
Howard Ro8b56f752018-08-07 15:44:25 -07002420 mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
2421 .setType(MetricsEvent.TYPE_ACTION)
2422 .setPackageName(pkg)
2423 .setSubtype(enabled ? 1 : 0));
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002424 // Now, cancel any outstanding notifications that are part of a just-disabled app
Julia Reynolds4da79702017-06-01 11:06:10 -04002425 if (!enabled) {
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002426 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
2427 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
2428 }
Julia Reynoldsfc9767b2018-01-22 17:45:16 -05002429
2430 try {
2431 getContext().sendBroadcastAsUser(
2432 new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
2433 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
2434 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2435 .setPackage(pkg),
2436 UserHandle.of(UserHandle.getUserId(uid)), null);
2437 } catch (SecurityException e) {
2438 Slog.w(TAG, "Can't notify app about app block change", e);
2439 }
2440
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002441 handleSavePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002442 }
2443
2444 /**
Rohan Shah590e1b22018-04-10 23:48:47 -04002445 * Updates the enabled state for notifications for the given package (and uid).
2446 * Additionally, this method marks the app importance as locked by the user, which means
2447 * that notifications from the app will <b>not</b> be considered for showing a
2448 * blocking helper.
2449 *
2450 * @param pkg package that owns the notifications to update
2451 * @param uid uid of the app providing notifications
2452 * @param enabled whether notifications should be enabled for the app
2453 *
2454 * @see #setNotificationsEnabledForPackage(String, int, boolean)
2455 */
2456 @Override
2457 public void setNotificationsEnabledWithImportanceLockForPackage(
2458 String pkg, int uid, boolean enabled) {
2459 setNotificationsEnabledForPackage(pkg, uid, enabled);
2460
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002461 mPreferencesHelper.setAppImportanceLocked(pkg, uid);
Rohan Shah590e1b22018-04-10 23:48:47 -04002462 }
2463
2464 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002465 * Use this when you just want to know if notifications are OK for this package.
2466 */
2467 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002468 public boolean areNotificationsEnabled(String pkg) {
2469 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
2470 }
2471
2472 /**
2473 * Use this when you just want to know if notifications are OK for this package.
2474 */
2475 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002476 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Evan Laird47dc4542019-04-24 15:10:52 -04002477 enforceSystemOrSystemUIOrSamePackage(pkg,
2478 "Caller not system or systemui or same package");
Julia Reynolds657d1642019-03-27 12:15:57 -04002479 if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
2480 getContext().enforceCallingPermission(
2481 android.Manifest.permission.INTERACT_ACROSS_USERS,
2482 "canNotifyAsPackage for uid " + uid);
2483 }
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002484
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002485 return mPreferencesHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002486 }
2487
Chris Wren54bbef42014-07-09 18:37:56 -04002488 @Override
Mady Mellorc39b4ae2019-01-09 17:11:37 -08002489 public boolean areBubblesAllowed(String pkg) {
2490 return areBubblesAllowedForPackage(pkg, Binder.getCallingUid());
Julia Reynolds33ab8a02018-12-17 16:19:52 -05002491 }
2492
2493 @Override
Mady Mellorc39b4ae2019-01-09 17:11:37 -08002494 public boolean areBubblesAllowedForPackage(String pkg, int uid) {
2495 enforceSystemOrSystemUIOrSamePackage(pkg,
2496 "Caller not system or systemui or same package");
Julia Reynolds2f7592d2019-03-27 12:17:23 -04002497
2498 if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
2499 getContext().enforceCallingPermission(
2500 android.Manifest.permission.INTERACT_ACROSS_USERS,
2501 "canNotifyAsPackage for uid " + uid);
2502 }
2503
Mady Mellor9db685a2019-01-23 13:23:37 -08002504 return mPreferencesHelper.areBubblesAllowed(pkg, uid);
Julia Reynolds33ab8a02018-12-17 16:19:52 -05002505 }
2506
2507 @Override
Mady Mellorc39b4ae2019-01-09 17:11:37 -08002508 public void setBubblesAllowed(String pkg, int uid, boolean allowed) {
Mady Mellor9db685a2019-01-23 13:23:37 -08002509 enforceSystemOrSystemUI("Caller not system or systemui");
Mady Mellorc39b4ae2019-01-09 17:11:37 -08002510 mPreferencesHelper.setBubblesAllowed(pkg, uid, allowed);
Julia Reynolds33ab8a02018-12-17 16:19:52 -05002511 handleSavePolicyFile();
2512 }
2513
2514 @Override
Mady Mellor9db685a2019-01-23 13:23:37 -08002515 public boolean hasUserApprovedBubblesForPackage(String pkg, int uid) {
2516 enforceSystemOrSystemUI("Caller not system or systemui");
2517 int lockedFields = mPreferencesHelper.getAppLockedFields(pkg, uid);
2518 return (lockedFields & PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE) != 0;
2519 }
2520
2521 @Override
Julia Reynolds12ad7ca2019-01-28 09:29:16 -05002522 public boolean shouldHideSilentStatusIcons(String callingPkg) {
2523 checkCallerIsSameApp(callingPkg);
2524
2525 if (isCallerSystemOrPhone()
2526 || mListeners.isListenerPackage(callingPkg)) {
2527 return mPreferencesHelper.shouldHideSilentStatusIcons();
2528 } else {
2529 throw new SecurityException("Only available for notification listeners");
2530 }
2531 }
2532
2533 @Override
2534 public void setHideSilentStatusIcons(boolean hide) {
2535 checkCallerIsSystem();
2536
2537 mPreferencesHelper.setHideSilentStatusIcons(hide);
2538 handleSavePolicyFile();
2539
2540 mListeners.onStatusBarIconsBehaviorChanged(hide);
2541 }
2542
2543 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05002544 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002545 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002546 return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002547 }
2548
2549 @Override
Julia Reynolds924eed12017-01-19 09:52:07 -05002550 public boolean canShowBadge(String pkg, int uid) {
2551 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002552 return mPreferencesHelper.canShowBadge(pkg, uid);
Julia Reynolds924eed12017-01-19 09:52:07 -05002553 }
2554
2555 @Override
2556 public void setShowBadge(String pkg, int uid, boolean showBadge) {
2557 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002558 mPreferencesHelper.setShowBadge(pkg, uid, showBadge);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002559 handleSavePolicyFile();
Julia Reynolds924eed12017-01-19 09:52:07 -05002560 }
2561
2562 @Override
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002563 public void setNotificationDelegate(String callingPkg, String delegate) {
2564 checkCallerIsSameApp(callingPkg);
2565 final int callingUid = Binder.getCallingUid();
2566 UserHandle user = UserHandle.getUserHandleForUid(callingUid);
Julia Reynoldscbc45e72019-03-07 12:31:52 -05002567 if (delegate == null) {
2568 mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid());
2569 handleSavePolicyFile();
2570 } else {
2571 try {
2572 ApplicationInfo info =
2573 mPackageManager.getApplicationInfo(delegate,
2574 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
2575 user.getIdentifier());
2576 if (info != null) {
2577 mPreferencesHelper.setNotificationDelegate(
2578 callingPkg, callingUid, delegate, info.uid);
2579 handleSavePolicyFile();
2580 }
2581 } catch (RemoteException e) {
2582 e.rethrowFromSystemServer();
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002583 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002584 }
2585 }
2586
2587 @Override
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002588 public String getNotificationDelegate(String callingPkg) {
2589 // callable by Settings also
2590 checkCallerIsSystemOrSameApp(callingPkg);
2591 return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid());
2592 }
2593
2594 @Override
Julia Reynolds7a6d07a2019-03-18 11:31:56 -04002595 public boolean canNotifyAsPackage(String callingPkg, String targetPkg, int userId) {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002596 checkCallerIsSameApp(callingPkg);
2597 final int callingUid = Binder.getCallingUid();
2598 UserHandle user = UserHandle.getUserHandleForUid(callingUid);
Julia Reynolds7a6d07a2019-03-18 11:31:56 -04002599 if (user.getIdentifier() != userId) {
2600 getContext().enforceCallingPermission(
2601 android.Manifest.permission.INTERACT_ACROSS_USERS,
2602 "canNotifyAsPackage for user " + userId);
2603 }
Julia Reynoldsb4a9e9c2019-03-20 15:46:08 -04002604 if (callingPkg.equals(targetPkg)) {
2605 return true;
2606 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002607 try {
2608 ApplicationInfo info =
2609 mPackageManager.getApplicationInfo(targetPkg,
2610 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
Julia Reynolds7a6d07a2019-03-18 11:31:56 -04002611 userId);
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002612 if (info != null) {
2613 return mPreferencesHelper.isDelegateAllowed(
2614 targetPkg, info.uid, callingPkg, callingUid);
2615 }
2616 } catch (RemoteException e) {
2617 // :(
2618 }
2619 return false;
2620 }
2621
2622 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002623 public void updateNotificationChannelGroupForPackage(String pkg, int uid,
2624 NotificationChannelGroup group) throws RemoteException {
2625 enforceSystemOrSystemUI("Caller not system or systemui");
2626 createNotificationChannelGroup(pkg, uid, group, false, false);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002627 handleSavePolicyFile();
Julia Reynolds005c8b92017-08-24 10:35:53 -04002628 }
2629
2630 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002631 public void createNotificationChannelGroups(String pkg,
2632 ParceledListSlice channelGroupList) throws RemoteException {
2633 checkCallerIsSystemOrSameApp(pkg);
2634 List<NotificationChannelGroup> groups = channelGroupList.getList();
2635 final int groupSize = groups.size();
2636 for (int i = 0; i < groupSize; i++) {
2637 final NotificationChannelGroup group = groups.get(i);
Julia Reynolds005c8b92017-08-24 10:35:53 -04002638 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002639 }
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002640 handleSavePolicyFile();
Julia Reynolds59e152e2017-01-25 17:42:53 -05002641 }
2642
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002643 private void createNotificationChannelsImpl(String pkg, int uid,
2644 ParceledListSlice channelsList) {
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002645 List<NotificationChannel> channels = channelsList.getList();
2646 final int channelsSize = channels.size();
2647 for (int i = 0; i < channelsSize; i++) {
2648 final NotificationChannel channel = channels.get(i);
2649 Preconditions.checkNotNull(channel, "channel in list is null");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002650 mPreferencesHelper.createNotificationChannel(pkg, uid, channel,
Julia Reynolds1fe10942018-03-28 12:46:51 -04002651 true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed(
2652 pkg, UserHandle.getUserId(uid)));
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002653 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002654 UserHandle.getUserHandleForUid(uid),
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002655 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002656 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002657 }
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002658 handleSavePolicyFile();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002659 }
2660
2661 @Override
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002662 public void createNotificationChannels(String pkg,
2663 ParceledListSlice channelsList) throws RemoteException {
2664 checkCallerIsSystemOrSameApp(pkg);
2665 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
2666 }
2667
2668 @Override
2669 public void createNotificationChannelsForPackage(String pkg, int uid,
2670 ParceledListSlice channelsList) throws RemoteException {
2671 checkCallerIsSystem();
2672 createNotificationChannelsImpl(pkg, uid, channelsList);
2673 }
2674
2675 @Override
Julia Reynoldsb4a9e9c2019-03-20 15:46:08 -04002676 public NotificationChannel getNotificationChannel(String callingPkg, int userId,
2677 String targetPkg, String channelId) {
2678 if (canNotifyAsPackage(callingPkg, targetPkg, userId)
2679 || isCallingUidSystem()) {
2680 int targetUid = -1;
2681 try {
2682 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
2683 } catch (NameNotFoundException e) {
2684 /* ignore */
2685 }
2686 return mPreferencesHelper.getNotificationChannel(
2687 targetPkg, targetUid, channelId, false /* includeDeleted */);
2688 }
2689 throw new SecurityException("Pkg " + callingPkg
2690 + " cannot read channels for " + targetPkg + " in " + userId);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002691 }
2692
2693 @Override
2694 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002695 String channelId, boolean includeDeleted) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002696 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002697 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002698 }
2699
2700 @Override
2701 public void deleteNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002702 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002703 final int callingUid = Binder.getCallingUid();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002704 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
2705 throw new IllegalArgumentException("Cannot delete default channel");
2706 }
2707 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002708 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002709 mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002710 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002711 UserHandle.getUserHandleForUid(callingUid),
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002712 mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002713 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002714 handleSavePolicyFile();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002715 }
2716
2717 @Override
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002718 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
2719 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002720 return mPreferencesHelper.getNotificationChannelGroupWithChannels(
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002721 pkg, Binder.getCallingUid(), groupId, false);
2722 }
2723
2724 @Override
Julia Reynolds9bfba592017-03-15 14:03:55 -04002725 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
2726 String pkg) {
2727 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002728 return mPreferencesHelper.getNotificationChannelGroups(
Julia Reynolds13ed28b2018-09-21 15:20:13 -04002729 pkg, Binder.getCallingUid(), false, false, true);
Julia Reynolds9bfba592017-03-15 14:03:55 -04002730 }
2731
2732 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002733 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04002734 checkCallerIsSystemOrSameApp(pkg);
2735
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002736 final int callingUid = Binder.getCallingUid();
2737 NotificationChannelGroup groupToDelete =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002738 mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002739 if (groupToDelete != null) {
2740 List<NotificationChannel> deletedChannels =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002741 mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002742 for (int i = 0; i < deletedChannels.size(); i++) {
2743 final NotificationChannel deletedChannel = deletedChannels.get(i);
2744 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2745 true,
2746 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2747 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002748 mListeners.notifyNotificationChannelChanged(pkg,
2749 UserHandle.getUserHandleForUid(callingUid),
2750 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002751 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2752 }
2753 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002754 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2755 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002756 handleSavePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002757 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04002758 }
2759
2760 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002761 public void updateNotificationChannelForPackage(String pkg, int uid,
2762 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002763 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05002764 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002765 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002766 }
2767
2768 @Override
2769 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002770 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002771 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002772 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002773 }
2774
2775 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002776 public int getNumNotificationChannelsForPackage(String pkg, int uid,
2777 boolean includeDeleted) {
2778 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002779 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted)
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002780 .getList().size();
2781 }
2782
2783 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04002784 public boolean onlyHasDefaultChannel(String pkg, int uid) {
2785 enforceSystemOrSystemUI("onlyHasDefaultChannel");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002786 return mPreferencesHelper.onlyHasDefaultChannel(pkg, uid);
Julia Reynolds17717f52017-05-09 11:46:06 -04002787 }
2788
2789 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04002790 public int getDeletedChannelCount(String pkg, int uid) {
2791 enforceSystemOrSystemUI("getDeletedChannelCount");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002792 return mPreferencesHelper.getDeletedChannelCount(pkg, uid);
Julia Reynolds41103f42017-03-15 11:36:35 -04002793 }
2794
2795 @Override
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002796 public int getBlockedChannelCount(String pkg, int uid) {
2797 enforceSystemOrSystemUI("getBlockedChannelCount");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002798 return mPreferencesHelper.getBlockedChannelCount(pkg, uid);
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002799 }
2800
2801 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002802 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2803 String pkg, int uid, boolean includeDeleted) {
Evan Laird47dc4542019-04-24 15:10:52 -04002804 enforceSystemOrSystemUI("getNotificationChannelGroupsForPackage");
Julia Reynolds13ed28b2018-09-21 15:20:13 -04002805 return mPreferencesHelper.getNotificationChannelGroups(
2806 pkg, uid, includeDeleted, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002807 }
2808
2809 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002810 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2811 String pkg, int uid, String groupId, boolean includeDeleted) {
2812 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002813 return mPreferencesHelper.getNotificationChannelGroupWithChannels(
Julia Reynolds005c8b92017-08-24 10:35:53 -04002814 pkg, uid, groupId, includeDeleted);
2815 }
2816
2817 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002818 public NotificationChannelGroup getNotificationChannelGroupForPackage(
2819 String groupId, String pkg, int uid) {
2820 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002821 return mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, uid);
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002822 }
2823
2824 @Override
Julia Reynoldsb4a9e9c2019-03-20 15:46:08 -04002825 public ParceledListSlice<NotificationChannel> getNotificationChannels(
2826 String callingPkg, String targetPkg, int userId) {
2827 if (canNotifyAsPackage(callingPkg, targetPkg, userId)
2828 || isCallingUidSystem()) {
2829 int targetUid = -1;
2830 try {
2831 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
2832 } catch (NameNotFoundException e) {
2833 /* ignore */
2834 }
2835 return mPreferencesHelper.getNotificationChannels(
2836 targetPkg, targetUid, false /* includeDeleted */);
2837 }
2838 throw new SecurityException("Pkg " + callingPkg
2839 + " cannot read channels for " + targetPkg + " in " + userId);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002840 }
2841
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002842 @Override
Julia Reynoldse273f082018-04-12 13:48:49 -04002843 public int getBlockedAppCount(int userId) {
2844 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002845 return mPreferencesHelper.getBlockedAppCount(userId);
Julia Reynoldse273f082018-04-12 13:48:49 -04002846 }
2847
2848 @Override
Beverly0479cde22018-11-09 11:05:34 -05002849 public int getAppsBypassingDndCount(int userId) {
2850 checkCallerIsSystem();
2851 return mPreferencesHelper.getAppsBypassingDndCount(userId);
2852 }
2853
2854 @Override
2855 public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd(
2856 String pkg, int userId) {
2857 checkCallerIsSystem();
2858 return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, userId);
2859 }
2860
2861 @Override
Beverly86d076f2018-04-17 14:44:52 -04002862 public boolean areChannelsBypassingDnd() {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002863 return mPreferencesHelper.areChannelsBypassingDnd();
Beverly86d076f2018-04-17 14:44:52 -04002864 }
2865
2866 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05002867 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002868 checkCallerIsSystem();
2869
2870 // Cancel posted notifications
2871 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2872 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2873
Julia Reynoldsb852e562017-06-06 16:14:18 -04002874 final String[] packages = new String[] {packageName};
2875 final int[] uids = new int[] {uid};
2876
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002877 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04002878 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002879 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002880
2881 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04002882 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002883
Julia Reynolds67c1e962019-01-04 14:01:10 -05002884 // Snoozing
2885 mSnoozeHelper.clearData(UserHandle.getUserId(uid), packageName);
2886
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002887 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05002888 if (!fromApp) {
Julia Reynolds7af51c52019-04-19 11:08:27 -04002889 mPreferencesHelper.clearData(packageName, uid);
Julia Reynolds5355e852017-02-07 14:54:13 -05002890 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002891
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002892 handleSavePolicyFile();
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002893 }
2894
Julia Reynoldsad6dd352019-03-07 16:46:22 -05002895 @Override
Julia Reynolds088c4482019-04-10 12:43:27 -04002896 public List<String> getAllowedAssistantAdjustments(String pkg) {
Julia Reynoldsad6dd352019-03-07 16:46:22 -05002897 checkCallerIsSystemOrSameApp(pkg);
2898
2899 if (!isCallerSystemOrPhone()
2900 && !mAssistants.isPackageAllowed(pkg, UserHandle.getCallingUserId())) {
2901 throw new SecurityException("Not currently an assistant");
2902 }
2903
Julia Reynolds088c4482019-04-10 12:43:27 -04002904 return mAssistants.getAllowedAssistantAdjustments();
Julia Reynoldsad6dd352019-03-07 16:46:22 -05002905 }
2906
2907 @Override
Julia Reynolds088c4482019-04-10 12:43:27 -04002908 public void allowAssistantAdjustment(String adjustmentType) {
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04002909 checkCallerIsSystemOrSystemUiOrShell();
Julia Reynoldsad6dd352019-03-07 16:46:22 -05002910 mAssistants.allowAdjustmentType(adjustmentType);
2911
2912 handleSavePolicyFile();
2913 }
2914
2915 @Override
Julia Reynolds088c4482019-04-10 12:43:27 -04002916 public void disallowAssistantAdjustment(String adjustmentType) {
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04002917 checkCallerIsSystemOrSystemUiOrShell();
Julia Reynoldsad6dd352019-03-07 16:46:22 -05002918 mAssistants.disallowAdjustmentType(adjustmentType);
2919
2920 handleSavePolicyFile();
2921 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002922
Adam Lesinski182f73f2013-12-05 16:48:06 -08002923 /**
2924 * System-only API for getting a list of current (i.e. not cleared) notifications.
2925 *
2926 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04002927 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002928 */
2929 @Override
2930 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2931 // enforce() will ensure the calling uid has the correct permission
2932 getContext().enforceCallingOrSelfPermission(
2933 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2934 "NotificationManagerService.getActiveNotifications");
2935
2936 StatusBarNotification[] tmp = null;
2937 int uid = Binder.getCallingUid();
2938
2939 // noteOp will check to make sure the callingPkg matches the uid
2940 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2941 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002942 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002943 tmp = new StatusBarNotification[mNotificationList.size()];
2944 final int N = mNotificationList.size();
2945 for (int i=0; i<N; i++) {
2946 tmp[i] = mNotificationList.get(i).sbn;
2947 }
2948 }
2949 }
2950 return tmp;
2951 }
2952
2953 /**
Dan Sandler994349c2015-04-15 11:02:54 -04002954 * Public API for getting a list of current notifications for the calling package/uid.
2955 *
Julia Reynolds573c6532017-01-24 17:44:38 -05002956 * Note that since notification posting is done asynchronously, this will not return
2957 * notifications that are in the process of being posted.
2958 *
Julia Reynoldsd12392c2018-12-17 14:06:04 -05002959 * From {@link Build.VERSION_CODES#Q}, will also return notifications you've posted as
2960 * an app's notification delegate via
2961 * {@link NotificationManager#notifyAsPackage(String, String, int, Notification)}.
2962 *
Dan Sandler994349c2015-04-15 11:02:54 -04002963 * @returns A list of all the package's notifications, in natural order.
2964 */
2965 @Override
2966 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2967 int incomingUserId) {
2968 checkCallerIsSystemOrSameApp(pkg);
2969 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2970 Binder.getCallingUid(), incomingUserId, true, false,
2971 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002972 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002973 final ArrayMap<String, StatusBarNotification> map
2974 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002975 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002976 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002977 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2978 mNotificationList.get(i).sbn);
2979 if (sbn != null) {
2980 map.put(sbn.getKey(), sbn);
2981 }
2982 }
2983 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2984 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2985 if (sbn != null) {
2986 map.put(sbn.getKey(), sbn);
2987 }
2988 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002989 final int M = mEnqueuedNotifications.size();
2990 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002991 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2992 mEnqueuedNotifications.get(i).sbn);
2993 if (sbn != null) {
2994 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04002995 }
2996 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002997 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2998 list.addAll(map.values());
2999 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04003000 }
Dan Sandler994349c2015-04-15 11:02:54 -04003001 }
3002
Chris Wren6676dab2016-12-21 18:26:27 -05003003 private StatusBarNotification sanitizeSbn(String pkg, int userId,
3004 StatusBarNotification sbn) {
Julia Reynoldsd12392c2018-12-17 14:06:04 -05003005 if (sbn.getUserId() == userId) {
3006 if (sbn.getPackageName().equals(pkg) || sbn.getOpPkg().equals(pkg)) {
3007 // We could pass back a cloneLight() but clients might get confused and
3008 // try to send this thing back to notify() again, which would not work
3009 // very well.
3010 return new StatusBarNotification(
3011 sbn.getPackageName(),
3012 sbn.getOpPkg(),
3013 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
3014 sbn.getNotification().clone(),
3015 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
3016 }
Chris Wren6676dab2016-12-21 18:26:27 -05003017 }
3018 return null;
3019 }
3020
Dan Sandler994349c2015-04-15 11:02:54 -04003021 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08003022 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
3023 *
3024 * Requires ACCESS_NOTIFICATIONS which is signature|system.
3025 */
3026 @Override
3027 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
3028 // enforce() will ensure the calling uid has the correct permission
3029 getContext().enforceCallingOrSelfPermission(
3030 android.Manifest.permission.ACCESS_NOTIFICATIONS,
3031 "NotificationManagerService.getHistoricalNotifications");
3032
3033 StatusBarNotification[] tmp = null;
3034 int uid = Binder.getCallingUid();
3035
3036 // noteOp will check to make sure the callingPkg matches the uid
3037 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
3038 == AppOpsManager.MODE_ALLOWED) {
3039 synchronized (mArchive) {
3040 tmp = mArchive.getArray(count);
3041 }
3042 }
3043 return tmp;
3044 }
3045
3046 /**
3047 * Register a listener binder directly with the notification manager.
3048 *
3049 * Only works with system callers. Apps should extend
3050 * {@link android.service.notification.NotificationListenerService}.
3051 */
3052 @Override
3053 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05003054 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02003055 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05003056 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003057 }
3058
3059 /**
3060 * Remove a listener binder directly
3061 */
3062 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003063 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05003064 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003065 }
3066
3067 /**
3068 * Allow an INotificationListener to simulate a "clear all" operation.
3069 *
3070 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
3071 *
3072 * @param token The binder for the listener, to check that the caller is allowed
3073 */
3074 @Override
John Spurlocka4294292014-03-24 18:02:32 -04003075 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04003076 final int callingUid = Binder.getCallingUid();
3077 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08003078 long identity = Binder.clearCallingIdentity();
3079 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003080 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04003081 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Beverly5a20a5e2018-03-06 15:02:44 -05003082
John Spurlocka4294292014-03-24 18:02:32 -04003083 if (keys != null) {
3084 final int N = keys.length;
3085 for (int i = 0; i < N; i++) {
3086 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07003087 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00003088 final int userId = r.sbn.getUserId();
3089 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04003090 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00003091 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04003092 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00003093 }
Griff Hazen335e1f02014-09-11 14:49:31 -07003094 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
3095 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
3096 userId);
John Spurlocka4294292014-03-24 18:02:32 -04003097 }
3098 } else {
3099 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00003100 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04003101 }
Adam Lesinskie8240262014-03-26 16:01:00 -07003102 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003103 } finally {
3104 Binder.restoreCallingIdentity(identity);
3105 }
3106 }
3107
Chris Wrenab41eec2016-01-04 18:01:27 -05003108 /**
3109 * Handle request from an approved listener to re-enable itself.
3110 *
3111 * @param component The componenet to be re-enabled, caller must match package.
3112 */
3113 @Override
3114 public void requestBindListener(ComponentName component) {
3115 checkCallerIsSystemOrSameApp(component.getPackageName());
3116 long identity = Binder.clearCallingIdentity();
3117 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003118 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003119 mAssistants.isComponentEnabledForCurrentProfiles(component)
3120 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05003121 : mListeners;
3122 manager.setComponentState(component, true);
3123 } finally {
3124 Binder.restoreCallingIdentity(identity);
3125 }
3126 }
3127
3128 @Override
3129 public void requestUnbindListener(INotificationListener token) {
3130 long identity = Binder.clearCallingIdentity();
3131 try {
3132 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003133 synchronized (mNotificationLock) {
3134 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3135 info.getOwner().setComponentState(info.component, false);
3136 }
Chris Wrenab41eec2016-01-04 18:01:27 -05003137 } finally {
3138 Binder.restoreCallingIdentity(identity);
3139 }
3140 }
3141
Amith Yamasanif47e51e2015-04-17 10:02:15 -07003142 @Override
3143 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07003144 long identity = Binder.clearCallingIdentity();
3145 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003146 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07003147 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04003148 if (keys == null) {
3149 return;
3150 }
3151 ArrayList<NotificationRecord> seen = new ArrayList<>();
3152 final int n = keys.length;
3153 for (int i = 0; i < n; i++) {
3154 NotificationRecord r = mNotificationsByKey.get(keys[i]);
3155 if (r == null) continue;
3156 final int userId = r.sbn.getUserId();
3157 if (userId != info.userid && userId != UserHandle.USER_ALL
3158 && !mUserProfiles.isCurrentProfile(userId)) {
3159 throw new SecurityException("Disallowed call from listener: "
3160 + info.service);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07003161 }
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04003162 seen.add(r);
3163 if (!r.isSeen()) {
3164 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
3165 reportSeen(r);
3166 r.setSeen();
3167 maybeRecordInterruptionLocked(r);
3168 }
3169 }
3170 if (!seen.isEmpty()) {
3171 mAssistants.onNotificationsSeenLocked(seen);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07003172 }
3173 }
3174 } finally {
3175 Binder.restoreCallingIdentity(identity);
3176 }
3177 }
3178
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003179 /**
3180 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
3181 *
3182 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
3183 *
Julia Reynolds79672302017-01-12 08:30:16 -05003184 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003185 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04003186 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04003187 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00003188 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04003189 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Mady Mellor49b1bf12019-03-29 12:00:02 -07003190 FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE | FLAG_BUBBLE,
John Spurlocka4294292014-03-24 18:02:32 -04003191 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00003192 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04003193 }
3194
Adam Lesinski182f73f2013-12-05 16:48:06 -08003195 /**
Julia Reynolds79672302017-01-12 08:30:16 -05003196 * Allow an INotificationListener to snooze a single notification until a context.
3197 *
3198 * @param token The binder for the listener, to check that the caller is allowed
3199 */
3200 @Override
3201 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
3202 String key, String snoozeCriterionId) {
3203 long identity = Binder.clearCallingIdentity();
3204 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003205 synchronized (mNotificationLock) {
3206 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3207 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
3208 }
Julia Reynolds79672302017-01-12 08:30:16 -05003209 } finally {
3210 Binder.restoreCallingIdentity(identity);
3211 }
3212 }
3213
3214 /**
3215 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003216 *
3217 * @param token The binder for the listener, to check that the caller is allowed
3218 */
3219 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003220 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05003221 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003222 long identity = Binder.clearCallingIdentity();
3223 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003224 synchronized (mNotificationLock) {
3225 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3226 snoozeNotificationInt(key, duration, null, info);
3227 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003228 } finally {
3229 Binder.restoreCallingIdentity(identity);
3230 }
3231 }
3232
3233 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05003234 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003235 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05003236 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003237 */
3238 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05003239 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003240 long identity = Binder.clearCallingIdentity();
3241 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003242 synchronized (mNotificationLock) {
3243 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003244 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003245 unsnoozeNotificationInt(key, info);
3246 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003247 } finally {
3248 Binder.restoreCallingIdentity(identity);
3249 }
3250 }
3251
3252 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08003253 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
3254 *
3255 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
3256 *
3257 * @param token The binder for the listener, to check that the caller is allowed
3258 */
3259 @Override
3260 public void cancelNotificationFromListener(INotificationListener token, String pkg,
3261 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04003262 final int callingUid = Binder.getCallingUid();
3263 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08003264 long identity = Binder.clearCallingIdentity();
3265 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003266 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04003267 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00003268 if (info.supportsProfiles()) {
Tony Mak180a9c42019-03-08 13:33:08 +00003269 Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
Kenny Guya263e4e2014-03-03 18:24:03 +00003270 + "from " + info.component
3271 + " use cancelNotification(key) instead.");
3272 } else {
3273 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
3274 pkg, tag, id, info.userid);
3275 }
Adam Lesinskie8240262014-03-26 16:01:00 -07003276 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003277 } finally {
3278 Binder.restoreCallingIdentity(identity);
3279 }
3280 }
3281
3282 /**
3283 * Allow an INotificationListener to request the list of outstanding notifications seen by
3284 * the current user. Useful when starting up, after which point the listener callbacks
3285 * should be used.
3286 *
3287 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04003288 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04003289 * @returns The return value will contain the notifications specified in keys, in that
3290 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08003291 */
3292 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02003293 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02003294 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003295 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04003296 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04003297 final boolean getKeys = keys != null;
3298 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02003299 final ArrayList<StatusBarNotification> list
3300 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02003301 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04003302 final NotificationRecord r = getKeys
3303 ? mNotificationsByKey.get(keys[i])
3304 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02003305 if (r == null) continue;
3306 StatusBarNotification sbn = r.sbn;
3307 if (!isVisibleToListener(sbn, info)) continue;
3308 StatusBarNotification sbnToSend =
3309 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
3310 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003311 }
Christoph Studercee44ba2014-05-20 18:36:43 +02003312 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003313 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003314 }
3315
Julia Reynoldscf63ff12017-01-24 13:55:48 -05003316 /**
3317 * Allow an INotificationListener to request the list of outstanding snoozed notifications
3318 * seen by the current user. Useful when starting up, after which point the listener
3319 * callbacks should be used.
3320 *
3321 * @param token The binder for the listener, to check that the caller is allowed
3322 * @returns The return value will contain the notifications specified in keys, in that
3323 * order, or if keys is null, all the notifications, in natural order.
3324 */
3325 @Override
3326 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
3327 INotificationListener token, int trim) {
3328 synchronized (mNotificationLock) {
3329 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3330 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
3331 final int N = snoozedRecords.size();
3332 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
3333 for (int i=0; i < N; i++) {
3334 final NotificationRecord r = snoozedRecords.get(i);
3335 if (r == null) continue;
3336 StatusBarNotification sbn = r.sbn;
3337 if (!isVisibleToListener(sbn, info)) continue;
3338 StatusBarNotification sbnToSend =
3339 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
3340 list.add(sbnToSend);
3341 }
3342 return new ParceledListSlice<>(list);
3343 }
3344 }
3345
Adam Lesinski182f73f2013-12-05 16:48:06 -08003346 @Override
Julia Reynolds4703bac2018-09-12 10:39:30 -04003347 public void clearRequestedListenerHints(INotificationListener token) {
3348 final long identity = Binder.clearCallingIdentity();
3349 try {
3350 synchronized (mNotificationLock) {
3351 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3352 removeDisabledHints(info);
3353 updateListenerHintsLocked();
3354 updateEffectsSuppressorLocked();
3355 }
3356 } finally {
3357 Binder.restoreCallingIdentity(identity);
3358 }
3359 }
3360
3361 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04003362 public void requestHintsFromListener(INotificationListener token, int hints) {
3363 final long identity = Binder.clearCallingIdentity();
3364 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003365 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003366 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07003367 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
3368 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
3369 | HINT_HOST_DISABLE_CALL_EFFECTS;
3370 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04003371 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003372 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003373 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07003374 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003375 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04003376 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04003377 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04003378 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04003379 } finally {
3380 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04003381 }
3382 }
3383
3384 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04003385 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003386 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003387 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04003388 }
3389 }
3390
3391 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02003392 public void requestInterruptionFilterFromListener(INotificationListener token,
3393 int interruptionFilter) throws RemoteException {
3394 final long identity = Binder.clearCallingIdentity();
3395 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003396 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05003397 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3398 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02003399 updateInterruptionFilterLocked();
3400 }
3401 } finally {
3402 Binder.restoreCallingIdentity(identity);
3403 }
3404 }
3405
3406 @Override
3407 public int getInterruptionFilterFromListener(INotificationListener token)
3408 throws RemoteException {
3409 synchronized (mNotificationLight) {
3410 return mInterruptionFilter;
3411 }
3412 }
3413
3414 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02003415 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
3416 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003417 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02003418 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3419 if (info == null) return;
3420 mListeners.setOnNotificationPostedTrimLocked(info, trim);
3421 }
3422 }
3423
3424 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04003425 public int getZenMode() {
3426 return mZenModeHelper.getZenMode();
3427 }
3428
3429 @Override
John Spurlock056c5192014-04-20 21:52:01 -04003430 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003431 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04003432 return mZenModeHelper.getConfig();
3433 }
3434
3435 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04003436 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003437 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05003438 final long identity = Binder.clearCallingIdentity();
3439 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04003440 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05003441 } finally {
3442 Binder.restoreCallingIdentity(identity);
3443 }
3444 }
3445
3446 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05003447 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003448 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05003449 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003450 }
3451
3452 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003453 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
3454 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003455 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003456 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003457 }
3458
3459 @Override
Julia Reynoldsa94365d2019-04-09 10:48:43 -04003460 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003461 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
3462 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
Julia Reynolds68062072018-08-06 15:38:21 -04003463 if (automaticZenRule.getOwner() == null
3464 && automaticZenRule.getConfigurationActivity() == null) {
3465 throw new NullPointerException(
3466 "Rule must have a conditionproviderservice and/or configuration activity");
3467 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003468 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynoldsa94365d2019-04-09 10:48:43 -04003469 if (automaticZenRule.getZenPolicy() != null
3470 && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) {
3471 throw new IllegalArgumentException("ZenPolicy is only applicable to "
3472 + "INTERRUPTION_FILTER_PRIORITY filters");
3473 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003474 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003475
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003476 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
3477 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003478 }
3479
3480 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05003481 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003482 throws RemoteException {
3483 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
3484 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
Julia Reynolds68062072018-08-06 15:38:21 -04003485 if (automaticZenRule.getOwner() == null
3486 && automaticZenRule.getConfigurationActivity() == null) {
3487 throw new NullPointerException(
3488 "Rule must have a conditionproviderservice and/or configuration activity");
3489 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003490 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
3491 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003492
Julia Reynolds361e82d32016-02-26 18:19:49 -05003493 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003494 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003495 }
3496
3497 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003498 public boolean removeAutomaticZenRule(String id) throws RemoteException {
3499 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003500 // Verify that they can modify zen rules.
3501 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
3502
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003503 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003504 }
3505
3506 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05003507 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
3508 Preconditions.checkNotNull(packageName, "Package name is null");
3509 enforceSystemOrSystemUI("removeAutomaticZenRules");
3510
3511 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
3512 }
3513
3514 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05003515 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
3516 Preconditions.checkNotNull(owner, "Owner is null");
3517 enforceSystemOrSystemUI("getRuleInstanceCount");
3518
3519 return mZenModeHelper.getCurrentInstanceCount(owner);
3520 }
3521
3522 @Override
Julia Reynolds68062072018-08-06 15:38:21 -04003523 public void setAutomaticZenRuleState(String id, Condition condition) {
3524 Preconditions.checkNotNull(id, "id is null");
3525 Preconditions.checkNotNull(condition, "Condition is null");
3526
3527 enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
3528
3529 mZenModeHelper.setAutomaticZenRuleState(id, condition);
3530 }
3531
3532 @Override
John Spurlock80774932015-05-07 17:38:50 -04003533 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
3534 enforcePolicyAccess(pkg, "setInterruptionFilter");
3535 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
3536 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
3537 final long identity = Binder.clearCallingIdentity();
3538 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04003539 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04003540 } finally {
3541 Binder.restoreCallingIdentity(identity);
3542 }
3543 }
3544
3545 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04003546 public void notifyConditions(final String pkg, IConditionProvider provider,
3547 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04003548 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3549 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04003550 mHandler.post(new Runnable() {
3551 @Override
3552 public void run() {
3553 mConditionProviders.notifyConditions(pkg, info, conditions);
3554 }
3555 });
John Spurlocke77bb362014-04-26 10:24:59 -04003556 }
3557
Julia Reynolds38e6ca42016-08-08 08:38:09 -04003558 @Override
3559 public void requestUnbindProvider(IConditionProvider provider) {
3560 long identity = Binder.clearCallingIdentity();
3561 try {
3562 // allow bound services to disable themselves
3563 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3564 info.getOwner().setComponentState(info.component, false);
3565 } finally {
3566 Binder.restoreCallingIdentity(identity);
3567 }
3568 }
3569
3570 @Override
3571 public void requestBindProvider(ComponentName component) {
3572 checkCallerIsSystemOrSameApp(component.getPackageName());
3573 long identity = Binder.clearCallingIdentity();
3574 try {
3575 mConditionProviders.setComponentState(component, true);
3576 } finally {
3577 Binder.restoreCallingIdentity(identity);
3578 }
3579 }
3580
John Spurlocke77bb362014-04-26 10:24:59 -04003581 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003582 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04003583 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
3584 message);
John Spurlock7340fc82014-04-24 18:50:12 -04003585 }
3586
Julia Reynolds48034f82016-03-09 10:15:16 -05003587 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
3588 try {
3589 checkCallerIsSystemOrSameApp(pkg);
3590 } catch (SecurityException e) {
3591 getContext().enforceCallingPermission(
3592 android.Manifest.permission.STATUS_BAR_SERVICE,
3593 message);
3594 }
3595 }
3596
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003597 private void enforcePolicyAccess(int uid, String method) {
3598 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3599 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3600 return;
3601 }
3602 boolean accessAllowed = false;
Julia Reynolds4214da92019-04-10 15:04:06 -04003603 String[] packages = mPackageManagerClient.getPackagesForUid(uid);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003604 final int packageCount = packages.length;
3605 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003606 if (mConditionProviders.isPackageOrComponentAllowed(
3607 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003608 accessAllowed = true;
3609 }
3610 }
3611 if (!accessAllowed) {
3612 Slog.w(TAG, "Notification policy access denied calling " + method);
3613 throw new SecurityException("Notification policy access denied");
3614 }
3615 }
3616
John Spurlock80774932015-05-07 17:38:50 -04003617 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04003618 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3619 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3620 return;
3621 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04003622 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003623 if (!checkPolicyAccess(pkg)) {
3624 Slog.w(TAG, "Notification policy access denied calling " + method);
3625 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04003626 }
3627 }
3628
John Spurlock80774932015-05-07 17:38:50 -04003629 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003630 return mConditionProviders.isPackageOrComponentAllowed(
3631 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04003632 }
3633
3634 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003635 try {
Jason Parks50322ff2018-03-27 10:23:33 -05003636 int uid = getContext().getPackageManager().getPackageUidAsUser(pkg,
3637 UserHandle.getCallingUserId());
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003638 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
3639 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
3640 -1, true)) {
3641 return true;
3642 }
3643 } catch (NameNotFoundException e) {
3644 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003645 }
Jason Parks50322ff2018-03-27 10:23:33 -05003646 return checkPackagePolicyAccess(pkg)
3647 || mListeners.isComponentEnabledForPackage(pkg)
3648 || (mDpm != null &&
3649 mDpm.isActiveAdminWithPolicy(Binder.getCallingUid(),
3650 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER));
John Spurlock1fc476d2015-04-14 16:05:20 -04003651 }
3652
John Spurlock7340fc82014-04-24 18:50:12 -04003653 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08003654 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003655 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04003656 final DumpFilter filter = DumpFilter.parseFromArguments(args);
Makoto Onukibbb4b222018-06-25 16:01:02 -07003657 final long token = Binder.clearCallingIdentity();
3658 try {
3659 if (filter.stats) {
3660 dumpJson(pw, filter);
3661 } else if (filter.proto) {
3662 dumpProto(fd, filter);
3663 } else if (filter.criticalPriority) {
3664 dumpNotificationRecords(pw, filter);
3665 } else {
3666 dumpImpl(pw, filter);
3667 }
3668 } finally {
3669 Binder.restoreCallingIdentity(token);
Chris Wrene4b38802015-07-07 15:54:19 -04003670 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003671 }
John Spurlockb4782522014-08-22 14:54:46 -04003672
3673 @Override
3674 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07003675 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04003676 }
John Spurlock2b122f42014-08-27 16:29:47 -04003677
3678 @Override
3679 public boolean matchesCallFilter(Bundle extras) {
3680 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02003681 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003682 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02003683 extras,
3684 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
3685 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
3686 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04003687 }
John Spurlock530052a2014-11-30 16:26:19 -05003688
3689 @Override
3690 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003691 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04003692 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05003693 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003694
Christopher Tatef9767d62015-04-08 14:35:43 -07003695 // Backup/restore interface
3696 @Override
3697 public byte[] getBackupPayload(int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003698 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003699 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Julia Reynolds8a613f82018-12-13 14:25:13 -05003700 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
3701 try {
Annie Meng8b646fd2019-02-01 18:46:42 +00003702 writePolicyXml(baos, true /*forBackup*/, user);
Julia Reynolds8a613f82018-12-13 14:25:13 -05003703 return baos.toByteArray();
3704 } catch (IOException e) {
3705 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
John Spurlock35ef0a62015-05-28 11:24:10 -04003706 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003707 return null;
3708 }
3709
3710 @Override
3711 public void applyRestore(byte[] payload, int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003712 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003713 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
3714 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
3715 if (payload == null) {
3716 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
3717 return;
3718 }
Julia Reynolds8a613f82018-12-13 14:25:13 -05003719 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
3720 try {
Annie Meng8b646fd2019-02-01 18:46:42 +00003721 readPolicyXml(bais, true /*forRestore*/, user);
Julia Reynolds8a613f82018-12-13 14:25:13 -05003722 handleSavePolicyFile();
3723 } catch (NumberFormatException | XmlPullParserException | IOException e) {
3724 Slog.w(TAG, "applyRestore: error reading payload", e);
John Spurlock35ef0a62015-05-28 11:24:10 -04003725 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003726 }
3727
John Spurlock1fc476d2015-04-14 16:05:20 -04003728 @Override
John Spurlock80774932015-05-07 17:38:50 -04003729 public boolean isNotificationPolicyAccessGranted(String pkg) {
3730 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04003731 }
3732
3733 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05003734 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
3735 enforceSystemOrSystemUIOrSamePackage(pkg,
3736 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003737 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003738 }
3739
3740 @Override
John Spurlock80774932015-05-07 17:38:50 -04003741 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
3742 throws RemoteException {
Julia Reynolds92febc32017-10-26 11:30:31 -04003743 setNotificationPolicyAccessGrantedForUser(
3744 pkg, getCallingUserHandle().getIdentifier(), granted);
3745 }
3746
3747 @Override
3748 public void setNotificationPolicyAccessGrantedForUser(
3749 String pkg, int userId, boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003750 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003751 final long identity = Binder.clearCallingIdentity();
3752 try {
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05003753 if (mAllowedManagedServicePackages.test(
3754 pkg, userId, mConditionProviders.getRequiredPermission())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003755 mConditionProviders.setPackageOrComponentEnabled(
Julia Reynolds92febc32017-10-26 11:30:31 -04003756 pkg, userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003757
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003758 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds4afe2642019-05-01 08:42:24 -04003759 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003760 .setPackage(pkg)
Julia Reynolds99f72072019-01-14 09:35:22 -05003761 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Julia Reynolds92febc32017-10-26 11:30:31 -04003762 UserHandle.of(userId), null);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05003763 handleSavePolicyFile();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003764 }
3765 } finally {
3766 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003767 }
John Spurlock80774932015-05-07 17:38:50 -04003768 }
3769
3770 @Override
3771 public Policy getNotificationPolicy(String pkg) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003772 final long identity = Binder.clearCallingIdentity();
3773 try {
3774 return mZenModeHelper.getNotificationPolicy();
3775 } finally {
3776 Binder.restoreCallingIdentity(identity);
3777 }
3778 }
3779
Beverlyff2df9b2018-10-10 16:54:10 -04003780 @Override
3781 public Policy getConsolidatedNotificationPolicy() {
3782 final long identity = Binder.clearCallingIdentity();
3783 try {
3784 return mZenModeHelper.getConsolidatedNotificationPolicy();
3785 } finally {
3786 Binder.restoreCallingIdentity(identity);
3787 }
3788 }
3789
Beverly6697eff2017-12-14 15:00:27 -05003790 /**
3791 * Sets the notification policy. Apps that target API levels below
Beverly98ef61b2018-02-15 10:36:28 -05003792 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
Beverlyd6964762018-02-16 14:07:03 -05003793 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3794 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3795 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
Beverly6697eff2017-12-14 15:00:27 -05003796 */
John Spurlock1fc476d2015-04-14 16:05:20 -04003797 @Override
John Spurlock80774932015-05-07 17:38:50 -04003798 public void setNotificationPolicy(String pkg, Policy policy) {
3799 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04003800 final long identity = Binder.clearCallingIdentity();
3801 try {
Beverly6697eff2017-12-14 15:00:27 -05003802 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3803 0, UserHandle.getUserId(MY_UID));
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003804 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
Beverly6697eff2017-12-14 15:00:27 -05003805
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06003806 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
Beverly98ef61b2018-02-15 10:36:28 -05003807 int priorityCategories = policy.priorityCategories;
3808 // ignore alarm and media values from new policy
3809 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
Beverlyd6964762018-02-16 14:07:03 -05003810 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3811 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003812 // use user-designated values
Beverlyd6964762018-02-16 14:07:03 -05003813 priorityCategories |= currPolicy.priorityCategories
3814 & Policy.PRIORITY_CATEGORY_ALARMS;
3815 priorityCategories |= currPolicy.priorityCategories
3816 & Policy.PRIORITY_CATEGORY_MEDIA;
3817 priorityCategories |= currPolicy.priorityCategories
3818 & Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003819
Beverly6697eff2017-12-14 15:00:27 -05003820 policy = new Policy(priorityCategories,
3821 policy.priorityCallSenders, policy.priorityMessageSenders,
3822 policy.suppressedVisualEffects);
3823 }
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003824 int newVisualEffects = calculateSuppressedVisualEffects(
3825 policy, currPolicy, applicationInfo.targetSdkVersion);
3826 policy = new Policy(policy.priorityCategories,
3827 policy.priorityCallSenders, policy.priorityMessageSenders,
3828 newVisualEffects);
Beverly5e073222018-03-08 10:36:25 -05003829 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
John Spurlock1fc476d2015-04-14 16:05:20 -04003830 mZenModeHelper.setNotificationPolicy(policy);
Beverly6697eff2017-12-14 15:00:27 -05003831 } catch (RemoteException e) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003832 } finally {
3833 Binder.restoreCallingIdentity(identity);
3834 }
3835 }
Chris Wren51017d02015-12-15 15:34:46 -05003836
3837 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003838 public List<String> getEnabledNotificationListenerPackages() {
3839 checkCallerIsSystem();
3840 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3841 }
3842
3843 @Override
3844 public List<ComponentName> getEnabledNotificationListeners(int userId) {
3845 checkCallerIsSystem();
3846 return mListeners.getAllowedComponents(userId);
3847 }
3848
3849 @Override
Fabian Kozynskid9425662019-01-29 13:08:30 -05003850 public ComponentName getAllowedNotificationAssistantForUser(int userId) {
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04003851 checkCallerIsSystemOrSystemUiOrShell();
Fabian Kozynskid9425662019-01-29 13:08:30 -05003852 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
3853 if (allowedComponents.size() > 1) {
3854 throw new IllegalStateException(
3855 "At most one NotificationAssistant: " + allowedComponents.size());
3856 }
3857 return CollectionUtils.firstOrNull(allowedComponents);
3858 }
3859
3860 @Override
3861 public ComponentName getAllowedNotificationAssistant() {
3862 return getAllowedNotificationAssistantForUser(getCallingUserHandle().getIdentifier());
3863 }
3864
3865 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003866 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3867 Preconditions.checkNotNull(listener);
3868 checkCallerIsSystemOrSameApp(listener.getPackageName());
3869 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3870 getCallingUserHandle().getIdentifier());
3871 }
3872
3873 @Override
3874 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3875 int userId) {
3876 Preconditions.checkNotNull(listener);
3877 checkCallerIsSystem();
3878 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3879 userId);
3880 }
3881
3882 @Override
3883 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3884 Preconditions.checkNotNull(assistant);
3885 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003886 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04003887 getCallingUserHandle().getIdentifier());
3888 }
3889
3890 @Override
3891 public void setNotificationListenerAccessGranted(ComponentName listener,
3892 boolean granted) throws RemoteException {
3893 setNotificationListenerAccessGrantedForUser(
3894 listener, getCallingUserHandle().getIdentifier(), granted);
3895 }
3896
3897 @Override
3898 public void setNotificationAssistantAccessGranted(ComponentName assistant,
Tony Mak9a3c1f12019-03-04 16:04:42 +00003899 boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003900 setNotificationAssistantAccessGrantedForUser(
3901 assistant, getCallingUserHandle().getIdentifier(), granted);
3902 }
3903
3904 @Override
3905 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
Tony Mak9a3c1f12019-03-04 16:04:42 +00003906 boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003907 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04003908 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003909 final long identity = Binder.clearCallingIdentity();
3910 try {
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05003911 if (mAllowedManagedServicePackages.test(
3912 listener.getPackageName(), userId, mListeners.getRequiredPermission())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003913 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3914 userId, false, granted);
3915 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3916 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003917
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003918 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds4afe2642019-05-01 08:42:24 -04003919 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003920 .setPackage(listener.getPackageName())
3921 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003922 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003923
Julia Reynoldsb62dad42018-11-26 16:33:02 -05003924 handleSavePolicyFile();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003925 }
3926 } finally {
3927 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003928 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003929 }
3930
3931 @Override
3932 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
Tony Mak9a3c1f12019-03-04 16:04:42 +00003933 int userId, boolean granted) {
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04003934 checkCallerIsSystemOrSystemUiOrShell();
Julia Reynolds4afe2642019-05-01 08:42:24 -04003935 for (UserInfo ui : mUm.getEnabledProfiles(userId)) {
3936 mAssistants.setUserSet(ui.id, true);
3937 }
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003938 final long identity = Binder.clearCallingIdentity();
3939 try {
Tony Mak9a3c1f12019-03-04 16:04:42 +00003940 setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003941 } finally {
3942 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003943 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003944 }
3945
3946 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003947 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003948 Adjustment adjustment) {
3949 boolean foundEnqueued = false;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003950 final long identity = Binder.clearCallingIdentity();
3951 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003952 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003953 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003954 int N = mEnqueuedNotifications.size();
3955 for (int i = 0; i < N; i++) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003956 final NotificationRecord r = mEnqueuedNotifications.get(i);
3957 if (Objects.equals(adjustment.getKey(), r.getKey())
Julia Reynolds70aaea72018-07-13 13:38:34 -04003958 && Objects.equals(adjustment.getUser(), r.getUserId())
3959 && mAssistants.isSameUser(token, r.getUserId())) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003960 applyAdjustment(r, adjustment);
3961 r.applyAdjustments();
Julia Reynolds27c0a962018-12-10 12:37:28 -05003962 // importance is checked at the beginning of the
3963 // PostNotificationRunnable, before the signal extractors are run, so
3964 // calculate the final importance here
3965 r.calculateImportance();
Julia Reynolds666ccf02018-06-18 10:19:20 -04003966 foundEnqueued = true;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003967 break;
3968 }
3969 }
Julia Reynolds666ccf02018-06-18 10:19:20 -04003970 if (!foundEnqueued) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003971 applyAdjustmentFromAssistant(token, adjustment);
3972 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003973 }
3974 } finally {
3975 Binder.restoreCallingIdentity(identity);
3976 }
3977 }
3978
3979 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003980 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003981 Adjustment adjustment) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003982 List<Adjustment> adjustments = new ArrayList<>();
3983 adjustments.add(adjustment);
3984 applyAdjustmentsFromAssistant(token, adjustments);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003985 }
3986
3987 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003988 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003989 List<Adjustment> adjustments) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003990
Julia Reynoldsefcdff42018-08-09 09:42:56 -04003991 boolean needsSort = false;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003992 final long identity = Binder.clearCallingIdentity();
3993 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003994 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003995 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003996 for (Adjustment adjustment : adjustments) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003997 NotificationRecord r = mNotificationsByKey.get(adjustment.getKey());
3998 if (r != null && mAssistants.isSameUser(token, r.getUserId())) {
3999 applyAdjustment(r, adjustment);
Julia Reynolds27c0a962018-12-10 12:37:28 -05004000 // If the assistant has blocked the notification, cancel it
4001 // This will trigger a sort, so we don't have to explicitly ask for
4002 // one here.
4003 if (adjustment.getSignals().containsKey(Adjustment.KEY_IMPORTANCE)
4004 && adjustment.getSignals().getInt(Adjustment.KEY_IMPORTANCE)
4005 == IMPORTANCE_NONE) {
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004006 cancelNotificationsFromListener(token, new String[]{r.getKey()});
4007 } else {
4008 needsSort = true;
4009 }
Julia Reynolds70aaea72018-07-13 13:38:34 -04004010 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04004011 }
4012 }
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004013 if (needsSort) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04004014 mRankingHandler.requestSort();
4015 }
Chris Wren51017d02015-12-15 15:34:46 -05004016 } finally {
4017 Binder.restoreCallingIdentity(identity);
4018 }
4019 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004020
4021 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04004022 public void updateNotificationChannelGroupFromPrivilegedListener(
4023 INotificationListener token, String pkg, UserHandle user,
4024 NotificationChannelGroup group) throws RemoteException {
4025 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04004026 verifyPrivilegedListener(token, user, false);
Julia Reynolds005c8b92017-08-24 10:35:53 -04004027 createNotificationChannelGroup(
4028 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05004029 handleSavePolicyFile();
Julia Reynolds005c8b92017-08-24 10:35:53 -04004030 }
4031
4032 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004033 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004034 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004035 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004036 Preconditions.checkNotNull(pkg);
4037 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004038
Julia Reynolds48a6ed92018-10-22 12:52:03 -04004039 verifyPrivilegedListener(token, user, false);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004040 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004041 }
4042
4043 @Override
4044 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004045 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
4046 Preconditions.checkNotNull(pkg);
4047 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04004048 verifyPrivilegedListener(token, user, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004049
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004050 return mPreferencesHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004051 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004052 }
4053
4054 @Override
4055 public ParceledListSlice<NotificationChannelGroup>
4056 getNotificationChannelGroupsFromPrivilegedListener(
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 Reynoldsf27d6b22017-04-13 15:48:16 -04004061
4062 List<NotificationChannelGroup> groups = new ArrayList<>();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004063 groups.addAll(mPreferencesHelper.getNotificationChannelGroups(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004064 pkg, getUidForPackageAndUser(pkg, user)));
4065 return new ParceledListSlice<>(groups);
4066 }
4067
Zimuzob3b9c262018-10-31 11:54:20 +00004068 @Override
4069 public void setPrivateNotificationsAllowed(boolean allow) {
4070 if (PackageManager.PERMISSION_GRANTED
4071 != getContext().checkCallingPermission(
4072 permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
4073 throw new SecurityException(
4074 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
4075 }
4076 if (allow != mLockScreenAllowSecureNotifications) {
4077 mLockScreenAllowSecureNotifications = allow;
Julia Reynoldsb62dad42018-11-26 16:33:02 -05004078 handleSavePolicyFile();
Zimuzob3b9c262018-10-31 11:54:20 +00004079 }
4080 }
4081
4082 @Override
4083 public boolean getPrivateNotificationsAllowed() {
4084 if (PackageManager.PERMISSION_GRANTED
4085 != getContext().checkCallingPermission(
4086 permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
4087 throw new SecurityException(
4088 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
4089 }
4090 return mLockScreenAllowSecureNotifications;
4091 }
4092
Julia Reynoldsb40cd092019-01-25 09:35:02 -05004093 @Override
4094 public boolean isPackagePaused(String pkg) {
4095 Preconditions.checkNotNull(pkg);
4096 checkCallerIsSameApp(pkg);
4097
4098 boolean isPaused;
4099
4100 final PackageManagerInternal pmi = LocalServices.getService(
4101 PackageManagerInternal.class);
4102 int flags = pmi.getDistractingPackageRestrictions(
4103 pkg, Binder.getCallingUserHandle().getIdentifier());
4104 isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
4105
4106 isPaused |= isPackageSuspendedForUser(pkg, Binder.getCallingUid());
4107
4108 return isPaused;
4109 }
4110
Julia Reynolds48a6ed92018-10-22 12:52:03 -04004111 private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
4112 boolean assistantAllowed) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04004113 ManagedServiceInfo info;
4114 synchronized (mNotificationLock) {
4115 info = mListeners.checkServiceTokenLocked(token);
4116 }
Julia Reynoldsda781472017-04-12 09:41:16 -04004117 if (!hasCompanionDevice(info)) {
Julia Reynolds48a6ed92018-10-22 12:52:03 -04004118 synchronized (mNotificationLock) {
4119 if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) {
4120 throw new SecurityException(info + " does not have access");
4121 }
4122 }
Julia Reynoldsda781472017-04-12 09:41:16 -04004123 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004124 if (!info.enabledAndUserMatches(user.getIdentifier())) {
4125 throw new SecurityException(info + " does not have access");
4126 }
4127 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004128
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004129 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
4130 int uid = 0;
4131 long identity = Binder.clearCallingIdentity();
4132 try {
4133 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
4134 } finally {
4135 Binder.restoreCallingIdentity(identity);
4136 }
4137 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004138 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04004139
4140 @Override
4141 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
4142 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
4143 throws RemoteException {
Dan Sandler7647f1d2018-11-26 09:56:26 -05004144 new NotificationShellCmd(NotificationManagerService.this)
4145 .exec(this, in, out, err, args, callback, resultReceiver);
Julia Reynoldsb852e562017-06-06 16:14:18 -04004146 }
John Spurlock1fc476d2015-04-14 16:05:20 -04004147 };
John Spurlocka4294292014-03-24 18:02:32 -04004148
Tony Mak9a3c1f12019-03-04 16:04:42 +00004149 @VisibleForTesting
4150 protected void setNotificationAssistantAccessGrantedForUserInternal(
Julia Reynolds4afe2642019-05-01 08:42:24 -04004151 ComponentName assistant, int baseUserId, boolean granted) {
4152 List<UserInfo> users = mUm.getEnabledProfiles(baseUserId);
4153 if (users != null) {
4154 for (UserInfo user : users) {
4155 int userId = user.id;
4156 if (assistant == null) {
4157 ComponentName allowedAssistant = CollectionUtils.firstOrNull(
4158 mAssistants.getAllowedComponents(userId));
4159 if (allowedAssistant != null) {
4160 setNotificationAssistantAccessGrantedForUserInternal(
4161 allowedAssistant, userId, false);
4162 }
4163 continue;
4164 }
4165 if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(),
4166 userId, mAssistants.getRequiredPermission())) {
4167 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
4168 userId, false, granted);
4169 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
4170 userId, true, granted);
4171
4172 getContext().sendBroadcastAsUser(
4173 new Intent(ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4174 .setPackage(assistant.getPackageName())
4175 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
4176 UserHandle.of(userId), null);
4177
4178 handleSavePolicyFile();
4179 }
Tony Mak9a3c1f12019-03-04 16:04:42 +00004180 }
Tony Mak9a3c1f12019-03-04 16:04:42 +00004181 }
4182 }
4183
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004184 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
4185 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04004186 return;
4187 }
Julia Reynoldsc7dcdc22019-03-25 10:26:14 -04004188 if (adjustment.getSignals() != null) {
4189 final Bundle adjustments = adjustment.getSignals();
4190 Bundle.setDefusable(adjustments, true);
4191 List<String> toRemove = new ArrayList<>();
4192 for (String potentialKey : adjustments.keySet()) {
4193 if (!mAssistants.isAdjustmentAllowed(potentialKey)) {
4194 toRemove.add(potentialKey);
4195 }
Julia Reynolds418a8ff2019-03-21 10:45:10 -04004196 }
Julia Reynoldsc7dcdc22019-03-25 10:26:14 -04004197 for (String removeKey : toRemove) {
4198 adjustments.remove(removeKey);
4199 }
4200 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04004201 }
4202 }
4203
Julia Reynolds88860ce2017-06-01 16:55:49 -04004204 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004205 void addAutogroupKeyLocked(String key) {
4206 NotificationRecord r = mNotificationsByKey.get(key);
4207 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04004208 return;
4209 }
Julia Reynolds51710712017-07-19 13:48:07 -04004210 if (r.sbn.getOverrideGroupKey() == null) {
4211 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
4212 EventLogTags.writeNotificationAutogrouped(key);
4213 mRankingHandler.requestSort();
4214 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04004215 }
4216
Julia Reynolds88860ce2017-06-01 16:55:49 -04004217 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004218 void removeAutogroupKeyLocked(String key) {
4219 NotificationRecord r = mNotificationsByKey.get(key);
4220 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04004221 return;
4222 }
Julia Reynolds51710712017-07-19 13:48:07 -04004223 if (r.sbn.getOverrideGroupKey() != null) {
4224 addAutoGroupAdjustment(r, null);
4225 EventLogTags.writeNotificationUnautogrouped(key);
4226 mRankingHandler.requestSort();
4227 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004228 }
4229
4230 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
4231 Bundle signals = new Bundle();
4232 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
4233 Adjustment adjustment =
4234 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
4235 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004236 }
4237
4238 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04004239 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04004240 private void clearAutogroupSummaryLocked(int userId, String pkg) {
4241 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
4242 if (summaries != null && summaries.containsKey(pkg)) {
4243 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004244 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04004245 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04004246 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004247 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04004248 }
4249 }
4250 }
4251
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04004252 @GuardedBy("mNotificationLock")
4253 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
4254 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
4255 return summaries != null && summaries.containsKey(sbn.getPackageName());
4256 }
4257
Julia Reynoldse46bb372016-03-17 11:05:58 -04004258 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04004259 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
4260 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004261 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04004262 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
4263 if (notificationRecord == null) {
4264 // The notification could have been cancelled again already. A successive
4265 // adjustment will post a summary if needed.
4266 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04004267 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04004268 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
4269 userId = adjustedSbn.getUser().getIdentifier();
4270 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
4271 if (summaries == null) {
4272 summaries = new ArrayMap<>();
4273 }
4274 mAutobundledSummaries.put(userId, summaries);
4275 if (!summaries.containsKey(pkg)) {
4276 // Add summary
4277 final ApplicationInfo appInfo =
4278 adjustedSbn.getNotification().extras.getParcelable(
4279 Notification.EXTRA_BUILDER_APPLICATION_INFO);
4280 final Bundle extras = new Bundle();
4281 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004282 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04004283 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004284 new Notification.Builder(getContext(), channelId)
4285 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04004286 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04004287 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04004288 .setGroup(GroupHelper.AUTOGROUP_KEY)
Mady Mellor49b1bf12019-03-29 12:00:02 -07004289 .setFlag(FLAG_AUTOGROUP_SUMMARY, true)
Julia Reynolds8f488d32016-10-14 10:59:01 -04004290 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
4291 .setColor(adjustedSbn.getNotification().color)
4292 .setLocalOnly(true)
4293 .build();
4294 summaryNotification.extras.putAll(extras);
4295 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
4296 if (appIntent != null) {
4297 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
4298 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
4299 }
4300 final StatusBarNotification summarySbn =
4301 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004302 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004303 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04004304 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
4305 adjustedSbn.getInitialPid(), summaryNotification,
4306 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
4307 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05004308 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004309 notificationRecord.getChannel());
Rohan Shah590e1b22018-04-10 23:48:47 -04004310 summaryRecord.setIsAppImportanceLocked(
4311 notificationRecord.getIsAppImportanceLocked());
Julia Reynolds8f488d32016-10-14 10:59:01 -04004312 summaries.put(pkg, summarySbn.getKey());
4313 }
4314 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004315 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04004316 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04004317 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04004318 }
4319 }
4320
John Spurlock32fe4c62014-10-02 12:16:02 -04004321 private String disableNotificationEffects(NotificationRecord record) {
4322 if (mDisableNotificationEffects) {
4323 return "booleanState";
4324 }
4325 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
4326 return "listenerHints";
4327 }
Julia Reynoldsdb7081e2019-01-03 14:35:38 -05004328 if (record != null && record.getAudioAttributes() != null) {
4329 if ((mListenerHints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
4330 if (record.getAudioAttributes().getUsage()
4331 != AudioAttributes.USAGE_VOICE_COMMUNICATION) {
4332 return "listenerNoti";
4333 }
4334 }
4335 if ((mListenerHints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
4336 if (record.getAudioAttributes().getUsage()
4337 == AudioAttributes.USAGE_VOICE_COMMUNICATION) {
4338 return "listenerCall";
4339 }
4340 }
4341 }
John Spurlock32fe4c62014-10-02 12:16:02 -04004342 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
4343 return "callState";
4344 }
4345 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04004346 };
4347
Kweku Adams887f09c2017-11-13 17:12:20 -08004348 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
Chris Wrene4b38802015-07-07 15:54:19 -04004349 JSONObject dump = new JSONObject();
4350 try {
4351 dump.put("service", "Notification Manager");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004352 dump.put("bans", mPreferencesHelper.dumpBansJson(filter));
4353 dump.put("ranking", mPreferencesHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04004354 dump.put("stats", mUsageStats.dumpJson(filter));
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004355 dump.put("channels", mPreferencesHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04004356 } catch (JSONException e) {
4357 e.printStackTrace();
4358 }
4359 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04004360 }
4361
Kweku Adams887f09c2017-11-13 17:12:20 -08004362 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004363 final ProtoOutputStream proto = new ProtoOutputStream(fd);
4364 synchronized (mNotificationLock) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004365 int N = mNotificationList.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08004366 for (int i = 0; i < N; i++) {
4367 final NotificationRecord nr = mNotificationList.get(i);
4368 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4369 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
4370 NotificationRecordProto.POSTED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004371 }
4372 N = mEnqueuedNotifications.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08004373 for (int i = 0; i < N; i++) {
4374 final NotificationRecord nr = mEnqueuedNotifications.get(i);
4375 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4376 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
4377 NotificationRecordProto.ENQUEUED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004378 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004379 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
4380 N = snoozed.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08004381 for (int i = 0; i < N; i++) {
4382 final NotificationRecord nr = snoozed.get(i);
4383 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4384 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
4385 NotificationRecordProto.SNOOZED);
Julia Reynolds520df6e2017-02-13 09:05:10 -05004386 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004387
Kweku Adams93304b62017-09-20 17:03:00 -07004388 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
4389 mZenModeHelper.dump(proto);
4390 for (ComponentName suppressor : mEffectsSuppressors) {
Kweku Adams99546332018-01-24 17:03:50 -08004391 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
Kweku Adams93304b62017-09-20 17:03:00 -07004392 }
4393 proto.end(zenLog);
4394
4395 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
4396 mListeners.dump(proto, filter);
4397 proto.end(listenersToken);
4398
4399 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
4400
4401 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
4402 long effectsToken = proto.start(
4403 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
4404
4405 proto.write(
4406 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
Julia Reynolds4703bac2018-09-12 10:39:30 -04004407 final ArraySet<ComponentName> listeners =
Kweku Adams93304b62017-09-20 17:03:00 -07004408 mListenersDisablingEffects.valueAt(i);
4409 for (int j = 0; j < listeners.size(); j++) {
Kweku Adamsf2169532018-12-20 04:15:49 -08004410 final ComponentName componentName = listeners.valueAt(j);
Julia Reynolds4703bac2018-09-12 10:39:30 -04004411 componentName.writeToProto(proto,
4412 ListenersDisablingEffectsProto.LISTENER_COMPONENTS);
Kweku Adams93304b62017-09-20 17:03:00 -07004413 }
4414
4415 proto.end(effectsToken);
4416 }
4417
4418 long assistantsToken = proto.start(
4419 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
4420 mAssistants.dump(proto, filter);
4421 proto.end(assistantsToken);
4422
4423 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
4424 mConditionProviders.dump(proto, filter);
4425 proto.end(conditionsToken);
Kweku Adams62b42242017-09-25 12:54:02 -07004426
4427 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
4428 mRankingHelper.dump(proto, filter);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004429 mPreferencesHelper.dump(proto, filter);
Kweku Adams62b42242017-09-25 12:54:02 -07004430 proto.end(rankingToken);
Julia Reynolds520df6e2017-02-13 09:05:10 -05004431 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004432
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004433 proto.flush();
4434 }
4435
Vishnu Naire3e4d252018-03-01 11:26:57 -08004436 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
4437 synchronized (mNotificationLock) {
4438 int N;
4439 N = mNotificationList.size();
4440 if (N > 0) {
4441 pw.println(" Notification List:");
4442 for (int i = 0; i < N; i++) {
4443 final NotificationRecord nr = mNotificationList.get(i);
4444 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4445 nr.dump(pw, " ", getContext(), filter.redact);
4446 }
4447 pw.println(" ");
4448 }
4449 }
4450 }
4451
Kweku Adams887f09c2017-11-13 17:12:20 -08004452 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
John Spurlock25e2d242014-06-27 13:58:23 -04004453 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04004454 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04004455 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04004456 }
4457 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08004458 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04004459 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08004460
John Spurlock50806fc2014-07-15 10:22:02 -04004461 if (!zenOnly) {
4462 synchronized (mToastQueue) {
4463 N = mToastQueue.size();
4464 if (N > 0) {
4465 pw.println(" Toast Queue:");
4466 for (int i=0; i<N; i++) {
4467 mToastQueue.get(i).dump(pw, " ", filter);
4468 }
4469 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08004470 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004471 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004472 }
4473
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004474 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04004475 if (!zenOnly) {
Vishnu Naire3e4d252018-03-01 11:26:57 -08004476 // Priority filters are only set when called via bugreport. If set
4477 // skip sections that are part of the critical section.
4478 if (!filter.normalPriority) {
4479 dumpNotificationRecords(pw, filter);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004480 }
Julia Reynoldse6b53e62015-07-31 09:25:10 -04004481 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04004482 N = mLights.size();
4483 if (N > 0) {
4484 pw.println(" Lights List:");
4485 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05004486 if (i == N - 1) {
4487 pw.print(" > ");
4488 } else {
4489 pw.print(" ");
4490 }
4491 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04004492 }
4493 pw.println(" ");
4494 }
John Spurlockcb566aa2014-08-03 22:58:28 -04004495 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
Julia Reynolds28149f62018-07-03 10:43:35 -04004496 pw.println(" mHasLight=" + mHasLight);
John Spurlockcb566aa2014-08-03 22:58:28 -04004497 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05004498 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
4499 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04004500 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04004501 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04004502 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04004503 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04004504 }
4505 pw.println(" mArchive=" + mArchive.toString());
4506 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004507 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04004508 while (iter.hasNext()) {
4509 final StatusBarNotification sbn = iter.next();
4510 if (filter != null && !filter.matches(sbn)) continue;
4511 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004512 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04004513 if (iter.hasNext()) pw.println(" ...");
4514 break;
4515 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004516 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004517
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004518 if (!zenOnly) {
4519 N = mEnqueuedNotifications.size();
4520 if (N > 0) {
4521 pw.println(" Enqueued Notification List:");
4522 for (int i = 0; i < N; i++) {
4523 final NotificationRecord nr = mEnqueuedNotifications.get(i);
4524 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4525 nr.dump(pw, " ", getContext(), filter.redact);
4526 }
4527 pw.println(" ");
4528 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004529
4530 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004531 }
4532 }
4533
John Spurlock50806fc2014-07-15 10:22:02 -04004534 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04004535 pw.println("\n Ranking Config:");
4536 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04004537
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004538 pw.println("\n Notification Preferences:");
4539 mPreferencesHelper.dump(pw, " ", filter);
4540
John Spurlock50806fc2014-07-15 10:22:02 -04004541 pw.println("\n Notification listeners:");
4542 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04004543 pw.print(" mListenerHints: "); pw.println(mListenerHints);
4544 pw.print(" mListenersDisablingEffects: (");
4545 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04004546 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07004547 final int hint = mListenersDisablingEffects.keyAt(i);
4548 if (i > 0) pw.print(';');
4549 pw.print("hint[" + hint + "]:");
4550
Julia Reynolds4703bac2018-09-12 10:39:30 -04004551 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07004552 final int listenerSize = listeners.size();
4553
4554 for (int j = 0; j < listenerSize; j++) {
Kweku Adamsf2169532018-12-20 04:15:49 -08004555 if (j > 0) pw.print(',');
4556 final ComponentName listener = listeners.valueAt(j);
Julia Reynolds1f580572018-04-27 14:48:36 -04004557 if (listener != null) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04004558 pw.print(listener);
Julia Reynolds1f580572018-04-27 14:48:36 -04004559 }
Bryce Lee7219ada2016-04-08 10:54:23 -07004560 }
John Spurlock1fa865f2014-07-21 14:56:39 -04004561 }
4562 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05004563 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004564 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04004565 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004566
Julia Reynolds520df6e2017-02-13 09:05:10 -05004567 if (!filter.filtered || zenOnly) {
4568 pw.println("\n Zen Mode:");
4569 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
4570 mZenModeHelper.dump(pw, " ");
4571
4572 pw.println("\n Zen Log:");
4573 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004574 }
4575
John Spurlocke77bb362014-04-26 10:24:59 -04004576 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04004577 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02004578
4579 pw.println("\n Group summaries:");
4580 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
4581 NotificationRecord r = entry.getValue();
4582 pw.println(" " + entry.getKey() + " -> " + r.getKey());
4583 if (mNotificationsByKey.get(r.getKey()) != r) {
4584 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04004585 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02004586 }
4587 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004588
4589 if (!zenOnly) {
4590 pw.println("\n Usage Stats:");
4591 mUsageStats.dump(pw, " ", filter);
4592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004593 }
4594 }
4595
Adam Lesinski182f73f2013-12-05 16:48:06 -08004596 /**
4597 * The private API only accessible to the system process.
4598 */
4599 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
4600 @Override
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04004601 public NotificationChannel getNotificationChannel(String pkg, int uid, String
4602 channelId) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004603 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false);
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04004604 }
4605
4606 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004607 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004608 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004609 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004610 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004611 }
Christoph Studer365e4c32014-09-18 20:35:36 +02004612
4613 @Override
4614 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
4615 int userId) {
4616 checkCallerIsSystem();
Julia Reynolds564273f2018-09-13 15:53:11 -04004617 mHandler.post(() -> {
4618 synchronized (mNotificationLock) {
4619 // strip flag from all enqueued notifications. listeners will be informed
4620 // in post runnable.
4621 List<NotificationRecord> enqueued = findNotificationsByListLocked(
4622 mEnqueuedNotifications, pkg, null, notificationId, userId);
4623 for (int i = 0; i < enqueued.size(); i++) {
4624 removeForegroundServiceFlagLocked(enqueued.get(i));
4625 }
4626
4627 // if posted notification exists, strip its flag and tell listeners
4628 NotificationRecord r = findNotificationByListLocked(
4629 mNotificationList, pkg, null, notificationId, userId);
4630 if (r != null) {
4631 removeForegroundServiceFlagLocked(r);
4632 mRankingHelper.sort(mNotificationList);
4633 mListeners.notifyPostedLocked(r, r);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004634 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004635 }
4636 });
4637 }
4638
Julia Reynolds88860ce2017-06-01 16:55:49 -04004639 @GuardedBy("mNotificationLock")
Julia Reynolds564273f2018-09-13 15:53:11 -04004640 private void removeForegroundServiceFlagLocked(NotificationRecord r) {
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004641 if (r == null) {
4642 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02004643 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004644 StatusBarNotification sbn = r.sbn;
4645 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
4646 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
4647 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
4648 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
4649 sbn.getNotification().flags =
Julia Reynoldse5c60452018-04-30 14:41:36 -04004650 (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
Christoph Studer365e4c32014-09-18 20:35:36 +02004651 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004652 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004653
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004654 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04004655 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004656 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04004657 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08004658 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
4659 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04004660 }
Dianne Hackborn41203752012-08-31 14:05:51 -07004661
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004662 if (pkg == null || notification == null) {
4663 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
4664 + " id=" + id + " notification=" + notification);
4665 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004666
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004667 final int userId = ActivityManager.handleIncomingUser(callingPid,
4668 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
4669 final UserHandle user = UserHandle.of(userId);
4670
4671 // Can throw a SecurityException if the calling uid doesn't have permission to post
4672 // as "pkg"
4673 final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
4674
4675 checkRestrictedCategories(notification);
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004676
Julia Reynoldse46bb372016-03-17 11:05:58 -04004677 // Fix the notification as best we can.
4678 try {
Julia Reynolds47fd15f2018-11-28 10:16:00 -05004679 fixNotification(notification, pkg, userId);
Julia Reynolds4db59552017-06-30 13:34:01 -04004680
Julia Reynoldse46bb372016-03-17 11:05:58 -04004681 } catch (NameNotFoundException e) {
4682 Slog.e(TAG, "Cannot create a context for sending app", e);
4683 return;
4684 }
4685
Chris Wren888b7a82016-06-17 15:47:19 -04004686 mUsageStats.registerEnqueuedByApp(pkg);
4687
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004688 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04004689 String channelId = notification.getChannelId();
4690 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
4691 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05004692 }
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004693 final NotificationChannel channel = mPreferencesHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004694 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004695 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004696 final String noChannelStr = "No Channel found for "
4697 + "pkg=" + pkg
4698 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04004699 + ", id=" + id
4700 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004701 + ", opPkg=" + opPkg
4702 + ", callingUid=" + callingUid
4703 + ", userId=" + userId
4704 + ", incomingUserId=" + incomingUserId
4705 + ", notificationUid=" + notificationUid
4706 + ", notification=" + notification;
Tony Mak180a9c42019-03-08 13:33:08 +00004707 Slog.e(TAG, noChannelStr);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004708 boolean appNotificationsOff = mPreferencesHelper.getImportance(pkg, notificationUid)
Beverly5d4564b2018-04-10 20:09:23 -04004709 == NotificationManager.IMPORTANCE_NONE;
4710
4711 if (!appNotificationsOff) {
4712 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
4713 "Failed to post notification on channel \"" + channelId + "\"\n" +
4714 "See log for more details");
4715 }
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004716 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004717 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004718
Chris Wrena61f1792016-08-04 11:24:42 -04004719 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004720 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004721 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004722 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004723 r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
Chris Wrena61f1792016-08-04 11:24:42 -04004724
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004725 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4726 final boolean fgServiceShown = channel.isFgServiceShown();
4727 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
4728 || !fgServiceShown)
4729 && (r.getImportance() == IMPORTANCE_MIN
4730 || r.getImportance() == IMPORTANCE_NONE)) {
4731 // Increase the importance of foreground service notifications unless the user had
4732 // an opinion otherwise (and the channel hasn't yet shown a fg service).
4733 if (TextUtils.isEmpty(channelId)
4734 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004735 r.setSystemImportance(IMPORTANCE_LOW);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004736 } else {
4737 channel.setImportance(IMPORTANCE_LOW);
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004738 r.setSystemImportance(IMPORTANCE_LOW);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004739 if (!fgServiceShown) {
4740 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
4741 channel.setFgServiceShown(true);
4742 }
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004743 mPreferencesHelper.updateNotificationChannel(
4744 pkg, notificationUid, channel, false);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004745 r.updateNotificationChannel(channel);
4746 }
4747 } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
4748 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4749 channel.setFgServiceShown(true);
Julia Reynolds8617e4e2017-09-18 16:52:37 -04004750 r.updateNotificationChannel(channel);
4751 }
4752 }
4753
Julia Reynolds5e702192017-08-18 09:22:40 -04004754 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
4755 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004756 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07004757 }
4758
Felipe Lemedd85da62016-06-28 11:29:54 -07004759 // Whitelist pending intents.
4760 if (notification.allPendingIntents != null) {
4761 final int intentCount = notification.allPendingIntents.size();
4762 if (intentCount > 0) {
4763 final ActivityManagerInternal am = LocalServices
4764 .getService(ActivityManagerInternal.class);
4765 final long duration = LocalServices.getService(
4766 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
4767 for (int i = 0; i < intentCount; i++) {
4768 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4769 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07004770 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4771 WHITELIST_TOKEN, duration);
Michal Karpinskiac116df2018-12-10 17:51:42 +00004772 am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
Michal Karpinskic8aa91b2019-01-10 16:45:59 +00004773 WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
4774 | FLAG_SERVICE_SENDER));
Felipe Lemedd85da62016-06-28 11:29:54 -07004775 }
4776 }
4777 }
4778 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07004779
Chris Wren47633422016-01-22 09:56:59 -05004780 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004781 }
4782
Julia Reynolds47fd15f2018-11-28 10:16:00 -05004783 @VisibleForTesting
4784 protected void fixNotification(Notification notification, String pkg, int userId)
4785 throws NameNotFoundException {
4786 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
4787 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
4788 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
4789 Notification.addFieldsFromContext(ai, notification);
4790
4791 int canColorize = mPackageManagerClient.checkPermission(
4792 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
4793 if (canColorize == PERMISSION_GRANTED) {
4794 notification.flags |= Notification.FLAG_CAN_COLORIZE;
4795 } else {
4796 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
4797 }
4798
Takamasa Kuramitsu3dd7b2d2018-12-14 20:46:02 +09004799 if (notification.fullScreenIntent != null && ai.targetSdkVersion >= Build.VERSION_CODES.Q) {
Julia Reynolds47fd15f2018-11-28 10:16:00 -05004800 int fullscreenIntentPermission = mPackageManagerClient.checkPermission(
4801 android.Manifest.permission.USE_FULL_SCREEN_INTENT, pkg);
4802 if (fullscreenIntentPermission != PERMISSION_GRANTED) {
4803 notification.fullScreenIntent = null;
Tony Mak180a9c42019-03-08 13:33:08 +00004804 Slog.w(TAG, "Package " + pkg +
Julia Reynolds47fd15f2018-11-28 10:16:00 -05004805 ": Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission");
4806 }
4807 }
4808 }
4809
Mady Mellor7eb18ef2019-03-27 14:03:46 -07004810 /**
4811 * Updates the flags for this notification to reflect whether it is a bubble or not.
4812 */
Mady Mellorbe797962019-04-01 16:04:24 -07004813 private void flagNotificationForBubbles(NotificationRecord r, String pkg, int userId,
4814 NotificationRecord oldRecord) {
Mady Mellor7eb18ef2019-03-27 14:03:46 -07004815 Notification notification = r.getNotification();
Mady Mellora54e9fa2019-04-18 13:26:18 -07004816 if (isNotificationAppropriateToBubble(r, pkg, userId, oldRecord)) {
4817 notification.flags |= FLAG_BUBBLE;
4818 } else {
4819 notification.flags &= ~FLAG_BUBBLE;
4820 }
4821 }
4822
4823 /**
4824 * @return whether the provided notification record is allowed to be represented as a bubble.
4825 */
4826 private boolean isNotificationAppropriateToBubble(NotificationRecord r, String pkg, int userId,
4827 NotificationRecord oldRecord) {
4828 Notification notification = r.getNotification();
Mady Mellorca0c24c2019-05-16 16:14:32 -07004829 Notification.BubbleMetadata metadata = notification.getBubbleMetadata();
4830 boolean intentCanBubble = metadata != null
4831 && canLaunchInActivityView(getContext(), metadata.getIntent(), pkg);
Mady Mellorbe797962019-04-01 16:04:24 -07004832
Mady Mellor5c11a2e2019-04-25 17:26:15 -07004833 // Does the app want to bubble & is able to bubble
Mady Mellorca0c24c2019-05-16 16:14:32 -07004834 boolean canBubble = intentCanBubble
Mady Mellorbe797962019-04-01 16:04:24 -07004835 && mPreferencesHelper.areBubblesAllowed(pkg, userId)
Mady Mellorc6820342019-05-20 12:04:36 -07004836 && mPreferencesHelper.bubblesEnabled(r.sbn.getUser())
Mady Mellor5c11a2e2019-04-25 17:26:15 -07004837 && r.getChannel().canBubble()
4838 && !mActivityManager.isLowRamDevice();
Mady Mellorbe797962019-04-01 16:04:24 -07004839
4840 // Is the app in the foreground?
4841 final boolean appIsForeground =
4842 mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
4843
4844 // Is the notification something we'd allow to bubble?
4845 // A call with a foreground service + person
4846 ArrayList<Person> peopleList = notification.extras != null
4847 ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)
4848 : null;
4849 boolean isForegroundCall = CATEGORY_CALL.equals(notification.category)
4850 && (notification.flags & FLAG_FOREGROUND_SERVICE) != 0;
Mady Mellora10448e2019-04-26 13:50:58 -07004851 // OR message style (which always has a person) with any remote input
Mady Mellorbe797962019-04-01 16:04:24 -07004852 Class<? extends Notification.Style> style = notification.getNotificationStyle();
4853 boolean isMessageStyle = Notification.MessagingStyle.class.equals(style);
Mady Mellora10448e2019-04-26 13:50:58 -07004854 boolean notificationAppropriateToBubble =
4855 (isMessageStyle && hasValidRemoteInput(notification))
Mady Mellorbe797962019-04-01 16:04:24 -07004856 || (peopleList != null && !peopleList.isEmpty() && isForegroundCall);
Mady Mellora10448e2019-04-26 13:50:58 -07004857
Mady Mellorbe797962019-04-01 16:04:24 -07004858 // OR something that was previously a bubble & still exists
4859 boolean bubbleUpdate = oldRecord != null
4860 && (oldRecord.getNotification().flags & FLAG_BUBBLE) != 0;
Mady Mellora54e9fa2019-04-18 13:26:18 -07004861 return canBubble && (notificationAppropriateToBubble || appIsForeground || bubbleUpdate);
Mady Mellor7eb18ef2019-03-27 14:03:46 -07004862 }
4863
Mady Mellora10448e2019-04-26 13:50:58 -07004864 private boolean hasValidRemoteInput(Notification n) {
4865 // Also check for inline reply
4866 Notification.Action[] actions = n.actions;
4867 if (actions != null) {
4868 // Get the remote inputs
4869 for (int i = 0; i < actions.length; i++) {
4870 Notification.Action action = actions[i];
4871 RemoteInput[] inputs = action.getRemoteInputs();
4872 if (inputs != null && inputs.length > 0) {
4873 return true;
4874 }
4875 }
4876 }
4877 return false;
4878 }
4879
Mady Mellorca0c24c2019-05-16 16:14:32 -07004880 /**
4881 * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
4882 *
4883 * @param context the context to use.
4884 * @param pendingIntent the pending intent of the bubble.
4885 * @param packageName the notification package name for this bubble.
4886 */
4887 // Keep checks in sync with BubbleController#canLaunchInActivityView.
4888 @VisibleForTesting
4889 protected boolean canLaunchInActivityView(Context context, PendingIntent pendingIntent,
4890 String packageName) {
4891 if (pendingIntent == null) {
4892 Log.w(TAG, "Unable to create bubble -- no intent");
4893 return false;
4894 }
4895
4896 // Need escalated privileges to get the intent.
4897 final long token = Binder.clearCallingIdentity();
4898 Intent intent;
4899 try {
4900 intent = pendingIntent.getIntent();
4901 } finally {
4902 Binder.restoreCallingIdentity(token);
4903 }
4904
4905 ActivityInfo info = intent != null
4906 ? intent.resolveActivityInfo(context.getPackageManager(), 0)
4907 : null;
4908 if (info == null) {
4909 StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
4910 BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING);
4911 Log.w(TAG, "Unable to send as bubble -- couldn't find activity info for intent: "
4912 + intent);
4913 return false;
4914 }
4915 if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
4916 StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
4917 BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE);
4918 Log.w(TAG, "Unable to send as bubble -- activity is not resizable for intent: "
4919 + intent);
4920 return false;
4921 }
4922 if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
4923 StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
4924 BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS);
4925 Log.w(TAG, "Unable to send as bubble -- activity is not documentLaunchMode=always "
4926 + "for intent: " + intent);
4927 return false;
4928 }
4929 if ((info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
4930 Log.w(TAG, "Unable to send as bubble -- activity is not embeddable for intent: "
4931 + intent);
4932 return false;
4933 }
4934 return true;
4935 }
4936
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04004937 private void doChannelWarningToast(CharSequence toastText) {
Julia Reynoldsbba26b12018-10-11 09:21:11 -04004938 Binder.withCleanCallingIdentity(() -> {
4939 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
4940 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
4941 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4942 if (warningEnabled) {
4943 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
4944 Toast.LENGTH_SHORT);
4945 toast.show();
4946 }
4947 });
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004948 }
4949
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004950 @VisibleForTesting
4951 int resolveNotificationUid(String callingPkg, String targetPkg,
4952 int callingUid, int userId) {
Julia Reynoldsb6634872018-09-25 13:19:53 -04004953 if (userId == UserHandle.USER_ALL) {
4954 userId = USER_SYSTEM;
4955 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004956 // posted from app A on behalf of app A
Julia Reynoldsb6634872018-09-25 13:19:53 -04004957 if (isCallerSameApp(targetPkg, callingUid, userId)
Julia Reynoldsecc1b572018-10-01 16:19:24 -04004958 && (TextUtils.equals(callingPkg, targetPkg)
4959 || isCallerSameApp(callingPkg, callingUid, userId))) {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004960 return callingUid;
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004961 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004962
4963 int targetUid = -1;
4964 try {
4965 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
4966 } catch (NameNotFoundException e) {
4967 /* ignore */
4968 }
4969 // posted from app A on behalf of app B
4970 if (targetUid != -1 && (isCallerAndroid(callingPkg, callingUid)
4971 || mPreferencesHelper.isDelegateAllowed(
4972 targetPkg, targetUid, callingPkg, callingUid))) {
4973 return targetUid;
4974 }
4975
Julia Reynoldsecc1b572018-10-01 16:19:24 -04004976 throw new SecurityException("Caller " + callingPkg + ":" + callingUid
4977 + " cannot post for pkg " + targetPkg + " in user " + userId);
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004978 }
4979
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004980 /**
4981 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4982 *
4983 * Has side effects.
4984 */
Julia Reynolds268647a2018-10-25 16:54:27 -04004985 private boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04004986 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004987 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004988 final boolean isSystemNotification =
Julia Reynolds268647a2018-10-25 16:54:27 -04004989 isUidSystemOrPhone(uid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004990 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
4991
4992 // Limit the number of notifications that any given package except the android
4993 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
4994 if (!isSystemNotification && !isNotificationFromListener) {
4995 synchronized (mNotificationLock) {
Julia Reynolds268647a2018-10-25 16:54:27 -04004996 final int callingUid = Binder.getCallingUid();
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004997 if (mNotificationsByKey.get(r.sbn.getKey()) == null
Julia Reynolds268647a2018-10-25 16:54:27 -04004998 && isCallerInstantApp(callingUid, userId)) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004999 // Ephemeral apps have some special constraints for notifications.
5000 // They are not allowed to create new notifications however they are allowed to
5001 // update notifications created by the system (e.g. a foreground service
5002 // notification).
5003 throw new SecurityException("Instant app " + pkg
5004 + " cannot create notifications");
5005 }
5006
5007 // rate limit updates that aren't completed progress notifications
5008 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04005009 && !r.getNotification().hasCompletedProgress()
5010 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04005011
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005012 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
5013 if (appEnqueueRate > mMaxPackageEnqueueRate) {
5014 mUsageStats.registerOverRateQuota(pkg);
5015 final long now = SystemClock.elapsedRealtime();
5016 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
5017 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04005018 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005019 mLastOverRateLogTime = now;
5020 }
5021 return false;
5022 }
5023 }
5024
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04005025 // limit the number of outstanding notificationrecords an app can have
5026 int count = getNotificationCountLocked(pkg, userId, id, tag);
5027 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
5028 mUsageStats.registerOverCountQuota(pkg);
5029 Slog.e(TAG, "Package has already posted or enqueued " + count
5030 + " notifications. Not showing more. package=" + pkg);
5031 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005032 }
5033 }
5034 }
5035
5036 // snoozed apps
5037 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05005038 MetricsLogger.action(r.getLogMaker()
5039 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
5040 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005041 if (DBG) {
5042 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
5043 }
5044 mSnoozeHelper.update(userId, r);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05005045 handleSavePolicyFile();
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005046 return false;
5047 }
5048
5049
5050 // blocked apps
5051 if (isBlocked(r, mUsageStats)) {
5052 return false;
5053 }
5054
5055 return true;
5056 }
5057
Andreas Gampea36dc622018-02-05 17:19:22 -08005058 @GuardedBy("mNotificationLock")
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04005059 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
5060 String excludedTag) {
5061 int count = 0;
5062 final int N = mNotificationList.size();
5063 for (int i = 0; i < N; i++) {
5064 final NotificationRecord existing = mNotificationList.get(i);
5065 if (existing.sbn.getPackageName().equals(pkg)
5066 && existing.sbn.getUserId() == userId) {
5067 if (existing.sbn.getId() == excludedId
5068 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
5069 continue;
5070 }
5071 count++;
5072 }
5073 }
5074 final int M = mEnqueuedNotifications.size();
5075 for (int i = 0; i < M; i++) {
5076 final NotificationRecord existing = mEnqueuedNotifications.get(i);
5077 if (existing.sbn.getPackageName().equals(pkg)
5078 && existing.sbn.getUserId() == userId) {
5079 count++;
5080 }
5081 }
5082 return count;
5083 }
5084
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005085 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
Beverly3c707b42018-09-14 09:49:07 -04005086 if (isBlocked(r)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005087 Slog.e(TAG, "Suppressing notification from package by user request.");
5088 usageStats.registerBlocked(r);
Beverly3c707b42018-09-14 09:49:07 -04005089 return true;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005090 }
Beverly3c707b42018-09-14 09:49:07 -04005091 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005092 }
5093
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005094 private boolean isBlocked(NotificationRecord r) {
5095 final String pkg = r.sbn.getPackageName();
5096 final int callingUid = r.sbn.getUid();
5097 return mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
5098 || mPreferencesHelper.getImportance(pkg, callingUid)
5099 == NotificationManager.IMPORTANCE_NONE
5100 || r.getImportance() == NotificationManager.IMPORTANCE_NONE;
5101 }
5102
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005103 protected class SnoozeNotificationRunnable implements Runnable {
5104 private final String mKey;
5105 private final long mDuration;
5106 private final String mSnoozeCriterionId;
5107
5108 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
5109 mKey = key;
5110 mDuration = duration;
5111 mSnoozeCriterionId = snoozeCriterionId;
5112 }
5113
5114 @Override
5115 public void run() {
5116 synchronized (mNotificationLock) {
5117 final NotificationRecord r = findNotificationByKeyLocked(mKey);
5118 if (r != null) {
5119 snoozeLocked(r);
5120 }
5121 }
5122 }
5123
Julia Reynolds88860ce2017-06-01 16:55:49 -04005124 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005125 void snoozeLocked(NotificationRecord r) {
5126 if (r.sbn.isGroup()) {
5127 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
5128 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
5129 if (r.getNotification().isGroupSummary()) {
5130 // snooze summary and all children
5131 for (int i = 0; i < groupNotifications.size(); i++) {
5132 snoozeNotificationLocked(groupNotifications.get(i));
5133 }
5134 } else {
5135 // if there is a valid summary for this group, and we are snoozing the only
5136 // child, also snooze the summary
5137 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
5138 if (groupNotifications.size() != 2) {
5139 snoozeNotificationLocked(r);
5140 } else {
5141 // snooze summary and the one child
5142 for (int i = 0; i < groupNotifications.size(); i++) {
5143 snoozeNotificationLocked(groupNotifications.get(i));
5144 }
5145 }
5146 } else {
5147 snoozeNotificationLocked(r);
5148 }
5149 }
5150 } else {
5151 // just snooze the one notification
5152 snoozeNotificationLocked(r);
5153 }
5154 }
5155
Julia Reynolds88860ce2017-06-01 16:55:49 -04005156 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005157 void snoozeNotificationLocked(NotificationRecord r) {
5158 MetricsLogger.action(r.getLogMaker()
5159 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
5160 .setType(MetricsEvent.TYPE_CLOSE)
Chris Wren21a2e722017-10-02 17:44:53 -04005161 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
5162 mDuration)
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005163 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
5164 mSnoozeCriterionId == null ? 0 : 1));
Esteban Talavera5d603892018-11-15 10:55:24 +00005165 reportUserInteraction(r);
Julia Reynolds0839c022017-06-15 15:24:01 -04005166 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04005167 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005168 updateLightsLocked();
5169 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04005170 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005171 mSnoozeHelper.snooze(r);
5172 } else {
5173 mSnoozeHelper.snooze(r, mDuration);
5174 }
Julia Reynolds503ed942017-10-04 16:04:56 -04005175 r.recordSnoozed();
Julia Reynoldsb62dad42018-11-26 16:33:02 -05005176 handleSavePolicyFile();
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005177 }
5178 }
5179
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005180 protected class CancelNotificationRunnable implements Runnable {
5181 private final int mCallingUid;
5182 private final int mCallingPid;
5183 private final String mPkg;
5184 private final String mTag;
5185 private final int mId;
5186 private final int mMustHaveFlags;
5187 private final int mMustNotHaveFlags;
5188 private final boolean mSendDelete;
5189 private final int mUserId;
5190 private final int mReason;
5191 private final int mRank;
5192 private final int mCount;
5193 private final ManagedServiceInfo mListener;
5194
5195 CancelNotificationRunnable(final int callingUid, final int callingPid,
5196 final String pkg, final String tag, final int id,
5197 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
5198 final int userId, final int reason, int rank, int count,
5199 final ManagedServiceInfo listener) {
5200 this.mCallingUid = callingUid;
5201 this.mCallingPid = callingPid;
5202 this.mPkg = pkg;
5203 this.mTag = tag;
5204 this.mId = id;
5205 this.mMustHaveFlags = mustHaveFlags;
5206 this.mMustNotHaveFlags = mustNotHaveFlags;
5207 this.mSendDelete = sendDelete;
5208 this.mUserId = userId;
5209 this.mReason = reason;
5210 this.mRank = rank;
5211 this.mCount = count;
5212 this.mListener = listener;
5213 }
5214
5215 @Override
5216 public void run() {
5217 String listenerName = mListener == null ? null : mListener.component.toShortString();
5218 if (DBG) {
5219 EventLogTags.writeNotificationCancel(mCallingUid, mCallingPid, mPkg, mId, mTag,
5220 mUserId, mMustHaveFlags, mMustNotHaveFlags, mReason, listenerName);
5221 }
5222
5223 synchronized (mNotificationLock) {
5224 // Look for the notification, searching both the posted and enqueued lists.
5225 NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId);
5226 if (r != null) {
5227 // The notification was found, check if it should be removed.
5228
5229 // Ideally we'd do this in the caller of this method. However, that would
5230 // require the caller to also find the notification.
5231 if (mReason == REASON_CLICK) {
5232 mUsageStats.registerClickedByUser(r);
5233 }
5234
5235 if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) {
5236 return;
5237 }
5238 if ((r.getNotification().flags & mMustNotHaveFlags) != 0) {
5239 return;
5240 }
5241
5242 // Cancel the notification.
5243 boolean wasPosted = removeFromNotificationListsLocked(r);
5244 cancelNotificationLocked(
5245 r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName);
5246 cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
5247 mSendDelete, null);
5248 updateLightsLocked();
5249 } else {
5250 // No notification was found, assume that it is snoozed and cancel it.
5251 if (mReason != REASON_SNOOZED) {
5252 final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId);
5253 if (wasSnoozed) {
Julia Reynoldsb62dad42018-11-26 16:33:02 -05005254 handleSavePolicyFile();
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005255 }
5256 }
5257 }
5258 }
5259 }
5260 }
5261
Julia Reynoldsbaff4002016-12-15 11:34:26 -05005262 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05005263 private final NotificationRecord r;
5264 private final int userId;
5265
5266 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
5267 this.userId = userId;
5268 this.r = r;
5269 };
5270
5271 @Override
5272 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005273 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05005274 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05005275 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05005276
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005277 final StatusBarNotification n = r.sbn;
5278 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
5279 NotificationRecord old = mNotificationsByKey.get(n.getKey());
5280 if (old != null) {
5281 // Retain ranking information from previous record
5282 r.copyRankingInformation(old);
5283 }
5284
5285 final int callingUid = n.getUid();
5286 final int callingPid = n.getInitialPid();
5287 final Notification notification = n.getNotification();
5288 final String pkg = n.getPackageName();
5289 final int id = n.getId();
5290 final String tag = n.getTag();
5291
Mady Mellor7eb18ef2019-03-27 14:03:46 -07005292 // We need to fix the notification up a little for bubbles
Mady Mellorbe797962019-04-01 16:04:24 -07005293 flagNotificationForBubbles(r, pkg, callingUid, old);
Mady Mellor7eb18ef2019-03-27 14:03:46 -07005294
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005295 // Handle grouped notifications and bail out early if we
5296 // can to avoid extracting signals.
5297 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
5298
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005299 // if this is a group child, unsnooze parent summary
5300 if (n.isGroup() && notification.isGroupChild()) {
5301 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
5302 }
5303
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005304 // This conditional is a dirty hack to limit the logging done on
5305 // behalf of the download manager without affecting other apps.
5306 if (!pkg.equals("com.android.providers.downloads")
5307 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
5308 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05005309 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005310 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05005311 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005312 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
5313 pkg, id, tag, userId, notification.toString(),
5314 enqueueStatus);
5315 }
Chris Wren6676dab2016-12-21 18:26:27 -05005316
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005317 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04005318 if (mAssistants.isEnabled()) {
Tony Makeda84a72018-11-19 17:01:32 +00005319 mAssistants.onNotificationEnqueuedLocked(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005320 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005321 DELAY_FOR_ASSISTANT_TIME);
5322 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005323 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005324 }
5325 }
5326 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005327 }
5328
Beverly5a20a5e2018-03-06 15:02:44 -05005329 @GuardedBy("mNotificationLock")
5330 private boolean isPackageSuspendedLocked(NotificationRecord r) {
5331 final String pkg = r.sbn.getPackageName();
5332 final int callingUid = r.sbn.getUid();
5333
5334 return isPackageSuspendedForUser(pkg, callingUid);
5335 }
5336
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005337 protected class PostNotificationRunnable implements Runnable {
5338 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005339
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005340 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005341 this.key = key;
5342 }
5343
5344 @Override
5345 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005346 synchronized (mNotificationLock) {
5347 try {
5348 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005349 int N = mEnqueuedNotifications.size();
5350 for (int i = 0; i < N; i++) {
5351 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
5352 if (Objects.equals(key, enqueued.getKey())) {
5353 r = enqueued;
5354 break;
Chris Wren6676dab2016-12-21 18:26:27 -05005355 }
Chris Wren6676dab2016-12-21 18:26:27 -05005356 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005357 if (r == null) {
5358 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
5359 return;
5360 }
Beverly5a20a5e2018-03-06 15:02:44 -05005361
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005362 if (isBlocked(r)) {
5363 Slog.i(TAG, "notification blocked by assistant request");
5364 return;
5365 }
5366
Beverly3c707b42018-09-14 09:49:07 -04005367 final boolean isPackageSuspended = isPackageSuspendedLocked(r);
5368 r.setHidden(isPackageSuspended);
5369 if (isPackageSuspended) {
5370 mUsageStats.registerSuspendedByAdmin(r);
5371 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005372 NotificationRecord old = mNotificationsByKey.get(key);
5373 final StatusBarNotification n = r.sbn;
5374 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05005375 int index = indexOfNotificationLocked(n.getKey());
5376 if (index < 0) {
5377 mNotificationList.add(r);
5378 mUsageStats.registerPostedByApp(r);
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04005379 r.setInterruptive(isVisuallyInterruptive(null, r));
Chris Wren6676dab2016-12-21 18:26:27 -05005380 } else {
5381 old = mNotificationList.get(index);
5382 mNotificationList.set(index, r);
5383 mUsageStats.registerUpdatedByApp(r, old);
5384 // Make sure we don't lose the foreground service state.
5385 notification.flags |=
Julia Reynoldse5c60452018-04-30 14:41:36 -04005386 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
Chris Wren6676dab2016-12-21 18:26:27 -05005387 r.isUpdate = true;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04005388 r.setTextChanged(isVisuallyInterruptive(old, r));
Chris Wren6676dab2016-12-21 18:26:27 -05005389 }
5390
5391 mNotificationsByKey.put(n.getKey(), r);
5392
5393 // Ensure if this is a foreground service that the proper additional
5394 // flags are set.
Julia Reynoldse5c60452018-04-30 14:41:36 -04005395 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
Mady Mellor49b1bf12019-03-29 12:00:02 -07005396 notification.flags |= FLAG_ONGOING_EVENT
5397 | FLAG_NO_CLEAR;
Chris Wren6676dab2016-12-21 18:26:27 -05005398 }
5399
Julia Reynolds27c0a962018-12-10 12:37:28 -05005400 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05005401 mRankingHelper.sort(mNotificationList);
5402
Gus Prevasa3226492018-10-23 11:10:09 -04005403 if (!r.isHidden()) {
5404 buzzBeepBlinkLocked(r);
5405 }
5406
Chris Wren6676dab2016-12-21 18:26:27 -05005407 if (notification.getSmallIcon() != null) {
5408 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005409 mListeners.notifyPostedLocked(r, old);
Brad Stenningd2e7a972018-10-01 09:08:42 -07005410 if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()))
5411 && !isCritical(r)) {
Julia Reynolds8aebf352017-06-26 11:35:33 -04005412 mHandler.post(new Runnable() {
5413 @Override
5414 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04005415 mGroupHelper.onNotificationPosted(
5416 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04005417 }
5418 });
5419 }
Chris Wren6676dab2016-12-21 18:26:27 -05005420 } else {
5421 Slog.e(TAG, "Not posting notification without small icon: " + notification);
5422 if (old != null && !old.isCanceled) {
Beverly5a20a5e2018-03-06 15:02:44 -05005423 mListeners.notifyRemovedLocked(r,
Julia Reynolds3207e2f2018-12-20 09:39:53 -05005424 NotificationListenerService.REASON_ERROR, r.getStats());
Chris Wren6676dab2016-12-21 18:26:27 -05005425 mHandler.post(new Runnable() {
5426 @Override
5427 public void run() {
5428 mGroupHelper.onNotificationRemoved(n);
5429 }
5430 });
5431 }
5432 // ATTENTION: in a future release we will bail out here
5433 // so that we do not play sounds, show lights, etc. for invalid
5434 // notifications
5435 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
5436 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05005437 }
Chris Wren47633422016-01-22 09:56:59 -05005438
Julia Reynolds1fac86e2018-03-07 08:30:37 -05005439 maybeRecordInterruptionLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005440 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005441 int N = mEnqueuedNotifications.size();
5442 for (int i = 0; i < N; i++) {
5443 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
5444 if (Objects.equals(key, enqueued.getKey())) {
5445 mEnqueuedNotifications.remove(i);
5446 break;
5447 }
5448 }
Chris Wren6676dab2016-12-21 18:26:27 -05005449 }
Chris Wren47633422016-01-22 09:56:59 -05005450 }
5451 }
5452 }
5453
Christoph Studer265c1052014-07-23 17:14:33 +02005454 /**
Julia Reynolds7217dc92018-03-07 12:12:09 -05005455 * If the notification differs enough visually, consider it a new interruptive notification.
5456 */
5457 @GuardedBy("mNotificationLock")
5458 @VisibleForTesting
5459 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
Julia Reynolds760fa762018-06-19 15:39:23 -04005460 // Ignore summary updates because we don't display most of the information.
5461 if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
5462 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005463 Slog.v(TAG, "INTERRUPTIVENESS: "
Julia Reynolds760fa762018-06-19 15:39:23 -04005464 + r.getKey() + " is not interruptive: summary");
5465 }
5466 return false;
5467 }
5468
Dan Sandler7d67bd42018-05-15 14:06:38 -04005469 if (old == null) {
5470 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005471 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005472 + r.getKey() + " is interruptive: new notification");
5473 }
5474 return true;
5475 }
5476
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04005477 if (r == null) {
5478 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005479 Slog.v(TAG, "INTERRUPTIVENESS: "
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04005480 + r.getKey() + " is not interruptive: null");
5481 }
5482 return false;
5483 }
5484
Julia Reynolds7217dc92018-03-07 12:12:09 -05005485 Notification oldN = old.sbn.getNotification();
5486 Notification newN = r.sbn.getNotification();
Dan Sandler7d67bd42018-05-15 14:06:38 -04005487
Julia Reynolds7217dc92018-03-07 12:12:09 -05005488 if (oldN.extras == null || newN.extras == null) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005489 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005490 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005491 + r.getKey() + " is not interruptive: no extras");
5492 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005493 return false;
5494 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04005495
5496 // Ignore visual interruptions from foreground services because users
5497 // consider them one 'session'. Count them for everything else.
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04005498 if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005499 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005500 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005501 + r.getKey() + " is not interruptive: foreground service");
5502 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04005503 return false;
5504 }
5505
Dan Sandler7d67bd42018-05-15 14:06:38 -04005506 final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
5507 final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
5508 if (!Objects.equals(oldTitle, newTitle)) {
5509 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005510 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005511 + r.getKey() + " is interruptive: changed title");
Tony Mak180a9c42019-03-08 13:33:08 +00005512 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)",
Dan Sandler7d67bd42018-05-15 14:06:38 -04005513 oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
Tony Mak180a9c42019-03-08 13:33:08 +00005514 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)",
Dan Sandler7d67bd42018-05-15 14:06:38 -04005515 newTitle, newTitle.getClass(), newTitle.hashCode()));
5516 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005517 return true;
5518 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04005519 // Do not compare Spannables (will always return false); compare unstyled Strings
5520 final String oldText = String.valueOf(oldN.extras.get(Notification.EXTRA_TEXT));
5521 final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT));
5522 if (!Objects.equals(oldText, newText)) {
5523 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005524 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005525 + r.getKey() + " is interruptive: changed text");
Tony Mak180a9c42019-03-08 13:33:08 +00005526 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)",
Dan Sandler7d67bd42018-05-15 14:06:38 -04005527 oldText, oldText.getClass(), oldText.hashCode()));
Tony Mak180a9c42019-03-08 13:33:08 +00005528 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)",
Dan Sandler7d67bd42018-05-15 14:06:38 -04005529 newText, newText.getClass(), newText.hashCode()));
5530 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005531 return true;
5532 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04005533 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
5534 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005535 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005536 + r.getKey() + " is interruptive: completed progress");
5537 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005538 return true;
5539 }
5540 // Actions
5541 if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005542 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005543 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005544 + r.getKey() + " is interruptive: changed actions");
5545 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005546 return true;
5547 }
5548
5549 try {
5550 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
5551 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
5552
5553 // Style based comparisons
5554 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005555 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005556 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005557 + r.getKey() + " is interruptive: styles differ");
5558 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005559 return true;
5560 }
5561
5562 // Remote views
5563 if (Notification.areRemoteViewsChanged(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005564 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005565 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005566 + r.getKey() + " is interruptive: remoteviews differ");
5567 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005568 return true;
5569 }
5570 } catch (Exception e) {
5571 Slog.w(TAG, "error recovering builder", e);
5572 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04005573
Julia Reynolds7217dc92018-03-07 12:12:09 -05005574 return false;
5575 }
5576
5577 /**
Brad Stenningd2e7a972018-10-01 09:08:42 -07005578 * Check if the notification is classified as critical.
5579 *
5580 * @param record the record to test for criticality
5581 * @return {@code true} if notification is considered critical
5582 *
5583 * @see CriticalNotificationExtractor for criteria
5584 */
5585 private boolean isCritical(NotificationRecord record) {
5586 // 0 is the most critical
5587 return record.getCriticality() < CriticalNotificationExtractor.NORMAL;
5588 }
5589
5590 /**
Christoph Studer265c1052014-07-23 17:14:33 +02005591 * Ensures that grouped notification receive their special treatment.
5592 *
5593 * <p>Cancels group children if the new notification causes a group to lose
5594 * its summary.</p>
5595 *
5596 * <p>Updates mSummaryByGroupKey.</p>
5597 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005598 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02005599 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
5600 int callingUid, int callingPid) {
5601 StatusBarNotification sbn = r.sbn;
5602 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07005603 if (n.isGroupSummary() && !sbn.isAppGroup()) {
5604 // notifications without a group shouldn't be a summary, otherwise autobundling can
5605 // lead to bugs
5606 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
5607 }
5608
Christoph Studer265c1052014-07-23 17:14:33 +02005609 String group = sbn.getGroupKey();
5610 boolean isSummary = n.isGroupSummary();
5611
5612 Notification oldN = old != null ? old.sbn.getNotification() : null;
5613 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
5614 boolean oldIsSummary = old != null && oldN.isGroupSummary();
5615
5616 if (oldIsSummary) {
5617 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
5618 if (removedSummary != old) {
5619 String removedKey =
5620 removedSummary != null ? removedSummary.getKey() : "<null>";
5621 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
5622 ", removed=" + removedKey);
5623 }
5624 }
5625 if (isSummary) {
5626 mSummaryByGroupKey.put(group, r);
5627 }
5628
5629 // Clear out group children of the old notification if the update
5630 // causes the group summary to go away. This happens when the old
5631 // notification was a summary and the new one isn't, or when the old
5632 // notification was a summary and its group key changed.
5633 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04005634 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
5635 null);
Christoph Studer265c1052014-07-23 17:14:33 +02005636 }
5637 }
5638
Chris Wren93bb8b82016-03-29 14:35:05 -04005639 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04005640 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05005641 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04005642 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05005643 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
5644 REQUEST_CODE_TIMEOUT,
5645 new Intent(ACTION_NOTIFICATION_TIMEOUT)
5646 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
5647 .appendPath(record.getKey()).build())
5648 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
5649 .putExtra(EXTRA_KEY, record.getKey()),
5650 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05005651 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04005652 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05005653 }
5654 }
5655
5656 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04005657 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04005658 void buzzBeepBlinkLocked(NotificationRecord record) {
Qiao (Adora) Zhang47b553c2019-04-15 20:42:57 +00005659 if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) {
5660 return;
5661 }
Chris Wren82ba59d2015-06-05 11:23:44 -04005662 boolean buzz = false;
5663 boolean beep = false;
5664 boolean blink = false;
5665
Chris Wrena3446562014-06-03 18:11:47 -04005666 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04005667 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04005668
5669 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04005670 final boolean aboveThreshold =
Adora Zhang963328f2018-11-15 18:17:19 -08005671 mIsAutomotive
5672 ? record.getImportance() > NotificationManager.IMPORTANCE_DEFAULT
5673 : record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04005674
5675 // Remember if this notification already owns the notification channels.
5676 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
5677 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04005678 // These are set inside the conditional if the notification is allowed to make noise.
5679 boolean hasValidVibrate = false;
5680 boolean hasValidSound = false;
Julia Reynolds94187562017-10-10 13:58:49 -04005681 boolean sentAccessibilityEvent = false;
5682 // If the notification will appear in the status bar, it should send an accessibility
5683 // event
5684 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
5685 sendAccessibilityEvent(notification, record.sbn.getPackageName());
5686 sentAccessibilityEvent = true;
5687 }
Chris Wrena3446562014-06-03 18:11:47 -04005688
Julia Reynolds76c096d2017-06-19 08:16:04 -04005689 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04005690
Julia Reynolds76c096d2017-06-19 08:16:04 -04005691 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04005692 Uri soundUri = record.getSound();
5693 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
5694 long[] vibration = record.getVibration();
5695 // Demote sound to vibration if vibration missing & phone in vibration mode.
5696 if (vibration == null
5697 && hasValidSound
5698 && (mAudioManager.getRingerModeInternal()
Julia Reynolds85896572017-09-20 12:54:52 -04005699 == AudioManager.RINGER_MODE_VIBRATE)
5700 && mAudioManager.getStreamVolume(
5701 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04005702 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04005703 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04005704 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01005705
Julia Reynolds76c096d2017-06-19 08:16:04 -04005706 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
Julia Reynolds76c096d2017-06-19 08:16:04 -04005707 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04005708 if (!sentAccessibilityEvent) {
5709 sendAccessibilityEvent(notification, record.sbn.getPackageName());
5710 sentAccessibilityEvent = true;
5711 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005712 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04005713 if (hasValidSound) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04005714 if (mInCall) {
5715 playInCallNotification();
5716 beep = true;
5717 } else {
5718 beep = playSound(record, soundUri);
5719 }
Seungho Lee55102a82018-12-09 19:27:36 +09005720 if(beep) {
5721 mSoundNotificationKey = key;
5722 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04005723 }
Chris Wren93bb8b82016-03-29 14:35:05 -04005724
Julia Reynolds7c96b582017-05-25 12:35:36 -04005725 final boolean ringerModeSilent =
5726 mAudioManager.getRingerModeInternal()
5727 == AudioManager.RINGER_MODE_SILENT;
5728 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005729 buzz = playVibration(record, vibration, hasValidSound);
Seungho Lee55102a82018-12-09 19:27:36 +09005730 if(buzz) {
5731 mVibrateNotificationKey = key;
5732 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04005733 }
Tyler Gunn48f86272018-07-03 12:38:49 -07005734 } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
5735 hasValidSound = false;
Chris Wrena3446562014-06-03 18:11:47 -04005736 }
5737 }
Chris Wren93bb8b82016-03-29 14:35:05 -04005738 }
5739 // If a notification is updated to remove the actively playing sound or vibrate,
5740 // cancel that feedback now
5741 if (wasBeep && !hasValidSound) {
5742 clearSoundLocked();
5743 }
5744 if (wasBuzz && !hasValidVibrate) {
5745 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04005746 }
5747
5748 // light
5749 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04005750 boolean wasShowLights = mLights.remove(key);
Julia Reynolds28149f62018-07-03 10:43:35 -04005751 if (canShowLightsLocked(record, aboveThreshold)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04005752 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04005753 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04005754 if (mUseAttentionLight) {
5755 mAttentionLight.pulse();
5756 }
Chris Wren82ba59d2015-06-05 11:23:44 -04005757 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04005758 } else if (wasShowLights) {
5759 updateLightsLocked();
5760 }
Chris Wren82ba59d2015-06-05 11:23:44 -04005761 if (buzz || beep || blink) {
Julia Reynolds28149f62018-07-03 10:43:35 -04005762 // Ignore summary updates because we don't display most of the information.
5763 if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) {
5764 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005765 Slog.v(TAG, "INTERRUPTIVENESS: "
Julia Reynolds28149f62018-07-03 10:43:35 -04005766 + record.getKey() + " is not interruptive: summary");
5767 }
5768 } else {
5769 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005770 Slog.v(TAG, "INTERRUPTIVENESS: "
Julia Reynolds28149f62018-07-03 10:43:35 -04005771 + record.getKey() + " is interruptive: alerted");
5772 }
5773 record.setInterruptive(true);
5774 }
Julia Reynolds445cfa82017-05-08 15:41:45 -04005775 MetricsLogger.action(record.getLogMaker()
5776 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
5777 .setType(MetricsEvent.TYPE_OPEN)
5778 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
5779 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04005780 }
Gus Prevasa3226492018-10-23 11:10:09 -04005781 record.setAudiblyAlerted(buzz || beep);
Chris Wrena3446562014-06-03 18:11:47 -04005782 }
5783
Julia Reynolds88860ce2017-06-01 16:55:49 -04005784 @GuardedBy("mNotificationLock")
Julia Reynolds28149f62018-07-03 10:43:35 -04005785 boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
5786 // device lacks light
5787 if (!mHasLight) {
5788 return false;
5789 }
5790 // user turned lights off globally
5791 if (!mNotificationPulseEnabled) {
5792 return false;
5793 }
5794 // the notification/channel has no light
5795 if (record.getLight() == null) {
5796 return false;
5797 }
5798 // unimportant notification
5799 if (!aboveThreshold) {
5800 return false;
5801 }
5802 // suppressed due to DND
5803 if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
5804 return false;
5805 }
5806 // Suppressed because it's a silent update
5807 final Notification notification = record.getNotification();
Mady Mellor66efd5e2019-05-15 13:38:11 -07005808 if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
Julia Reynolds28149f62018-07-03 10:43:35 -04005809 return false;
5810 }
5811 // Suppressed because another notification in its group handles alerting
5812 if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
5813 return false;
5814 }
5815 // not if in call or the screen's on
5816 if (mInCall || mScreenOn) {
5817 return false;
5818 }
5819
5820 return true;
5821 }
5822
5823 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005824 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04005825 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005826 final Notification notification = record.getNotification();
Mady Mellor66efd5e2019-05-15 13:38:11 -07005827 if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005828 return true;
5829 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005830
Julia Reynolds76c096d2017-06-19 08:16:04 -04005831 // muted by listener
5832 final String disableEffects = disableNotificationEffects(record);
5833 if (disableEffects != null) {
5834 ZenLog.traceDisableEffects(record, disableEffects);
5835 return true;
5836 }
5837
5838 // suppressed due to DND
5839 if (record.isIntercepted()) {
5840 return true;
5841 }
5842
5843 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005844 if (record.sbn.isGroup()) {
Julia Reynolds79dfdd62018-04-17 15:36:33 -04005845 if (notification.suppressAlertingDueToGrouping()) {
5846 return true;
5847 }
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005848 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005849
Julia Reynolds65b85cf2017-07-20 09:19:20 -04005850 // Suppressed for being too recently noisy
5851 final String pkg = record.sbn.getPackageName();
5852 if (mUsageStats.isAlertRateLimited(pkg)) {
5853 Slog.e(TAG, "Muting recently noisy " + record.getKey());
5854 return true;
5855 }
5856
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005857 return false;
5858 }
5859
Julia Reynolds0c299d42016-11-15 14:37:04 -05005860 private boolean playSound(final NotificationRecord record, Uri soundUri) {
5861 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
Jean-Michel Triviec2bb182018-03-23 18:04:00 -07005862 // play notifications if there is no user of exclusive audio focus
5863 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
5864 // VIBRATE ringer mode)
5865 if (!mAudioManager.isAudioFocusExclusive()
5866 && (mAudioManager.getStreamVolume(
5867 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05005868 final long identity = Binder.clearCallingIdentity();
5869 try {
5870 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5871 if (player != null) {
5872 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
5873 + " with attributes " + record.getAudioAttributes());
5874 player.playAsync(soundUri, record.sbn.getUser(), looping,
5875 record.getAudioAttributes());
5876 return true;
5877 }
5878 } catch (RemoteException e) {
5879 } finally {
5880 Binder.restoreCallingIdentity(identity);
5881 }
5882 }
5883 return false;
5884 }
5885
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005886 private boolean playVibration(final NotificationRecord record, long[] vibration,
5887 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005888 // Escalate privileges so we can use the vibrator even if the
5889 // notifying app does not have the VIBRATE permission.
5890 long identity = Binder.clearCallingIdentity();
5891 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005892 final VibrationEffect effect;
5893 try {
5894 final boolean insistent =
5895 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
5896 effect = VibrationEffect.createWaveform(
5897 vibration, insistent ? 0 : -1 /*repeatIndex*/);
5898 } catch (IllegalArgumentException e) {
5899 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
5900 Arrays.toString(vibration));
5901 return false;
5902 }
5903 if (delayVibForSound) {
5904 new Thread(() -> {
5905 // delay the vibration by the same amount as the notification sound
5906 final int waitMs = mAudioManager.getFocusRampTimeMs(
5907 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
5908 record.getAudioAttributes());
5909 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
5910 try {
5911 Thread.sleep(waitMs);
5912 } catch (InterruptedException e) { }
Seungho Leede933882018-10-31 21:49:09 +09005913
5914 // Notifications might be canceled before it actually vibrates due to waitMs,
5915 // so need to check the notification still valide for vibrate.
5916 synchronized (mNotificationLock) {
5917 if (mNotificationsByKey.get(record.getKey()) != null) {
5918 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
5919 effect, "Notification (delayed)", record.getAudioAttributes());
5920 } else {
5921 Slog.e(TAG, "No vibration for canceled notification : " + record.getKey());
5922 }
5923 }
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005924 }).start();
5925 } else {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04005926 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01005927 effect, "Notification", record.getAudioAttributes());
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005928 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005929 return true;
5930 } finally{
5931 Binder.restoreCallingIdentity(identity);
5932 }
5933 }
5934
Julia Reynolds7c96b582017-05-25 12:35:36 -04005935 private boolean isNotificationForCurrentUser(NotificationRecord record) {
5936 final int currentUser;
5937 final long token = Binder.clearCallingIdentity();
5938 try {
5939 currentUser = ActivityManager.getCurrentUser();
5940 } finally {
5941 Binder.restoreCallingIdentity(token);
5942 }
5943 return (record.getUserId() == UserHandle.USER_ALL ||
5944 record.getUserId() == currentUser ||
5945 mUserProfiles.isCurrentProfile(record.getUserId()));
5946 }
5947
Beverly5d463b62017-07-26 14:13:40 -04005948 protected void playInCallNotification() {
Beverly28c3d162018-06-28 11:37:53 -04005949 if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL
5950 && Settings.Secure.getInt(getContext().getContentResolver(),
5951 Settings.Secure.IN_CALL_NOTIFICATION_ENABLED, 1) != 0) {
5952 new Thread() {
5953 @Override
5954 public void run() {
5955 final long identity = Binder.clearCallingIdentity();
5956 try {
5957 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5958 if (player != null) {
5959 if (mCallNotificationToken != null) {
5960 player.stop(mCallNotificationToken);
5961 }
5962 mCallNotificationToken = new Binder();
5963 player.play(mCallNotificationToken, mInCallNotificationUri,
5964 mInCallNotificationAudioAttributes,
5965 mInCallNotificationVolume, false);
luochaojiang50e5273c2018-04-16 16:55:03 +08005966 }
Beverly28c3d162018-06-28 11:37:53 -04005967 } catch (RemoteException e) {
5968 } finally {
5969 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01005970 }
Marta Białka39c992f2011-03-10 10:27:24 +01005971 }
Beverly28c3d162018-06-28 11:37:53 -04005972 }.start();
5973 }
Marta Białka39c992f2011-03-10 10:27:24 +01005974 }
5975
Julia Reynolds88860ce2017-06-01 16:55:49 -04005976 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005977 void showNextToastLocked() {
5978 ToastRecord record = mToastQueue.get(0);
5979 while (record != null) {
5980 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
5981 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005982 record.callback.show(record.token);
Robert Carr997427342018-02-28 18:06:10 -08005983 scheduleDurationReachedLocked(record);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005984 return;
5985 } catch (RemoteException e) {
5986 Slog.w(TAG, "Object died trying to show notification " + record.callback
5987 + " in package " + record.pkg);
5988 // remove it from the list and let the process die
5989 int index = mToastQueue.indexOf(record);
5990 if (index >= 0) {
5991 mToastQueue.remove(index);
5992 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005993 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005994 if (mToastQueue.size() > 0) {
5995 record = mToastQueue.get(0);
5996 } else {
5997 record = null;
5998 }
5999 }
6000 }
6001 }
6002
Julia Reynolds88860ce2017-06-01 16:55:49 -04006003 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08006004 void cancelToastLocked(int index) {
6005 ToastRecord record = mToastQueue.get(index);
6006 try {
6007 record.callback.hide();
6008 } catch (RemoteException e) {
6009 Slog.w(TAG, "Object died trying to hide notification " + record.callback
6010 + " in package " + record.pkg);
6011 // don't worry about this, we're about to remove it from
6012 // the list anyway
6013 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07006014
6015 ToastRecord lastToast = mToastQueue.remove(index);
Robert Carr997427342018-02-28 18:06:10 -08006016
6017 mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
Jeff Chang48ecef42018-08-09 16:31:59 +08006018 lastToast.displayId);
Robert Carr997427342018-02-28 18:06:10 -08006019 // We passed 'false' for 'removeWindows' so that the client has time to stop
6020 // rendering (as hide above is a one-way message), otherwise we could crash
6021 // a client which was actively using a surface made from the token. However
6022 // we need to schedule a timeout to make sure the token is eventually killed
6023 // one way or another.
Jeff Chang48ecef42018-08-09 16:31:59 +08006024 scheduleKillTokenTimeout(lastToast);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07006025
6026 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08006027 if (mToastQueue.size() > 0) {
6028 // Show the next one. If the callback fails, this will remove
6029 // it from the list, so don't assume that the list hasn't changed
6030 // after this point.
6031 showNextToastLocked();
6032 }
6033 }
6034
Jeff Chang48ecef42018-08-09 16:31:59 +08006035 void finishTokenLocked(IBinder t, int displayId) {
Robert Carr997427342018-02-28 18:06:10 -08006036 mHandler.removeCallbacksAndMessages(t);
6037 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
6038 // remaining surfaces as either the client has called finishToken indicating
6039 // it has successfully removed the views, or the client has timed out
6040 // at which point anything goes.
Jeff Chang48ecef42018-08-09 16:31:59 +08006041 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */, displayId);
Robert Carr997427342018-02-28 18:06:10 -08006042 }
6043
Julia Reynolds88860ce2017-06-01 16:55:49 -04006044 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08006045 private void scheduleDurationReachedLocked(ToastRecord r)
Adam Lesinski182f73f2013-12-05 16:48:06 -08006046 {
6047 mHandler.removeCallbacksAndMessages(r);
Robert Carr997427342018-02-28 18:06:10 -08006048 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
Rhed Jao406d3a22018-11-30 19:28:58 +08006049 int delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
6050 // Accessibility users may need longer timeout duration. This api compares original delay
6051 // with user's preference and return longer one. It returns original delay if there's no
6052 // preference.
6053 delay = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
6054 AccessibilityManager.FLAG_CONTENT_TEXT);
Adam Lesinski182f73f2013-12-05 16:48:06 -08006055 mHandler.sendMessageDelayed(m, delay);
6056 }
6057
Robert Carr997427342018-02-28 18:06:10 -08006058 private void handleDurationReached(ToastRecord record)
Adam Lesinski182f73f2013-12-05 16:48:06 -08006059 {
6060 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
6061 synchronized (mToastQueue) {
6062 int index = indexOfToastLocked(record.pkg, record.callback);
6063 if (index >= 0) {
6064 cancelToastLocked(index);
6065 }
6066 }
6067 }
6068
Julia Reynolds88860ce2017-06-01 16:55:49 -04006069 @GuardedBy("mToastQueue")
Jeff Chang48ecef42018-08-09 16:31:59 +08006070 private void scheduleKillTokenTimeout(ToastRecord r)
Robert Carr997427342018-02-28 18:06:10 -08006071 {
Jeff Chang48ecef42018-08-09 16:31:59 +08006072 mHandler.removeCallbacksAndMessages(r);
6073 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, r);
Robert Carr3406d462018-03-15 16:19:07 -07006074 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
Robert Carr997427342018-02-28 18:06:10 -08006075 }
6076
Jeff Chang48ecef42018-08-09 16:31:59 +08006077 private void handleKillTokenTimeout(ToastRecord record)
Robert Carr997427342018-02-28 18:06:10 -08006078 {
Jeff Chang48ecef42018-08-09 16:31:59 +08006079 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.token);
Robert Carr997427342018-02-28 18:06:10 -08006080 synchronized (mToastQueue) {
Jeff Chang48ecef42018-08-09 16:31:59 +08006081 finishTokenLocked(record.token, record.displayId);
Robert Carr997427342018-02-28 18:06:10 -08006082 }
6083 }
6084
6085 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08006086 int indexOfToastLocked(String pkg, ITransientNotification callback)
6087 {
6088 IBinder cbak = callback.asBinder();
6089 ArrayList<ToastRecord> list = mToastQueue;
6090 int len = list.size();
6091 for (int i=0; i<len; i++) {
6092 ToastRecord r = list.get(i);
Beverly Taia7ed0ab2018-06-11 14:50:36 +00006093 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08006094 return i;
6095 }
6096 }
6097 return -1;
6098 }
6099
Julia Reynolds88860ce2017-06-01 16:55:49 -04006100 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07006101 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08006102 {
6103 int toastCount = 0; // toasts from this pid
6104 ArrayList<ToastRecord> list = mToastQueue;
6105 int N = list.size();
6106 for (int i=0; i<N; i++) {
6107 ToastRecord r = list.get(i);
6108 if (r.pid == pid) {
6109 toastCount++;
6110 }
6111 }
6112 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07006113 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08006114 } catch (RemoteException e) {
6115 // Shouldn't happen.
6116 }
6117 }
6118
Chris Wrenf9536642014-04-17 10:01:54 -04006119 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04006120 if (!(message.obj instanceof RankingReconsideration)) return;
6121 RankingReconsideration recon = (RankingReconsideration) message.obj;
6122 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04006123 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006124 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04006125 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
6126 if (record == null) {
6127 return;
Chris Wrenf9536642014-04-17 10:01:54 -04006128 }
Chris Wren333a61c2014-05-28 16:40:57 -04006129 int indexBefore = findNotificationRecordIndexLocked(record);
6130 boolean interceptBefore = record.isIntercepted();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006131 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04006132 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04006133 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04006134 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04006135 int indexAfter = findNotificationRecordIndexLocked(record);
6136 boolean interceptAfter = record.isIntercepted();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006137 int visibilityAfter = record.getPackageVisibilityOverride();
6138 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
6139 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04006140 if (interceptBefore && !interceptAfter
Julia Reynoldsd6730072019-01-04 12:52:52 -05006141 && record.isNewEnoughForAlerting(System.currentTimeMillis())) {
Chris Wrena3446562014-06-03 18:11:47 -04006142 buzzBeepBlinkLocked(record);
6143 }
Chris Wrenf9536642014-04-17 10:01:54 -04006144 }
Chris Wren333a61c2014-05-28 16:40:57 -04006145 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006146 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04006147 }
6148 }
6149
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006150 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04006151 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006152 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04006153 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006154 // Any field that can change via one of the extractors needs to be added here.
6155 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006156 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05006157 boolean[] showBadges = new boolean[N];
Julia Reynolds4509ce72019-01-31 13:12:43 -05006158 boolean[] allowBubbles = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006159 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
6160 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
6161 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
6162 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Julia Reynolds503ed942017-10-04 16:04:56 -04006163 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05006164 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
Gustav Sennton1463d832018-11-06 16:12:48 +00006165 ArrayList<ArrayList<Notification.Action>> systemSmartActionsBefore = new ArrayList<>(N);
Tony Makc9acf672018-07-20 13:58:24 +02006166 ArrayList<ArrayList<CharSequence>> smartRepliesBefore = new ArrayList<>(N);
Julia Reynolds27c0a962018-12-10 12:37:28 -05006167 int[] importancesBefore = new int[N];
Chris Wren54bbef42014-07-09 18:37:56 -04006168 for (int i = 0; i < N; i++) {
6169 final NotificationRecord r = mNotificationList.get(i);
6170 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006171 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05006172 showBadges[i] = r.canShowBadge();
Julia Reynolds4509ce72019-01-31 13:12:43 -05006173 allowBubbles[i] = r.canBubble();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006174 channelBefore.add(r.getChannel());
6175 groupKeyBefore.add(r.getGroupKey());
6176 overridePeopleBefore.add(r.getPeopleOverride());
6177 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Julia Reynolds503ed942017-10-04 16:04:56 -04006178 userSentimentBefore.add(r.getUserSentiment());
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05006179 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
Gustav Sennton1463d832018-11-06 16:12:48 +00006180 systemSmartActionsBefore.add(r.getSystemGeneratedSmartActions());
Tony Makc9acf672018-07-20 13:58:24 +02006181 smartRepliesBefore.add(r.getSmartReplies());
Julia Reynolds27c0a962018-12-10 12:37:28 -05006182 importancesBefore[i] = r.getImportance();
Chris Wren54bbef42014-07-09 18:37:56 -04006183 mRankingHelper.extractSignals(r);
6184 }
Chris Wren19a02b02015-12-22 10:34:22 -05006185 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04006186 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006187 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006188 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05006189 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006190 || showBadges[i] != r.canShowBadge()
Julia Reynolds4509ce72019-01-31 13:12:43 -05006191 || allowBubbles[i] != r.canBubble()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006192 || !Objects.equals(channelBefore.get(i), r.getChannel())
6193 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
6194 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
Julia Reynolds503ed942017-10-04 16:04:56 -04006195 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05006196 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
6197 || !Objects.equals(suppressVisuallyBefore.get(i),
Tony Mak628cb932018-06-19 18:30:41 +01006198 r.getSuppressedVisualEffects())
Gustav Sennton1463d832018-11-06 16:12:48 +00006199 || !Objects.equals(systemSmartActionsBefore.get(i),
6200 r.getSystemGeneratedSmartActions())
Julia Reynolds27c0a962018-12-10 12:37:28 -05006201 || !Objects.equals(smartRepliesBefore.get(i), r.getSmartReplies())
6202 || importancesBefore[i] != r.getImportance()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006203 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04006204 return;
6205 }
6206 }
6207 }
6208 }
6209
Julia Reynolds88860ce2017-06-01 16:55:49 -04006210 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04006211 private void recordCallerLocked(NotificationRecord record) {
6212 if (mZenModeHelper.isCall(record)) {
6213 mZenModeHelper.recordCaller(record);
6214 }
6215 }
6216
Christoph Studerd5092bc2014-07-03 17:47:58 +02006217 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04006218 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04006219 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02006220 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006221 if (record.isIntercepted()) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05006222 record.setSuppressedVisualEffects(
Beverlyff2df9b2018-10-10 16:54:10 -04006223 mZenModeHelper.getConsolidatedNotificationPolicy().suppressedVisualEffects);
Julia Reynolds445cfa82017-05-08 15:41:45 -04006224 } else {
6225 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006226 }
Chris Wren333a61c2014-05-28 16:40:57 -04006227 }
6228
Julia Reynolds88860ce2017-06-01 16:55:49 -04006229 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04006230 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04006231 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04006232 }
6233
Chris Wrenf9536642014-04-17 10:01:54 -04006234 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006235 synchronized (mNotificationLock) {
Beverly5a20a5e2018-03-06 15:02:44 -05006236 mListeners.notifyRankingUpdateLocked(null);
Chris Wrenf9536642014-04-17 10:01:54 -04006237 }
6238 }
6239
John Spurlockd8afe3c2014-08-01 14:04:07 -04006240 private void scheduleListenerHintsChanged(int state) {
6241 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
6242 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04006243 }
6244
Christoph Studer85a384b2014-08-27 20:16:15 +02006245 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
6246 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
6247 mHandler.obtainMessage(
6248 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
6249 listenerInterruptionFilter,
6250 0).sendToTarget();
6251 }
6252
John Spurlockd8afe3c2014-08-01 14:04:07 -04006253 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006254 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006255 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006256 }
6257 }
6258
Christoph Studer85a384b2014-08-27 20:16:15 +02006259 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006260 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02006261 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
6262 }
6263 }
6264
Julia Reynoldsb0405592018-11-26 17:01:13 -05006265 private void handleOnPackageChanged(boolean removingPackage, int changeUserId,
6266 String[] pkgList, int[] uidList) {
6267 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
6268 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
6269 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
6270 mPreferencesHelper.onPackagesChanged(
6271 removingPackage, changeUserId, pkgList, uidList);
6272 handleSavePolicyFile();
6273 }
6274
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006275 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08006276 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006277 public WorkerHandler(Looper looper) {
6278 super(looper);
6279 }
6280
Adam Lesinski182f73f2013-12-05 16:48:06 -08006281 @Override
6282 public void handleMessage(Message msg)
6283 {
6284 switch (msg.what)
6285 {
Robert Carr997427342018-02-28 18:06:10 -08006286 case MESSAGE_DURATION_REACHED:
Julia Reynoldsb0405592018-11-26 17:01:13 -05006287 handleDurationReached((ToastRecord) msg.obj);
Robert Carr997427342018-02-28 18:06:10 -08006288 break;
6289 case MESSAGE_FINISH_TOKEN_TIMEOUT:
Julia Reynoldsb0405592018-11-26 17:01:13 -05006290 handleKillTokenTimeout((ToastRecord) msg.obj);
Adam Lesinski182f73f2013-12-05 16:48:06 -08006291 break;
Chris Wrenf9536642014-04-17 10:01:54 -04006292 case MESSAGE_SEND_RANKING_UPDATE:
6293 handleSendRankingUpdate();
6294 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04006295 case MESSAGE_LISTENER_HINTS_CHANGED:
6296 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04006297 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02006298 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
6299 handleListenerInterruptionFilterChanged(msg.arg1);
6300 break;
Julia Reynoldsb0405592018-11-26 17:01:13 -05006301 case MESSAGE_ON_PACKAGE_CHANGED:
6302 SomeArgs args = (SomeArgs) msg.obj;
6303 handleOnPackageChanged((boolean) args.arg1, args.argi1, (String[]) args.arg2,
6304 (int[]) args.arg3);
6305 args.recycle();
6306 break;
Chris Wrenf9536642014-04-17 10:01:54 -04006307 }
6308 }
6309
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006310 protected void scheduleSendRankingUpdate() {
6311 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
6312 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
6313 sendMessage(m);
6314 }
6315 }
6316
Julia Reynoldsefcdff42018-08-09 09:42:56 -04006317 protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable) {
6318 if (!hasCallbacks(cancelRunnable)) {
6319 sendMessage(Message.obtain(this, cancelRunnable));
6320 }
6321 }
Julia Reynoldsb0405592018-11-26 17:01:13 -05006322
6323 protected void scheduleOnPackageChanged(boolean removingPackage, int changeUserId,
6324 String[] pkgList, int[] uidList) {
6325 SomeArgs args = SomeArgs.obtain();
6326 args.arg1 = removingPackage;
6327 args.argi1 = changeUserId;
6328 args.arg2 = pkgList;
6329 args.arg3 = uidList;
6330 sendMessage(Message.obtain(this, MESSAGE_ON_PACKAGE_CHANGED, args));
6331 }
Chris Wrenf9536642014-04-17 10:01:54 -04006332 }
6333
Chris Wren51017d02015-12-15 15:34:46 -05006334 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04006335 {
Chris Wren51017d02015-12-15 15:34:46 -05006336 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04006337 super(looper);
6338 }
6339
6340 @Override
6341 public void handleMessage(Message msg) {
6342 switch (msg.what) {
6343 case MESSAGE_RECONSIDER_RANKING:
6344 handleRankingReconsideration(msg);
6345 break;
Chris Wren51017d02015-12-15 15:34:46 -05006346 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006347 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04006348 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08006349 }
6350 }
Chris Wren51017d02015-12-15 15:34:46 -05006351
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006352 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05006353 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05006354 Message msg = Message.obtain();
6355 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05006356 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05006357 }
6358
6359 public void requestReconsideration(RankingReconsideration recon) {
6360 Message m = Message.obtain(this,
6361 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
6362 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
6363 sendMessageDelayed(m, delay);
6364 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08006365 }
6366
Adam Lesinski182f73f2013-12-05 16:48:06 -08006367 // Notifications
6368 // ============================================================================
6369 static int clamp(int x, int low, int high) {
6370 return (x < low) ? low : ((x > high) ? high : x);
6371 }
6372
6373 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
Eugene Suslad4128ec2017-12-04 19:48:41 +00006374 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07006375 return;
6376 }
6377
6378 AccessibilityEvent event =
6379 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
6380 event.setPackageName(packageName);
6381 event.setClassName(Notification.class.getName());
6382 event.setParcelableData(notification);
6383 CharSequence tickerText = notification.tickerText;
6384 if (!TextUtils.isEmpty(tickerText)) {
6385 event.getText().add(tickerText);
6386 }
6387
Julia Reynolds94187562017-10-10 13:58:49 -04006388 mAccessibilityManager.sendAccessibilityEvent(event);
svetoslavganov75986cf2009-05-14 22:28:01 -07006389 }
6390
Julia Reynolds0839c022017-06-15 15:24:01 -04006391 /**
6392 * Removes all NotificationsRecords with the same key as the given notification record
6393 * from both lists. Do not call this method while iterating over either list.
6394 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006395 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04006396 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
6397 // Remove from both lists, either list could have a separate Record for what is
6398 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006399 boolean wasPosted = false;
6400 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04006401 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
6402 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006403 mNotificationList.remove(recordInList);
6404 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006405 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006406 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006407 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006408 != null) {
6409 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006410 }
Julia Reynolds0839c022017-06-15 15:24:01 -04006411 return wasPosted;
6412 }
6413
6414 @GuardedBy("mNotificationLock")
6415 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04006416 boolean wasPosted, String listenerName) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08006417 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName);
6418 }
6419
6420 @GuardedBy("mNotificationLock")
6421 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
6422 int rank, int count, boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04006423 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04006424
6425 // Record caller.
6426 recordCallerLocked(r);
6427
Julia Reynolds503ed942017-10-04 16:04:56 -04006428 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
6429 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
6430 }
6431
Joe Onorato46439ce2010-11-19 13:56:21 -08006432 // tell the app
6433 if (sendDelete) {
Michal Karpinskid2075892019-04-17 16:01:10 +01006434 final PendingIntent deleteIntent = r.getNotification().deleteIntent;
6435 if (deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08006436 try {
Michal Karpinskid2075892019-04-17 16:01:10 +01006437 // make sure deleteIntent cannot be used to start activities from background
6438 LocalServices.getService(ActivityManagerInternal.class)
6439 .clearPendingIntentAllowBgActivityStarts(deleteIntent.getTarget(),
6440 WHITELIST_TOKEN);
6441 deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08006442 } catch (PendingIntent.CanceledException ex) {
6443 // do nothing - there's no relevant way to recover, and
6444 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04006445 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08006446 }
6447 }
6448 }
6449
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006450 // Only cancel these if this notification actually got to be posted.
6451 if (wasPosted) {
6452 // status bar
6453 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05006454 if (reason != REASON_SNOOZED) {
6455 r.isCanceled = true;
6456 }
Beverly5a20a5e2018-03-06 15:02:44 -05006457 mListeners.notifyRemovedLocked(r, reason, r.getStats());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006458 mHandler.post(new Runnable() {
6459 @Override
6460 public void run() {
6461 mGroupHelper.onNotificationRemoved(r.sbn);
6462 }
6463 });
6464 }
6465
6466 // sound
6467 if (canceledKey.equals(mSoundNotificationKey)) {
6468 mSoundNotificationKey = null;
6469 final long identity = Binder.clearCallingIdentity();
6470 try {
6471 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
6472 if (player != null) {
6473 player.stopAsync();
6474 }
6475 } catch (RemoteException e) {
6476 } finally {
6477 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04006478 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006479 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006480
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006481 // vibrate
6482 if (canceledKey.equals(mVibrateNotificationKey)) {
6483 mVibrateNotificationKey = null;
6484 long identity = Binder.clearCallingIdentity();
6485 try {
6486 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07006487 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006488 finally {
6489 Binder.restoreCallingIdentity(identity);
6490 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006491 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006492
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006493 // light
6494 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006495 }
6496
Christoph Studer546bec82014-03-14 12:17:12 +01006497 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04006498 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01006499 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04006500 case REASON_CANCEL:
6501 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01006502 case REASON_LISTENER_CANCEL:
6503 case REASON_LISTENER_CANCEL_ALL:
6504 mUsageStats.registerDismissedByUser(r);
6505 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05006506 case REASON_APP_CANCEL:
6507 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01006508 mUsageStats.registerRemovedByApp(r);
6509 break;
Christoph Studer546bec82014-03-14 12:17:12 +01006510 }
6511
Christoph Studer265c1052014-07-23 17:14:33 +02006512 String groupKey = r.getGroupKey();
6513 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006514 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02006515 mSummaryByGroupKey.remove(groupKey);
6516 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04006517 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
6518 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
6519 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04006520 }
Christoph Studercef37cf2014-07-25 14:18:17 +02006521
Daniel Sandler23d7c702013-03-07 16:32:06 -05006522 // Save it for users of getHistoricalNotifications()
6523 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02006524
Chris Wren6650e572015-05-15 17:19:25 -04006525 final long now = System.currentTimeMillis();
Julia Reynolds3dfdde02018-10-08 09:17:56 -04006526 final LogMaker logMaker = r.getItemLogMaker()
Chris Wren9eb5e102017-01-26 13:15:06 -05006527 .setType(MetricsEvent.TYPE_DISMISS)
Dieter Hsud39f0d52018-04-14 02:08:30 +08006528 .setSubtype(reason);
6529 if (rank != -1 && count != -1) {
6530 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
6531 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
6532 }
6533 MetricsLogger.action(logMaker);
Chris Wrene6ddb8a2015-05-27 15:21:00 -04006534 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Dieter Hsud39f0d52018-04-14 02:08:30 +08006535 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
6536 rank, count, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006537 }
6538
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006539 @VisibleForTesting
6540 void updateUriPermissions(@Nullable NotificationRecord newRecord,
6541 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) {
6542 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey();
6543 if (DBG) Slog.d(TAG, key + ": updating permissions");
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006544
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006545 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null;
6546 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null;
6547
6548 // Shortcut when no Uris involved
6549 if (newUris == null && oldUris == null) {
6550 return;
6551 }
6552
6553 // Inherit any existing owner
6554 IBinder permissionOwner = null;
6555 if (newRecord != null && permissionOwner == null) {
6556 permissionOwner = newRecord.permissionOwner;
6557 }
6558 if (oldRecord != null && permissionOwner == null) {
6559 permissionOwner = oldRecord.permissionOwner;
6560 }
6561
6562 // If we have Uris to grant, but no owner yet, go create one
6563 if (newUris != null && permissionOwner == null) {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07006564 if (DBG) Slog.d(TAG, key + ": creating owner");
6565 permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006566 }
6567
6568 // If we have no Uris to grant, but an existing owner, go destroy it
6569 if (newUris == null && permissionOwner != null) {
6570 final long ident = Binder.clearCallingIdentity();
6571 try {
6572 if (DBG) Slog.d(TAG, key + ": destroying owner");
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07006573 mUgmInternal.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006574 UserHandle.getUserId(oldRecord.getUid()));
6575 permissionOwner = null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006576 } finally {
6577 Binder.restoreCallingIdentity(ident);
6578 }
6579 }
6580
6581 // Grant access to new Uris
6582 if (newUris != null && permissionOwner != null) {
6583 for (int i = 0; i < newUris.size(); i++) {
6584 final Uri uri = newUris.valueAt(i);
6585 if (oldUris == null || !oldUris.contains(uri)) {
6586 if (DBG) Slog.d(TAG, key + ": granting " + uri);
6587 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
6588 targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006589 }
6590 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006591 }
6592
6593 // Revoke access to old Uris
6594 if (oldUris != null && permissionOwner != null) {
6595 for (int i = 0; i < oldUris.size(); i++) {
6596 final Uri uri = oldUris.valueAt(i);
6597 if (newUris == null || !newUris.contains(uri)) {
6598 if (DBG) Slog.d(TAG, key + ": revoking " + uri);
6599 revokeUriPermission(permissionOwner, uri, oldRecord.getUid());
6600 }
6601 }
6602 }
6603
6604 if (newRecord != null) {
6605 newRecord.permissionOwner = permissionOwner;
6606 }
6607 }
6608
6609 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg,
6610 int targetUserId) {
6611 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
6612
6613 final long ident = Binder.clearCallingIdentity();
6614 try {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07006615 mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006616 ContentProvider.getUriWithoutUserId(uri),
6617 Intent.FLAG_GRANT_READ_URI_PERMISSION,
6618 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
6619 targetUserId);
6620 } catch (RemoteException ignored) {
6621 // Ignored because we're in same process
6622 } finally {
6623 Binder.restoreCallingIdentity(ident);
6624 }
6625 }
6626
6627 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUid) {
6628 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
6629
6630 final long ident = Binder.clearCallingIdentity();
6631 try {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07006632 mUgmInternal.revokeUriPermissionFromOwner(
6633 owner,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006634 ContentProvider.getUriWithoutUserId(uri),
6635 Intent.FLAG_GRANT_READ_URI_PERMISSION,
6636 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006637 } finally {
6638 Binder.restoreCallingIdentity(ident);
6639 }
6640 }
6641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006642 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07006643 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006644 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006645 */
John Spurlocke6a7d932014-03-13 12:29:00 -04006646 void cancelNotification(final int callingUid, final int callingPid,
6647 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07006648 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04006649 final int userId, final int reason, final ManagedServiceInfo listener) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08006650 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
6651 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
6652 }
6653
6654 /**
6655 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
6656 * and none of the {@code mustNotHaveFlags}.
6657 */
6658 void cancelNotification(final int callingUid, final int callingPid,
6659 final String pkg, final String tag, final int id,
6660 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
Julia Reynoldsefcdff42018-08-09 09:42:56 -04006661 final int userId, final int reason, int rank, int count,
6662 final ManagedServiceInfo listener) {
Svetoslav Ganov835835e2013-08-04 20:17:52 -07006663 // In enqueueNotificationInternal notifications are added by scheduling the
6664 // work on the worker handler. Hence, we also schedule the cancel on this
6665 // handler to avoid a scenario where an add notification call followed by a
6666 // remove notification call ends up in not removing the notification.
Julia Reynoldsefcdff42018-08-09 09:42:56 -04006667 mHandler.scheduleCancelNotification(new CancelNotificationRunnable(callingUid, callingPid,
6668 pkg, tag, id, mustHaveFlags, mustNotHaveFlags, sendDelete, userId, reason, rank,
6669 count, listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006670 }
6671
6672 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07006673 * Determine whether the userId applies to the notification in question, either because
6674 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
6675 */
6676 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
6677 return
6678 // looking for USER_ALL notifications? match everything
6679 userId == UserHandle.USER_ALL
6680 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05006681 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07006682 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05006683 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07006684 }
6685
6686 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006687 * Determine whether the userId applies to the notification in question, either because
6688 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01006689 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006690 */
Kenny Guy2a764942014-04-02 13:29:20 +01006691 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00006692 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04006693 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006694 }
6695
6696 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05006697 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006698 * {@code mustHaveFlags}.
6699 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006700 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04006701 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04006702 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006703 mHandler.post(new Runnable() {
6704 @Override
6705 public void run() {
6706 String listenerName = listener == null ? null : listener.component.toShortString();
6707 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
6708 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
6709 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006710
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006711 // Why does this parameter exist? Do we actually want to execute the above if doit
6712 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08006713 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006714 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08006715 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006716
6717 synchronized (mNotificationLock) {
6718 FlagChecker flagChecker = (int flags) -> {
6719 if ((flags & mustHaveFlags) != mustHaveFlags) {
6720 return false;
6721 }
6722 if ((flags & mustNotHaveFlags) != 0) {
6723 return false;
6724 }
6725 return true;
6726 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006727 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
6728 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
6729 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04006730 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006731 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
6732 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
6733 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04006734 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006735 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02006736 }
6737 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006738 });
6739 }
6740
6741 private interface FlagChecker {
6742 // Returns false if these flags do not pass the defined flag test.
6743 public boolean apply(int flags);
6744 }
6745
Julia Reynolds88860ce2017-06-01 16:55:49 -04006746 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006747 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
6748 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
6749 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04006750 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006751 ArrayList<NotificationRecord> canceledNotifications = null;
6752 for (int i = notificationList.size() - 1; i >= 0; --i) {
6753 NotificationRecord r = notificationList.get(i);
6754 if (includeCurrentProfiles) {
6755 if (!notificationMatchesCurrentProfiles(r, userId)) {
6756 continue;
6757 }
6758 } else if (!notificationMatchesUserId(r, userId)) {
6759 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006760 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006761 // Don't remove notifications to all, if there's no package name specified
6762 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
6763 continue;
6764 }
6765 if (!flagChecker.apply(r.getFlags())) {
6766 continue;
6767 }
6768 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
6769 continue;
6770 }
6771 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
6772 continue;
6773 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006774 if (canceledNotifications == null) {
6775 canceledNotifications = new ArrayList<>();
6776 }
Julia Reynolds0839c022017-06-15 15:24:01 -04006777 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04006778 mNotificationsByKey.remove(r.getKey());
Julia Reynoldsfd4099d2018-08-21 11:06:06 -04006779 r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006780 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04006781 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006782 }
6783 if (canceledNotifications != null) {
6784 final int M = canceledNotifications.size();
6785 for (int i = 0; i < M; i++) {
6786 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04006787 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006788 }
6789 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006790 }
6791 }
6792
Julia Reynolds50989772017-02-23 14:32:16 -05006793 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006794 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05006795 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05006796 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05006797 return;
6798 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05006799
Julia Reynolds79672302017-01-12 08:30:16 -05006800 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05006801 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
6802 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05006803 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006804 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006805 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006806 }
6807
6808 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
6809 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006810 if (DBG) {
6811 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
6812 }
Julia Reynolds79672302017-01-12 08:30:16 -05006813 mSnoozeHelper.repost(key);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05006814 handleSavePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006815 }
6816
Julia Reynolds88860ce2017-06-01 16:55:49 -04006817 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07006818 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04006819 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006820 mHandler.post(new Runnable() {
6821 @Override
6822 public void run() {
6823 synchronized (mNotificationLock) {
6824 String listenerName =
6825 listener == null ? null : listener.component.toShortString();
6826 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
6827 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01006828
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006829 FlagChecker flagChecker = (int flags) -> {
Mady Mellor49b1bf12019-03-29 12:00:02 -07006830 int flagsToCheck = FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
6831 if (REASON_LISTENER_CANCEL_ALL == reason) {
6832 flagsToCheck |= FLAG_BUBBLE;
6833 }
6834 if ((flags & flagsToCheck) != 0) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006835 return false;
6836 }
6837 return true;
6838 };
6839
6840 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
6841 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
6842 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04006843 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006844 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
6845 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
6846 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04006847 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006848 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00006849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006850 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006851 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006852 }
6853
Christoph Studere4ef156b2014-07-04 18:41:57 +02006854 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04006855 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02006856 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04006857 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02006858 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02006859 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02006860 return;
6861 }
6862
6863 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02006864
6865 if (pkg == null) {
Tony Mak180a9c42019-03-08 13:33:08 +00006866 if (DBG) Slog.e(TAG, "No package for group summary: " + r.getKey());
Christoph Studere4ef156b2014-07-04 18:41:57 +02006867 return;
6868 }
6869
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006870 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04006871 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006872 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04006873 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006874 }
6875
Julia Reynolds88860ce2017-06-01 16:55:49 -04006876 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006877 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
6878 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04006879 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006880 final String pkg = parentNotification.sbn.getPackageName();
6881 final int userId = parentNotification.getUserId();
6882 final int reason = REASON_GROUP_SUMMARY_CANCELED;
6883 for (int i = notificationList.size() - 1; i >= 0; i--) {
6884 final NotificationRecord childR = notificationList.get(i);
6885 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04006886 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006887 childR.getGroupKey().equals(parentNotification.getGroupKey())
Julia Reynoldse5c60452018-04-30 14:41:36 -04006888 && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
Beverly40239d92017-07-07 10:20:41 -04006889 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02006890 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
6891 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04006892 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04006893 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04006894 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02006895 }
6896 }
6897 }
6898
Julia Reynolds88860ce2017-06-01 16:55:49 -04006899 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08006900 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006901 {
The Android Open Source Project10592532009-03-18 17:39:46 -07006902 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05006903 NotificationRecord ledNotification = null;
6904 while (ledNotification == null && !mLights.isEmpty()) {
6905 final String owner = mLights.get(mLights.size() - 1);
6906 ledNotification = mNotificationsByKey.get(owner);
6907 if (ledNotification == null) {
6908 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
6909 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006910 }
6911 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006912
Mike Lockwood63b5ad92011-08-30 09:55:30 -04006913 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05006914 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05006915 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07006916 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006917 NotificationRecord.Light light = ledNotification.getLight();
6918 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05006919 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006920 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
6921 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05006922 }
The Android Open Source Project10592532009-03-18 17:39:46 -07006923 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006924 }
6925
Julia Reynolds88860ce2017-06-01 16:55:49 -04006926 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006927 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
6928 String groupKey, int userId) {
6929 List<NotificationRecord> records = new ArrayList<>();
6930 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
6931 records.addAll(
6932 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
6933 return records;
6934 }
6935
6936
Julia Reynolds88860ce2017-06-01 16:55:49 -04006937 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006938 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
6939 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
6940 List<NotificationRecord> records = new ArrayList<>();
6941 final int len = list.size();
6942 for (int i = 0; i < len; i++) {
6943 NotificationRecord r = list.get(i);
6944 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
6945 && r.sbn.getPackageName().equals(pkg)) {
6946 records.add(r);
6947 }
6948 }
6949 return records;
6950 }
6951
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006952 // Searches both enqueued and posted notifications by key.
6953 // TODO: need to combine a bunch of these getters with slightly different behavior.
6954 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04006955 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006956 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006957 NotificationRecord r;
6958 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
6959 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006960 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006961 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
6962 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006963 }
6964 return null;
6965 }
6966
Julia Reynolds88860ce2017-06-01 16:55:49 -04006967 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006968 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006969 NotificationRecord r;
6970 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
6971 return r;
6972 }
6973 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
6974 != null) {
6975 return r;
6976 }
6977 return null;
6978 }
6979
Julia Reynolds88860ce2017-06-01 16:55:49 -04006980 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006981 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006982 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006983 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006984 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006985 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01006986 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
6987 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006988 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006989 }
6990 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006991 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006992 }
6993
Julia Reynolds88860ce2017-06-01 16:55:49 -04006994 @GuardedBy("mNotificationLock")
Julia Reynolds564273f2018-09-13 15:53:11 -04006995 private List<NotificationRecord> findNotificationsByListLocked(
6996 ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) {
6997 List<NotificationRecord> matching = new ArrayList<>();
6998 final int len = list.size();
6999 for (int i = 0; i < len; i++) {
7000 NotificationRecord r = list.get(i);
7001 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
7002 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
7003 matching.add(r);
7004 }
7005 }
7006 return matching;
7007 }
7008
7009 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05007010 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04007011 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05007012 final int N = list.size();
7013 for (int i = 0; i < N; i++) {
7014 if (key.equals(list.get(i).getKey())) {
7015 return list.get(i);
7016 }
7017 }
7018 return null;
7019 }
7020
Julia Reynolds88860ce2017-06-01 16:55:49 -04007021 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02007022 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02007023 final int N = mNotificationList.size();
7024 for (int i = 0; i < N; i++) {
7025 if (key.equals(mNotificationList.get(i).getKey())) {
7026 return i;
7027 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02007028 }
Christoph Studerc5115552014-06-12 20:22:31 +02007029 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02007030 }
7031
Beverly5a20a5e2018-03-06 15:02:44 -05007032 @VisibleForTesting
7033 protected void hideNotificationsForPackages(String[] pkgs) {
7034 synchronized (mNotificationLock) {
7035 List<String> pkgList = Arrays.asList(pkgs);
7036 List<NotificationRecord> changedNotifications = new ArrayList<>();
7037 int numNotifications = mNotificationList.size();
7038 for (int i = 0; i < numNotifications; i++) {
7039 NotificationRecord rec = mNotificationList.get(i);
7040 if (pkgList.contains(rec.sbn.getPackageName())) {
7041 rec.setHidden(true);
7042 changedNotifications.add(rec);
7043 }
7044 }
7045
7046 mListeners.notifyHiddenLocked(changedNotifications);
7047 }
7048 }
7049
7050 @VisibleForTesting
7051 protected void unhideNotificationsForPackages(String[] pkgs) {
7052 synchronized (mNotificationLock) {
7053 List<String> pkgList = Arrays.asList(pkgs);
7054 List<NotificationRecord> changedNotifications = new ArrayList<>();
7055 int numNotifications = mNotificationList.size();
7056 for (int i = 0; i < numNotifications; i++) {
7057 NotificationRecord rec = mNotificationList.get(i);
7058 if (pkgList.contains(rec.sbn.getPackageName())) {
7059 rec.setHidden(false);
7060 changedNotifications.add(rec);
7061 }
7062 }
7063
7064 mListeners.notifyUnhiddenLocked(changedNotifications);
7065 }
7066 }
7067
Mike Lockwoodc22404a2009-12-02 11:15:02 -05007068 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007069 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05007070 updateLightsLocked();
7071 }
7072 }
John Spurlocke677d712014-02-13 12:52:19 -05007073
Geoffrey Pitsch27684152017-05-02 11:41:31 -04007074 protected boolean isCallingUidSystem() {
7075 final int uid = Binder.getCallingUid();
7076 return uid == Process.SYSTEM_UID;
7077 }
7078
7079 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04007080 final int appid = UserHandle.getAppId(uid);
7081 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
7082 }
John Spurlockb408e8e2014-04-23 21:12:45 -04007083
Geoffrey Pitsch27684152017-05-02 11:41:31 -04007084 // TODO: Most calls should probably move to isCallerSystem.
7085 protected boolean isCallerSystemOrPhone() {
7086 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04007087 }
7088
Julia Reynoldsb852e562017-06-06 16:14:18 -04007089 private void checkCallerIsSystemOrShell() {
7090 if (Binder.getCallingUid() == Process.SHELL_UID) {
7091 return;
7092 }
7093 checkCallerIsSystem();
7094 }
7095
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007096 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04007097 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04007098 return;
7099 }
7100 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
7101 }
7102
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04007103 private void checkCallerIsSystemOrSystemUiOrShell() {
7104 if (Binder.getCallingUid() == Process.SHELL_UID) {
7105 return;
7106 }
7107 if (isCallerSystemOrPhone()) {
7108 return;
7109 }
7110 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, null);
7111 }
7112
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05007113 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04007114 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04007115 return;
7116 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04007117 checkCallerIsSameApp(pkg);
7118 }
7119
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04007120 private boolean isCallerAndroid(String callingPkg, int uid) {
7121 return isUidSystemOrPhone(uid) && callingPkg != null
7122 && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg);
7123 }
7124
Brad Stenning8c991ea2018-07-31 13:33:01 -07007125 /**
7126 * Check if the notification is of a category type that is restricted to system use only,
7127 * if so throw SecurityException
7128 */
7129 private void checkRestrictedCategories(final Notification notification) {
7130 try {
7131 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) {
7132 return;
7133 }
7134 } catch (RemoteException re) {
Tony Mak180a9c42019-03-08 13:33:08 +00007135 if (DBG) Slog.e(TAG, "Unable to confirm if it's safe to skip category "
Brad Stenning8c991ea2018-07-31 13:33:01 -07007136 + "restrictions check thus the check will be done anyway");
7137 }
7138 if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category)
7139 || Notification.CATEGORY_CAR_WARNING.equals(notification.category)
7140 || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) {
7141 checkCallerIsSystem();
7142 }
7143 }
7144
Julia Reynoldsb6634872018-09-25 13:19:53 -04007145 @VisibleForTesting
Julia Reynolds268647a2018-10-25 16:54:27 -04007146 boolean isCallerInstantApp(int callingUid, int userId) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08007147 // System is always allowed to act for ephemeral apps.
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04007148 if (isUidSystemOrPhone(callingUid)) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08007149 return false;
7150 }
7151
Chad Brubaker6b68f102017-01-27 13:39:00 -08007152 try {
Julia Reynolds268647a2018-10-25 16:54:27 -04007153 final String[] pkgs = mPackageManager.getPackagesForUid(callingUid);
7154 if (pkgs == null) {
7155 throw new SecurityException("Unknown uid " + callingUid);
7156 }
7157 final String pkg = pkgs[0];
7158 mAppOps.checkPackage(callingUid, pkg);
7159
Julia Reynoldsb6634872018-09-25 13:19:53 -04007160 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId);
Chad Brubaker6b68f102017-01-27 13:39:00 -08007161 if (ai == null) {
7162 throw new SecurityException("Unknown package " + pkg);
7163 }
7164 return ai.isInstantApp();
7165 } catch (RemoteException re) {
Julia Reynolds268647a2018-10-25 16:54:27 -04007166 throw new SecurityException("Unknown uid " + callingUid, re);
Chad Brubaker6b68f102017-01-27 13:39:00 -08007167 }
Chad Brubaker6b68f102017-01-27 13:39:00 -08007168 }
7169
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05007170 private void checkCallerIsSameApp(String pkg) {
Julia Reynoldsb6634872018-09-25 13:19:53 -04007171 checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId());
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04007172 }
7173
Julia Reynoldsb6634872018-09-25 13:19:53 -04007174 private void checkCallerIsSameApp(String pkg, int uid, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04007175 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05007176 ApplicationInfo ai = mPackageManager.getApplicationInfo(
Julia Reynoldsb6634872018-09-25 13:19:53 -04007177 pkg, 0, userId);
Dan Sandler09afc2e2014-07-18 14:29:20 -04007178 if (ai == null) {
7179 throw new SecurityException("Unknown package " + pkg);
7180 }
John Spurlock7340fc82014-04-24 18:50:12 -04007181 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05007182 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04007183 + pkg + " which is owned by uid " + ai.uid);
7184 }
7185 } catch (RemoteException re) {
7186 throw new SecurityException("Unknown package " + pkg + "\n" + re);
7187 }
7188 }
7189
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04007190 private boolean isCallerSameApp(String pkg) {
7191 try {
7192 checkCallerIsSameApp(pkg);
7193 return true;
7194 } catch (SecurityException e) {
7195 return false;
7196 }
7197 }
7198
Julia Reynoldsb6634872018-09-25 13:19:53 -04007199 private boolean isCallerSameApp(String pkg, int uid, int userId) {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04007200 try {
Julia Reynoldsb6634872018-09-25 13:19:53 -04007201 checkCallerIsSameApp(pkg, uid, userId);
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04007202 return true;
7203 } catch (SecurityException e) {
7204 return false;
7205 }
7206 }
7207
John Spurlock32fe4c62014-10-02 12:16:02 -04007208 private static String callStateToString(int state) {
7209 switch (state) {
7210 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
7211 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
7212 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
7213 default: return "CALL_STATE_UNKNOWN_" + state;
7214 }
7215 }
7216
7217 private void listenForCallState() {
7218 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
7219 @Override
7220 public void onCallStateChanged(int state, String incomingNumber) {
7221 if (mCallState == state) return;
7222 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
7223 mCallState = state;
7224 }
7225 }, PhoneStateListener.LISTEN_CALL_STATE);
7226 }
7227
Christoph Studer05ad4822014-05-16 14:16:03 +02007228 /**
7229 * Generates a NotificationRankingUpdate from 'sbns', considering only
7230 * notifications visible to the given listener.
7231 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007232 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04007233 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04007234 final int N = mNotificationList.size();
7235 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02007236 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05007237 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04007238 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04007239 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05007240 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05007241 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05007242 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05007243 Bundle overridePeople = new Bundle();
7244 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05007245 Bundle showBadge = new Bundle();
Julia Reynolds503ed942017-10-04 16:04:56 -04007246 Bundle userSentiment = new Bundle();
Beverly5a20a5e2018-03-06 15:02:44 -05007247 Bundle hidden = new Bundle();
Gustav Sennton1463d832018-11-06 16:12:48 +00007248 Bundle systemGeneratedSmartActions = new Bundle();
Tony Makc9acf672018-07-20 13:58:24 +02007249 Bundle smartReplies = new Bundle();
Gus Prevas7306b902018-12-11 10:57:06 -05007250 Bundle lastAudiblyAlerted = new Bundle();
Gus Prevas9abc5062018-10-31 16:11:04 -04007251 Bundle noisy = new Bundle();
Julia Reynolds4509ce72019-01-31 13:12:43 -05007252 ArrayList<Boolean> canBubble = new ArrayList<>(N);
Chris Wren333a61c2014-05-28 16:40:57 -04007253 for (int i = 0; i < N; i++) {
7254 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02007255 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02007256 continue;
7257 }
Chris Wrenbdf33762015-12-04 15:50:51 -05007258 final String key = record.sbn.getKey();
7259 keys.add(key);
7260 importance.add(record.getImportance());
7261 if (record.getImportanceExplanation() != null) {
7262 explanation.putCharSequence(key, record.getImportanceExplanation());
7263 }
Chris Wren333a61c2014-05-28 16:40:57 -04007264 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05007265 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05007266
Christoph Studer05ad4822014-05-16 14:16:03 +02007267 }
Chris Wrenbdf33762015-12-04 15:50:51 -05007268 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04007269 if (record.getPackageVisibilityOverride()
7270 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05007271 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04007272 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04007273 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05007274 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05007275 overridePeople.putStringArrayList(key, record.getPeopleOverride());
7276 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05007277 showBadge.putBoolean(key, record.canShowBadge());
Julia Reynolds503ed942017-10-04 16:04:56 -04007278 userSentiment.putInt(key, record.getUserSentiment());
Beverly5a20a5e2018-03-06 15:02:44 -05007279 hidden.putBoolean(key, record.isHidden());
Gustav Sennton1463d832018-11-06 16:12:48 +00007280 systemGeneratedSmartActions.putParcelableArrayList(key,
7281 record.getSystemGeneratedSmartActions());
Tony Makc9acf672018-07-20 13:58:24 +02007282 smartReplies.putCharSequenceArrayList(key, record.getSmartReplies());
Gus Prevas7306b902018-12-11 10:57:06 -05007283 lastAudiblyAlerted.putLong(key, record.getLastAudiblyAlertedMs());
Gus Prevas9abc5062018-10-31 16:11:04 -04007284 noisy.putBoolean(key, record.getSound() != null || record.getVibration() != null);
Julia Reynolds4509ce72019-01-31 13:12:43 -05007285 canBubble.add(record.canBubble());
Christoph Studer05ad4822014-05-16 14:16:03 +02007286 }
Chris Wrenbdf33762015-12-04 15:50:51 -05007287 final int M = keys.size();
7288 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02007289 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05007290 int[] importanceAr = new int[M];
Julia Reynolds4509ce72019-01-31 13:12:43 -05007291 boolean[] canBubbleAr = new boolean[M];
Chris Wrenbdf33762015-12-04 15:50:51 -05007292 for (int i = 0; i < M; i++) {
7293 importanceAr[i] = importance.get(i);
Julia Reynolds4509ce72019-01-31 13:12:43 -05007294 canBubbleAr[i] = canBubble.get(i);
Chris Wrenbdf33762015-12-04 15:50:51 -05007295 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04007296 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05007297 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Tony Mak628cb932018-06-19 18:30:41 +01007298 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden,
Julia Reynolds4509ce72019-01-31 13:12:43 -05007299 systemGeneratedSmartActions, smartReplies, lastAudiblyAlerted, noisy,
7300 canBubbleAr);
Christoph Studer05ad4822014-05-16 14:16:03 +02007301 }
7302
Julia Reynoldsda781472017-04-12 09:41:16 -04007303 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007304 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04007305 mCompanionManager = getCompanionManager();
7306 }
7307 // Companion mgr doesn't exist on all device types
7308 if (mCompanionManager == null) {
7309 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007310 }
Julia Reynoldsda781472017-04-12 09:41:16 -04007311 long identity = Binder.clearCallingIdentity();
7312 try {
7313 List<String> associations = mCompanionManager.getAssociations(
7314 info.component.getPackageName(), info.userid);
7315 if (!ArrayUtils.isEmpty(associations)) {
7316 return true;
7317 }
7318 } catch (SecurityException se) {
7319 // Not a privileged listener
7320 } catch (RemoteException re) {
7321 Slog.e(TAG, "Cannot reach companion device service", re);
7322 } catch (Exception e) {
7323 Slog.e(TAG, "Cannot verify listener " + info, e);
7324 } finally {
7325 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007326 }
Julia Reynoldsda781472017-04-12 09:41:16 -04007327 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007328 }
7329
Julia Reynolds727a7282017-04-13 10:54:01 -04007330 protected ICompanionDeviceManager getCompanionManager() {
7331 return ICompanionDeviceManager.Stub.asInterface(
7332 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
7333 }
7334
Christoph Studercef37cf2014-07-25 14:18:17 +02007335 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
7336 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
7337 return false;
7338 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07007339 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02007340 return true;
7341 }
7342
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00007343 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Beverly2be7a052018-03-27 11:37:58 -04007344 final long identity = Binder.clearCallingIdentity();
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007345 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007346 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05007347 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007348 } catch (RemoteException re) {
7349 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00007350 } catch (IllegalArgumentException ex) {
7351 // Package not found.
7352 return false;
Beverly2be7a052018-03-27 11:37:58 -04007353 } finally {
7354 Binder.restoreCallingIdentity(identity);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007355 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007356 }
7357
Kristian Monsen30f59b22018-04-09 10:27:16 +02007358 @VisibleForTesting
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05007359 boolean canUseManagedServices(String pkg, Integer userId, String requiredPermission) {
Kristian Monsen30f59b22018-04-09 10:27:16 +02007360 boolean canUseManagedServices = !mActivityManager.isLowRamDevice()
Julia Reynoldse1816412017-10-24 10:39:11 -04007361 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
Kristian Monsen30f59b22018-04-09 10:27:16 +02007362
7363 for (String whitelisted : getContext().getResources().getStringArray(
7364 R.array.config_allowedManagedServicesOnLowRamDevices)) {
7365 if (whitelisted.equals(pkg)) {
7366 canUseManagedServices = true;
7367 }
7368 }
7369
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05007370 if (requiredPermission != null) {
7371 try {
7372 if (mPackageManager.checkPermission(requiredPermission, pkg, userId)
7373 != PackageManager.PERMISSION_GRANTED) {
7374 canUseManagedServices = false;
7375 }
7376 } catch (RemoteException e) {
Tony Mak180a9c42019-03-08 13:33:08 +00007377 Slog.e(TAG, "can't talk to pm", e);
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05007378 }
7379 }
7380
Kristian Monsen30f59b22018-04-09 10:27:16 +02007381 return canUseManagedServices;
Julia Reynoldse1816412017-10-24 10:39:11 -04007382 }
7383
Chris Wren47633422016-01-22 09:56:59 -05007384 private class TrimCache {
7385 StatusBarNotification heavy;
7386 StatusBarNotification sbnClone;
7387 StatusBarNotification sbnCloneLight;
7388
7389 TrimCache(StatusBarNotification sbn) {
7390 heavy = sbn;
7391 }
7392
7393 StatusBarNotification ForListener(ManagedServiceInfo info) {
7394 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
7395 if (sbnCloneLight == null) {
7396 sbnCloneLight = heavy.cloneLight();
7397 }
7398 return sbnCloneLight;
7399 } else {
7400 if (sbnClone == null) {
7401 sbnClone = heavy.clone();
7402 }
7403 return sbnClone;
7404 }
7405 }
7406 }
7407
Julia Reynolds77b2cc92016-11-08 14:41:09 -05007408 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04007409 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05007410
Tony Mak9a3c1f12019-03-04 16:04:42 +00007411 private static final String ATT_USER_SET = "user_set";
Julia Reynolds54c5fd12019-05-20 12:56:27 -04007412 private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "q_allowed_adjustments";
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007413 private static final String ATT_TYPES = "types";
Tony Mak9a3c1f12019-03-04 16:04:42 +00007414
7415 private final Object mLock = new Object();
7416
7417 @GuardedBy("mLock")
7418 private ArrayMap<Integer, Boolean> mUserSetMap = new ArrayMap<>();
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04007419 private Set<String> mAllowedAdjustments = new ArraySet<>();
Tony Mak9a3c1f12019-03-04 16:04:42 +00007420
Julia Reynolds7380d872018-01-12 10:28:26 -05007421 public NotificationAssistants(Context context, Object lock, UserProfiles up,
7422 IPackageManager pm) {
7423 super(context, lock, up, pm);
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007424
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007425 // Add all default allowed adjustment types. Will be overwritten by values in xml,
7426 // if they exist
7427 for (int i = 0; i < DEFAULT_ALLOWED_ADJUSTMENTS.length; i++) {
7428 mAllowedAdjustments.add(DEFAULT_ALLOWED_ADJUSTMENTS[i]);
7429 }
Chris Wren51017d02015-12-15 15:34:46 -05007430 }
7431
7432 @Override
7433 protected Config getConfig() {
7434 Config c = new Config();
Julia Reynolds503ed942017-10-04 16:04:56 -04007435 c.caption = "notification assistant";
Julia Reynolds77b2cc92016-11-08 14:41:09 -05007436 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04007437 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05007438 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
7439 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05007440 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05007441 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05007442 return c;
7443 }
7444
7445 @Override
7446 protected IInterface asInterface(IBinder binder) {
7447 return INotificationListener.Stub.asInterface(binder);
7448 }
7449
7450 @Override
7451 protected boolean checkType(IInterface service) {
7452 return service instanceof INotificationListener;
7453 }
7454
7455 @Override
7456 protected void onServiceAdded(ManagedServiceInfo info) {
7457 mListeners.registerGuestService(info);
7458 }
7459
7460 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04007461 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05007462 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
7463 mListeners.unregisterService(removed.service, removed.userid);
7464 }
Chris Wren47633422016-01-22 09:56:59 -05007465
Julia Reynoldsef934fd2018-02-01 14:39:17 -05007466 @Override
7467 public void onUserUnlocked(int user) {
7468 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04007469 // force rebind the assistant, as it might be keeping its own state in user locked
7470 // storage
7471 rebindServices(true, user);
Julia Reynoldsef934fd2018-02-01 14:39:17 -05007472 }
7473
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05007474 @Override
7475 protected String getRequiredPermission() {
Julia Reynoldscbc45e72019-03-07 12:31:52 -05007476 // only signature/privileged apps can be bound.
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05007477 return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE;
7478 }
7479
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007480 @Override
7481 protected void writeExtraXmlTags(XmlSerializer out) throws IOException {
7482 synchronized (mLock) {
7483 out.startTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
7484 out.attribute(null, ATT_TYPES, TextUtils.join(",", mAllowedAdjustments));
7485 out.endTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
7486 }
7487 }
7488
7489 @Override
7490 protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {
7491 if (TAG_ALLOWED_ADJUSTMENT_TYPES.equals(tag)) {
7492 final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES);
Julia Reynolds25692c42019-05-03 15:01:24 -04007493 synchronized (mLock) {
7494 mAllowedAdjustments.clear();
7495 if (!TextUtils.isEmpty(types)) {
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007496 mAllowedAdjustments.addAll(Arrays.asList(types.split(",")));
7497 }
7498 }
7499 }
7500 }
7501
7502 protected void allowAdjustmentType(String type) {
7503 synchronized (mLock) {
7504 mAllowedAdjustments.add(type);
7505 }
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04007506 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7507 mHandler.post(() -> notifyCapabilitiesChanged(info));
7508 }
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007509 }
7510
7511 protected void disallowAdjustmentType(String type) {
7512 synchronized (mLock) {
7513 mAllowedAdjustments.remove(type);
7514 }
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04007515 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7516 mHandler.post(() -> notifyCapabilitiesChanged(info));
7517 }
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007518 }
7519
Julia Reynolds088c4482019-04-10 12:43:27 -04007520 protected List<String> getAllowedAssistantAdjustments() {
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007521 synchronized (mLock) {
7522 List<String> types = new ArrayList<>();
7523 types.addAll(mAllowedAdjustments);
7524 return types;
7525 }
7526 }
7527
Julia Reynolds418a8ff2019-03-21 10:45:10 -04007528 protected boolean isAdjustmentAllowed(String type) {
7529 synchronized (mLock) {
7530 return mAllowedAdjustments.contains(type);
7531 }
7532 }
7533
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04007534 protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
7535 // There should be only one, but it's a list, so while we enforce
7536 // singularity elsewhere, we keep it general here, to avoid surprises.
7537 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7538 ArrayList<String> keys = new ArrayList<>(records.size());
7539 for (NotificationRecord r : records) {
7540 boolean sbnVisible = isVisibleToListener(r.sbn, info)
7541 && info.isSameUser(r.getUserId());
7542 if (sbnVisible) {
7543 keys.add(r.getKey());
7544 }
7545 }
7546
7547 if (!keys.isEmpty()) {
7548 mHandler.post(() -> notifySeen(info, keys));
7549 }
7550 }
7551 }
7552
Tony Mak9a3c1f12019-03-04 16:04:42 +00007553 boolean hasUserSet(int userId) {
7554 synchronized (mLock) {
7555 return mUserSetMap.getOrDefault(userId, false);
7556 }
7557 }
7558
7559 void setUserSet(int userId, boolean set) {
7560 synchronized (mLock) {
7561 mUserSetMap.put(userId, set);
7562 }
7563 }
7564
7565 @Override
7566 protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException {
7567 out.attribute(null, ATT_USER_SET, Boolean.toString(hasUserSet(userId)));
7568 }
7569
7570 @Override
7571 protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
7572 throws IOException {
7573 boolean userSet = XmlUtils.readBooleanAttribute(parser, ATT_USER_SET, false);
7574 setUserSet(userId, userSet);
7575 }
7576
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04007577 private void notifyCapabilitiesChanged(final ManagedServiceInfo info) {
7578 final INotificationListener assistant = (INotificationListener) info.service;
7579 try {
Julia Reynolds088c4482019-04-10 12:43:27 -04007580 assistant.onAllowedAdjustmentsChanged();
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04007581 } catch (RemoteException ex) {
7582 Slog.e(TAG, "unable to notify assistant (capabilities): " + assistant, ex);
7583 }
7584 }
7585
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04007586 private void notifySeen(final ManagedServiceInfo info,
7587 final ArrayList<String> keys) {
7588 final INotificationListener assistant = (INotificationListener) info.service;
7589 try {
7590 assistant.onNotificationsSeen(keys);
7591 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007592 Slog.e(TAG, "unable to notify assistant (seen): " + assistant, ex);
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04007593 }
7594 }
7595
Tony Makeda84a72018-11-19 17:01:32 +00007596 @GuardedBy("mNotificationLock")
7597 private void onNotificationEnqueuedLocked(final NotificationRecord r) {
Tony Mak180a9c42019-03-08 13:33:08 +00007598 final boolean debug = isVerboseLogEnabled();
7599 if (debug) {
7600 Slog.v(TAG, "onNotificationEnqueuedLocked() called with: r = [" + r + "]");
7601 }
Chris Wren47633422016-01-22 09:56:59 -05007602 final StatusBarNotification sbn = r.sbn;
Tony Makeda84a72018-11-19 17:01:32 +00007603 notifyAssistantLocked(
7604 sbn,
7605 true /* sameUserOnly */,
7606 (assistant, sbnHolder) -> {
7607 try {
Tony Mak180a9c42019-03-08 13:33:08 +00007608 if (debug) {
7609 Slog.v(TAG,
7610 "calling onNotificationEnqueuedWithChannel " + sbnHolder);
7611 }
Tony Makeda84a72018-11-19 17:01:32 +00007612 assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel());
7613 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007614 Slog.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Tony Makeda84a72018-11-19 17:01:32 +00007615 }
7616 });
Chris Wren47633422016-01-22 09:56:59 -05007617 }
7618
Tony Makeda84a72018-11-19 17:01:32 +00007619 @GuardedBy("mNotificationLock")
7620 void notifyAssistantExpansionChangedLocked(
7621 final StatusBarNotification sbn,
7622 final boolean isUserAction,
7623 final boolean isExpanded) {
7624 final String key = sbn.getKey();
7625 notifyAssistantLocked(
7626 sbn,
7627 false /* sameUserOnly */,
7628 (assistant, sbnHolder) -> {
7629 try {
7630 assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded);
7631 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007632 Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
Tony Makeda84a72018-11-19 17:01:32 +00007633 }
7634 });
Chris Wren47633422016-01-22 09:56:59 -05007635 }
7636
Tony Makeda84a72018-11-19 17:01:32 +00007637 @GuardedBy("mNotificationLock")
7638 void notifyAssistantNotificationDirectReplyLocked(
7639 final StatusBarNotification sbn) {
7640 final String key = sbn.getKey();
7641 notifyAssistantLocked(
7642 sbn,
7643 false /* sameUserOnly */,
7644 (assistant, sbnHolder) -> {
7645 try {
7646 assistant.onNotificationDirectReply(key);
7647 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007648 Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
Tony Makeda84a72018-11-19 17:01:32 +00007649 }
7650 });
7651 }
7652
Tony Mak29996702018-11-26 16:23:34 +00007653 @GuardedBy("mNotificationLock")
7654 void notifyAssistantSuggestedReplySent(
7655 final StatusBarNotification sbn, CharSequence reply, boolean generatedByAssistant) {
7656 final String key = sbn.getKey();
7657 notifyAssistantLocked(
7658 sbn,
7659 false /* sameUserOnly */,
7660 (assistant, sbnHolder) -> {
7661 try {
7662 assistant.onSuggestedReplySent(
7663 key,
7664 reply,
7665 generatedByAssistant
7666 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
7667 : NotificationAssistantService.SOURCE_FROM_APP);
7668 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007669 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
Tony Mak29996702018-11-26 16:23:34 +00007670 }
7671 });
7672 }
7673
Tony Mak7d4b3a52018-11-27 17:29:36 +00007674 @GuardedBy("mNotificationLock")
7675 void notifyAssistantActionClicked(
7676 final StatusBarNotification sbn, int actionIndex, Notification.Action action,
7677 boolean generatedByAssistant) {
7678 final String key = sbn.getKey();
7679 notifyAssistantLocked(
7680 sbn,
7681 false /* sameUserOnly */,
7682 (assistant, sbnHolder) -> {
7683 try {
7684 assistant.onActionClicked(
7685 key,
7686 action,
7687 generatedByAssistant
7688 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
7689 : NotificationAssistantService.SOURCE_FROM_APP);
7690 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007691 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
Tony Mak7d4b3a52018-11-27 17:29:36 +00007692 }
7693 });
7694 }
Tony Makeda84a72018-11-19 17:01:32 +00007695
Julia Reynolds79672302017-01-12 08:30:16 -05007696 /**
7697 * asynchronously notify the assistant that a notification has been snoozed until a
7698 * context
7699 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007700 @GuardedBy("mNotificationLock")
Tony Makeda84a72018-11-19 17:01:32 +00007701 private void notifyAssistantSnoozedLocked(
7702 final StatusBarNotification sbn, final String snoozeCriterionId) {
7703 notifyAssistantLocked(
7704 sbn,
7705 false /* sameUserOnly */,
7706 (assistant, sbnHolder) -> {
Julia Reynolds79672302017-01-12 08:30:16 -05007707 try {
7708 assistant.onNotificationSnoozedUntilContext(
7709 sbnHolder, snoozeCriterionId);
7710 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007711 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
Julia Reynolds79672302017-01-12 08:30:16 -05007712 }
Tony Makeda84a72018-11-19 17:01:32 +00007713 });
7714 }
7715
7716 /**
7717 * Notifies the assistant something about the specified notification, only assistant
7718 * that is visible to the notification will be notified.
7719 *
7720 * @param sbn the notification object that the update is about.
7721 * @param sameUserOnly should the update be sent to the assistant in the same user only.
7722 * @param callback the callback that provides the assistant to be notified, executed
7723 * in WorkerHandler.
7724 */
7725 @GuardedBy("mNotificationLock")
7726 private void notifyAssistantLocked(
7727 final StatusBarNotification sbn,
7728 boolean sameUserOnly,
7729 BiConsumer<INotificationListener, StatusBarNotificationHolder> callback) {
7730 TrimCache trimCache = new TrimCache(sbn);
7731 // There should be only one, but it's a list, so while we enforce
7732 // singularity elsewhere, we keep it general here, to avoid surprises.
Tony Mak180a9c42019-03-08 13:33:08 +00007733
7734 final boolean debug = isVerboseLogEnabled();
7735 if (debug) {
7736 Slog.v(TAG,
7737 "notifyAssistantLocked() called with: sbn = [" + sbn + "], sameUserOnly = ["
7738 + sameUserOnly + "], callback = [" + callback + "]");
7739 }
Tony Makeda84a72018-11-19 17:01:32 +00007740 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7741 boolean sbnVisible = isVisibleToListener(sbn, info)
7742 && (!sameUserOnly || info.isSameUser(sbn.getUserId()));
Tony Mak180a9c42019-03-08 13:33:08 +00007743 if (debug) {
7744 Slog.v(TAG, "notifyAssistantLocked info=" + info + " snbVisible=" + sbnVisible);
7745 }
Tony Makeda84a72018-11-19 17:01:32 +00007746 if (!sbnVisible) {
7747 continue;
7748 }
7749 final INotificationListener assistant = (INotificationListener) info.service;
7750 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
7751 final StatusBarNotificationHolder sbnHolder =
7752 new StatusBarNotificationHolder(sbnToPost);
7753 mHandler.post(() -> callback.accept(assistant, sbnHolder));
Julia Reynolds79672302017-01-12 08:30:16 -05007754 }
7755 }
7756
Chris Wren47633422016-01-22 09:56:59 -05007757 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04007758 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05007759 }
Julia Reynolds7380d872018-01-12 10:28:26 -05007760
Tony Mak9a3c1f12019-03-04 16:04:42 +00007761 protected void resetDefaultAssistantsIfNecessary() {
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04007762 final List<UserInfo> activeUsers = mUm.getUsers(true);
7763 for (UserInfo userInfo : activeUsers) {
7764 int userId = userInfo.getUserHandle().getIdentifier();
Tony Mak9a3c1f12019-03-04 16:04:42 +00007765 if (!hasUserSet(userId)) {
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04007766 Slog.d(TAG, "Approving default notification assistant for user " + userId);
Tony Mak9a3c1f12019-03-04 16:04:42 +00007767 setDefaultAssistantForUser(userId);
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04007768 }
Julia Reynolds7380d872018-01-12 10:28:26 -05007769 }
7770 }
Fabian Kozynskid9425662019-01-29 13:08:30 -05007771
7772 @Override
7773 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
7774 boolean isPrimary, boolean enabled) {
7775 // Ensures that only one component is enabled at a time
7776 if (enabled) {
7777 List<ComponentName> allowedComponents = getAllowedComponents(userId);
7778 if (!allowedComponents.isEmpty()) {
7779 ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents);
7780 if (currentComponent.flattenToString().equals(pkgOrComponent)) return;
Tony Mak9a3c1f12019-03-04 16:04:42 +00007781 setNotificationAssistantAccessGrantedForUserInternal(
7782 currentComponent, userId, false);
Fabian Kozynskid9425662019-01-29 13:08:30 -05007783 }
7784 }
7785 super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled);
7786 }
Tony Mak9a3c1f12019-03-04 16:04:42 +00007787
7788 @Override
7789 public void dump(PrintWriter pw, DumpFilter filter) {
7790 super.dump(pw, filter);
7791 pw.println(" Has user set:");
7792 synchronized (mLock) {
7793 Set<Integer> userIds = mUserSetMap.keySet();
7794 for (int userId : userIds) {
7795 pw.println(" userId=" + userId + " value=" + mUserSetMap.get(userId));
7796 }
7797 }
7798 }
Tony Mak180a9c42019-03-08 13:33:08 +00007799
7800 private boolean isVerboseLogEnabled() {
7801 return Log.isLoggable("notification_assistant", Log.VERBOSE);
7802 }
Chris Wren51017d02015-12-15 15:34:46 -05007803 }
7804
John Spurlock7340fc82014-04-24 18:50:12 -04007805 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04007806 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04007807
Christoph Studerb82bc782014-08-20 14:29:43 +02007808 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
7809
Julia Reynoldsb852e562017-06-06 16:14:18 -04007810 public NotificationListeners(IPackageManager pm) {
7811 super(getContext(), mNotificationLock, mUserProfiles, pm);
7812
John Spurlock7340fc82014-04-24 18:50:12 -04007813 }
7814
7815 @Override
Amith Yamasanie5bfeee2018-09-05 18:52:35 -07007816 protected int getBindFlags() {
7817 // Most of the same flags as the base, but also add BIND_ADJUST_BELOW_PERCEPTIBLE
7818 // because too many 3P apps could be kept in memory as notification listeners and
7819 // cause extreme memory pressure.
7820 // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation.
7821 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
7822 | BIND_ADJUST_BELOW_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
7823 }
7824
7825 @Override
John Spurlock7340fc82014-04-24 18:50:12 -04007826 protected Config getConfig() {
7827 Config c = new Config();
7828 c.caption = "notification listener";
7829 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04007830 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04007831 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
7832 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
7833 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
7834 c.clientLabel = R.string.notification_listener_binding_label;
7835 return c;
7836 }
7837
7838 @Override
7839 protected IInterface asInterface(IBinder binder) {
7840 return INotificationListener.Stub.asInterface(binder);
7841 }
7842
7843 @Override
Chris Wren51017d02015-12-15 15:34:46 -05007844 protected boolean checkType(IInterface service) {
7845 return service instanceof INotificationListener;
7846 }
7847
7848 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04007849 public void onServiceAdded(ManagedServiceInfo info) {
7850 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04007851 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007852 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04007853 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02007854 }
John Spurlock7340fc82014-04-24 18:50:12 -04007855 try {
Chris Wren333a61c2014-05-28 16:40:57 -04007856 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04007857 } catch (RemoteException e) {
7858 // we tried
7859 }
7860 }
7861
John Spurlock1fa865f2014-07-21 14:56:39 -04007862 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04007863 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04007864 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07007865 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04007866 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01007867 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04007868 }
Christoph Studerb82bc782014-08-20 14:29:43 +02007869 mLightTrimListeners.remove(removed);
7870 }
7871
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05007872 @Override
7873 protected String getRequiredPermission() {
7874 return null;
7875 }
7876
Julia Reynolds88860ce2017-06-01 16:55:49 -04007877 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02007878 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
7879 if (trim == TRIM_LIGHT) {
7880 mLightTrimListeners.add(info);
7881 } else {
7882 mLightTrimListeners.remove(info);
7883 }
7884 }
7885
7886 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
7887 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04007888 }
7889
Julia Reynolds12ad7ca2019-01-28 09:29:16 -05007890 public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
7891 for (final ManagedServiceInfo info : getServices()) {
7892 mHandler.post(() -> {
7893 final INotificationListener listener = (INotificationListener) info.service;
7894 try {
7895 listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
7896 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007897 Slog.e(TAG, "unable to notify listener "
Julia Reynolds12ad7ca2019-01-28 09:29:16 -05007898 + "(hideSilentStatusIcons): " + listener, ex);
7899 }
7900 });
7901 }
7902 }
7903
John Spurlock7340fc82014-04-24 18:50:12 -04007904 /**
7905 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02007906 *
7907 * <p>
7908 * Also takes care of removing a notification that has been visible to a listener before,
7909 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04007910 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007911 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007912 public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
7913 notifyPostedLocked(r, old, true);
Beverly5a20a5e2018-03-06 15:02:44 -05007914 }
7915
7916 /**
7917 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
7918 * targetting <= O_MR1
7919 */
7920 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007921 private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
Beverly5a20a5e2018-03-06 15:02:44 -05007922 boolean notifyAllListeners) {
Christoph Studerb82bc782014-08-20 14:29:43 +02007923 // Lazily initialized snapshots of the notification.
Julia Reynoldse0d711f2017-09-01 08:50:47 -04007924 StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007925 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Chris Wren47633422016-01-22 09:56:59 -05007926 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02007927
Julia Reynolds00314d92017-04-14 10:01:24 -04007928 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02007929 boolean sbnVisible = isVisibleToListener(sbn, info);
7930 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
7931 // This notification hasn't been and still isn't visible -> ignore.
7932 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02007933 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04007934 }
Beverly5a20a5e2018-03-06 15:02:44 -05007935 // If the notification is hidden, don't notifyPosted listeners targeting < P.
7936 // Instead, those listeners will receive notifyPosted when the notification is
7937 // unhidden.
7938 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
7939 continue;
7940 }
7941
7942 // If we shouldn't notify all listeners, this means the hidden state of
7943 // a notification was changed. Don't notifyPosted listeners targeting >= P.
7944 // Instead, those listeners will receive notifyRankingUpdate.
7945 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
7946 continue;
7947 }
7948
Chris Wren333a61c2014-05-28 16:40:57 -04007949 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02007950
7951 // This notification became invisible -> remove the old one.
7952 if (oldSbnVisible && !sbnVisible) {
7953 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
7954 mHandler.post(new Runnable() {
7955 @Override
7956 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04007957 notifyRemoved(
7958 info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02007959 }
7960 });
Christoph Studer05ad4822014-05-16 14:16:03 +02007961 continue;
7962 }
Christoph Studercef37cf2014-07-25 14:18:17 +02007963
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007964 // Grant access before listener is notified
7965 final int targetUserId = (info.userid == UserHandle.USER_ALL)
7966 ? UserHandle.USER_SYSTEM : info.userid;
7967 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04007968
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007969 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02007970 mHandler.post(new Runnable() {
7971 @Override
7972 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02007973 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02007974 }
7975 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00007976 }
7977 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00007978
John Spurlock7340fc82014-04-24 18:50:12 -04007979 /**
7980 * asynchronously notify all listeners about a removed notification
7981 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007982 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05007983 public void notifyRemovedLocked(NotificationRecord r, int reason,
Julia Reynolds503ed942017-10-04 16:04:56 -04007984 NotificationStats notificationStats) {
Beverly5a20a5e2018-03-06 15:02:44 -05007985 final StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007986
John Spurlock7340fc82014-04-24 18:50:12 -04007987 // make a copy in case changes are made to the underlying Notification object
7988 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
7989 // notification
7990 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04007991 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02007992 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02007993 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04007994 }
Beverly5a20a5e2018-03-06 15:02:44 -05007995
7996 // don't notifyRemoved for listeners targeting < P
7997 // if not for reason package suspended
7998 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
7999 && info.targetSdkVersion < Build.VERSION_CODES.P) {
8000 continue;
8001 }
8002
8003 // don't notifyRemoved for listeners targeting >= P
8004 // if the reason is package suspended
8005 if (reason == REASON_PACKAGE_SUSPENDED
8006 && info.targetSdkVersion >= Build.VERSION_CODES.P) {
8007 continue;
8008 }
8009
Julia Reynolds503ed942017-10-04 16:04:56 -04008010 // Only assistants can get stats
8011 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
8012 ? notificationStats : null;
Chris Wren333a61c2014-05-28 16:40:57 -04008013 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02008014 mHandler.post(new Runnable() {
8015 @Override
8016 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04008017 notifyRemoved(info, sbnLight, update, stats, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02008018 }
8019 });
Chris Wrenf9536642014-04-17 10:01:54 -04008020 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06008021
8022 // Revoke access after all listeners have been updated
8023 mHandler.post(() -> {
8024 updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM);
8025 });
Chris Wrenf9536642014-04-17 10:01:54 -04008026 }
8027
8028 /**
Beverly5a20a5e2018-03-06 15:02:44 -05008029 * Asynchronously notify all listeners about a reordering of notifications
8030 * unless changedHiddenNotifications is populated.
8031 * If changedHiddenNotifications is populated, there was a change in the hidden state
8032 * of the notifications. In this case, we only send updates to listeners that
8033 * target >= P.
Chris Wrenf9536642014-04-17 10:01:54 -04008034 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04008035 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05008036 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
8037 boolean isHiddenRankingUpdate = changedHiddenNotifications != null
8038 && changedHiddenNotifications.size() > 0;
8039
Julia Reynolds00314d92017-04-14 10:01:24 -04008040 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02008041 if (!serviceInfo.isEnabledForCurrentProfiles()) {
8042 continue;
8043 }
Beverly5a20a5e2018-03-06 15:02:44 -05008044
8045 boolean notifyThisListener = false;
8046 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
8047 Build.VERSION_CODES.P) {
8048 for (NotificationRecord rec : changedHiddenNotifications) {
8049 if (isVisibleToListener(rec.sbn, serviceInfo)) {
8050 notifyThisListener = true;
8051 break;
8052 }
John Spurlock7340fc82014-04-24 18:50:12 -04008053 }
Beverly5a20a5e2018-03-06 15:02:44 -05008054 }
8055
8056 if (notifyThisListener || !isHiddenRankingUpdate) {
8057 final NotificationRankingUpdate update = makeRankingUpdateLocked(
8058 serviceInfo);
8059
8060 mHandler.post(new Runnable() {
8061 @Override
8062 public void run() {
8063 notifyRankingUpdate(serviceInfo, update);
8064 }
8065 });
8066 }
Kenny Guya263e4e2014-03-03 18:24:03 +00008067 }
Kenny Guya263e4e2014-03-03 18:24:03 +00008068 }
Kenny Guya263e4e2014-03-03 18:24:03 +00008069
Julia Reynolds88860ce2017-06-01 16:55:49 -04008070 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04008071 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04008072 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04008073 if (!serviceInfo.isEnabledForCurrentProfiles()) {
8074 continue;
8075 }
8076 mHandler.post(new Runnable() {
8077 @Override
8078 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04008079 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04008080 }
8081 });
8082 }
8083 }
8084
Beverly5a20a5e2018-03-06 15:02:44 -05008085 /**
8086 * asynchronously notify relevant listeners their notification is hidden
8087 * NotificationListenerServices that target P+:
8088 * NotificationListenerService#notifyRankingUpdateLocked()
8089 * NotificationListenerServices that target <= P:
8090 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
8091 */
8092 @GuardedBy("mNotificationLock")
8093 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
8094 if (changedNotifications == null || changedNotifications.size() == 0) {
8095 return;
8096 }
8097
8098 notifyRankingUpdateLocked(changedNotifications);
8099
8100 // for listeners that target < P, notifyRemoveLocked
8101 int numChangedNotifications = changedNotifications.size();
8102 for (int i = 0; i < numChangedNotifications; i++) {
8103 NotificationRecord rec = changedNotifications.get(i);
8104 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
8105 }
8106 }
8107
8108 /**
8109 * asynchronously notify relevant listeners their notification is unhidden
8110 * NotificationListenerServices that target P+:
8111 * NotificationListenerService#notifyRankingUpdateLocked()
8112 * NotificationListenerServices that target <= P:
8113 * NotificationListeners#notifyPostedLocked()
8114 */
8115 @GuardedBy("mNotificationLock")
8116 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
8117 if (changedNotifications == null || changedNotifications.size() == 0) {
8118 return;
8119 }
8120
8121 notifyRankingUpdateLocked(changedNotifications);
8122
8123 // for listeners that target < P, notifyPostedLocked
8124 int numChangedNotifications = changedNotifications.size();
8125 for (int i = 0; i < numChangedNotifications; i++) {
8126 NotificationRecord rec = changedNotifications.get(i);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06008127 mListeners.notifyPostedLocked(rec, rec, false);
Beverly5a20a5e2018-03-06 15:02:44 -05008128 }
8129 }
8130
Christoph Studer85a384b2014-08-27 20:16:15 +02008131 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04008132 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02008133 if (!serviceInfo.isEnabledForCurrentProfiles()) {
8134 continue;
8135 }
8136 mHandler.post(new Runnable() {
8137 @Override
8138 public void run() {
8139 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
8140 }
8141 });
8142 }
8143 }
8144
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04008145 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008146 final NotificationChannel channel, final int modificationType) {
8147 if (channel == null) {
8148 return;
8149 }
8150 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04008151 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008152 continue;
8153 }
Julia Reynolds018aa622017-04-20 11:31:30 -04008154
Eugene Suslaa25d17f2017-08-24 11:28:08 -07008155 BackgroundThread.getHandler().post(() -> {
8156 if (hasCompanionDevice(serviceInfo)) {
8157 notifyNotificationChannelChanged(
8158 serviceInfo, pkg, user, channel, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04008159 }
8160 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008161 }
8162 }
8163
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04008164 protected void notifyNotificationChannelGroupChanged(
8165 final String pkg, final UserHandle user, final NotificationChannelGroup group,
8166 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008167 if (group == null) {
8168 return;
8169 }
8170 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04008171 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008172 continue;
8173 }
Julia Reynolds018aa622017-04-20 11:31:30 -04008174
Eugene Suslaa25d17f2017-08-24 11:28:08 -07008175 BackgroundThread.getHandler().post(() -> {
8176 if (hasCompanionDevice(serviceInfo)) {
8177 notifyNotificationChannelGroupChanged(
8178 serviceInfo, pkg, user, group, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04008179 }
8180 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008181 }
8182 }
8183
Christoph Studercef37cf2014-07-25 14:18:17 +02008184 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02008185 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04008186 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07008187 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04008188 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07008189 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04008190 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008191 Slog.e(TAG, "unable to notify listener (posted): " + listener, ex);
John Spurlock7340fc82014-04-24 18:50:12 -04008192 }
8193 }
8194
Christoph Studercef37cf2014-07-25 14:18:17 +02008195 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds503ed942017-10-04 16:04:56 -04008196 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04008197 if (!info.enabledAndUserMatches(sbn.getUserId())) {
8198 return;
8199 }
Christoph Studer05ad4822014-05-16 14:16:03 +02008200 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07008201 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04008202 try {
Julia Reynolds503ed942017-10-04 16:04:56 -04008203 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04008204 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008205 Slog.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04008206 }
Kenny Guya263e4e2014-03-03 18:24:03 +00008207 }
Chris Wrenf9536642014-04-17 10:01:54 -04008208
Christoph Studer05ad4822014-05-16 14:16:03 +02008209 private void notifyRankingUpdate(ManagedServiceInfo info,
8210 NotificationRankingUpdate rankingUpdate) {
8211 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04008212 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02008213 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04008214 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008215 Slog.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
Chris Wrenf9536642014-04-17 10:01:54 -04008216 }
8217 }
John Spurlock1fa865f2014-07-21 14:56:39 -04008218
John Spurlockd8afe3c2014-08-01 14:04:07 -04008219 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04008220 final INotificationListener listener = (INotificationListener) info.service;
8221 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04008222 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04008223 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008224 Slog.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04008225 }
8226 }
Justin Koh38156c52014-06-04 13:57:49 -07008227
Christoph Studer85a384b2014-08-27 20:16:15 +02008228 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
8229 int interruptionFilter) {
8230 final INotificationListener listener = (INotificationListener) info.service;
8231 try {
8232 listener.onInterruptionFilterChanged(interruptionFilter);
8233 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008234 Slog.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
Christoph Studer85a384b2014-08-27 20:16:15 +02008235 }
8236 }
8237
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008238 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04008239 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008240 final int modificationType) {
8241 final INotificationListener listener = (INotificationListener) info.service;
8242 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04008243 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008244 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008245 Slog.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008246 }
8247 }
8248
8249 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04008250 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008251 final int modificationType) {
8252 final INotificationListener listener = (INotificationListener) info.service;
8253 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04008254 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008255 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008256 Slog.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008257 }
8258 }
8259
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05008260 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07008261 if (packageName == null) {
8262 return false;
8263 }
8264 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05008265 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04008266 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07008267 if (packageName.equals(serviceInfo.component.getPackageName())) {
8268 return true;
8269 }
8270 }
8271 }
8272 return false;
8273 }
Kenny Guya263e4e2014-03-03 18:24:03 +00008274 }
John Spurlock25e2d242014-06-27 13:58:23 -04008275
Julia Reynolds0c245002019-03-27 16:10:11 -04008276 class RoleObserver implements OnRoleHoldersChangedListener {
8277 // Role name : user id : list of approved packages
8278 private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps;
8279
8280 private final RoleManager mRm;
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008281 private final IPackageManager mPm;
Julia Reynolds0c245002019-03-27 16:10:11 -04008282 private final Executor mExecutor;
8283
8284 RoleObserver(@NonNull RoleManager roleManager,
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008285 @NonNull IPackageManager pkgMgr,
Julia Reynolds0c245002019-03-27 16:10:11 -04008286 @NonNull @CallbackExecutor Executor executor) {
8287 mRm = roleManager;
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008288 mPm = pkgMgr;
Julia Reynolds0c245002019-03-27 16:10:11 -04008289 mExecutor = executor;
8290 }
8291
8292 public void init() {
8293 List<UserInfo> users = mUm.getUsers();
8294 mNonBlockableDefaultApps = new ArrayMap<>();
8295 for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
8296 final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>();
8297 mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList);
8298 for (int j = 0; j < users.size(); j++) {
8299 Integer userId = users.get(j).getUserHandle().getIdentifier();
8300 ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser(
8301 NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId)));
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008302 ArraySet<Pair<String, Integer>> approvedAppUids = new ArraySet<>();
8303 for (String pkg : approvedForUserId) {
8304 approvedAppUids.add(new Pair(pkg, getUidForPackage(pkg, userId)));
8305 }
Julia Reynolds0c245002019-03-27 16:10:11 -04008306 userToApprovedList.put(userId, approvedForUserId);
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008307 mPreferencesHelper.updateDefaultApps(userId, null, approvedAppUids);
Julia Reynolds0c245002019-03-27 16:10:11 -04008308 }
8309 }
8310
8311 mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);
8312 }
8313
8314 @VisibleForTesting
8315 public boolean isApprovedPackageForRoleForUser(String role, String pkg, int userId) {
8316 return mNonBlockableDefaultApps.get(role).get(userId).contains(pkg);
8317 }
8318
8319 /**
8320 * Convert the assistant-role holder into settings. The rest of the system uses the
8321 * settings.
8322 *
8323 * @param roleName the name of the role whose holders are changed
8324 * @param user the user for this role holder change
8325 */
8326 @Override
8327 public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
8328 // we only care about a couple of the roles they'll tell us about
8329 boolean relevantChange = false;
8330 for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
8331 if (NON_BLOCKABLE_DEFAULT_ROLES[i].equals(roleName)) {
8332 relevantChange = true;
8333 break;
8334 }
8335 }
8336
8337 if (!relevantChange) {
8338 return;
8339 }
8340
8341 ArraySet<String> roleHolders = new ArraySet<>(mRm.getRoleHoldersAsUser(roleName, user));
8342
8343 // find the diff
8344 ArrayMap<Integer, ArraySet<String>> prevApprovedForRole =
8345 mNonBlockableDefaultApps.getOrDefault(roleName, new ArrayMap<>());
8346 ArraySet<String> previouslyApproved =
8347 prevApprovedForRole.getOrDefault(user.getIdentifier(), new ArraySet<>());
8348
8349 ArraySet<String> toRemove = new ArraySet<>();
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008350 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
Julia Reynolds0c245002019-03-27 16:10:11 -04008351
8352 for (String previous : previouslyApproved) {
8353 if (!roleHolders.contains(previous)) {
8354 toRemove.add(previous);
8355 }
8356 }
8357 for (String nowApproved : roleHolders) {
8358 if (!previouslyApproved.contains(nowApproved)) {
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008359 toAdd.add(new Pair(nowApproved,
8360 getUidForPackage(nowApproved, user.getIdentifier())));
Julia Reynolds0c245002019-03-27 16:10:11 -04008361 }
8362 }
8363
8364 // store newly approved apps
8365 prevApprovedForRole.put(user.getIdentifier(), roleHolders);
8366 mNonBlockableDefaultApps.put(roleName, prevApprovedForRole);
8367
8368 // update what apps can be blocked
8369 mPreferencesHelper.updateDefaultApps(user.getIdentifier(), toRemove, toAdd);
8370
8371 // RoleManager is the source of truth for this data so we don't need to trigger a
8372 // write of the notification policy xml for this change
8373 }
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008374
8375 private int getUidForPackage(String pkg, int userId) {
8376 try {
8377 return mPm.getPackageUid(pkg, MATCH_ALL, userId);
8378 } catch (RemoteException e) {
8379 Slog.e(TAG, "role manager has bad default " + pkg + " " + userId);
8380 }
8381 return -1;
8382 }
Julia Reynolds0c245002019-03-27 16:10:11 -04008383 }
8384
John Spurlock25e2d242014-06-27 13:58:23 -04008385 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04008386 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04008387 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04008388 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04008389 public long since;
8390 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04008391 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05008392 public boolean proto = false;
Vishnu Naire3e4d252018-03-01 11:26:57 -08008393 public boolean criticalPriority = false;
8394 public boolean normalPriority = false;
John Spurlock25e2d242014-06-27 13:58:23 -04008395
Kweku Adams887f09c2017-11-13 17:12:20 -08008396 @NonNull
John Spurlock25e2d242014-06-27 13:58:23 -04008397 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04008398 final DumpFilter filter = new DumpFilter();
8399 for (int ai = 0; ai < args.length; ai++) {
8400 final String a = args[ai];
Kweku Adams62b42242017-09-25 12:54:02 -07008401 if ("--proto".equals(a)) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05008402 filter.proto = true;
Kweku Adams62b42242017-09-25 12:54:02 -07008403 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
Dan Sandlera1770312015-07-10 13:59:29 -04008404 filter.redact = false;
8405 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
8406 if (ai < args.length-1) {
8407 ai++;
8408 filter.pkgFilter = args[ai].trim().toLowerCase();
8409 if (filter.pkgFilter.isEmpty()) {
8410 filter.pkgFilter = null;
8411 } else {
8412 filter.filtered = true;
8413 }
8414 }
8415 } else if ("--zen".equals(a) || "zen".equals(a)) {
8416 filter.filtered = true;
8417 filter.zen = true;
8418 } else if ("--stats".equals(a)) {
8419 filter.stats = true;
8420 if (ai < args.length-1) {
8421 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01008422 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04008423 } else {
8424 filter.since = 0;
8425 }
Vishnu Naire3e4d252018-03-01 11:26:57 -08008426 } else if (PRIORITY_ARG.equals(a)) {
8427 // Bugreport will call the service twice with priority arguments, first to dump
8428 // critical sections and then non critical ones. Set approriate filters
8429 // to generate the desired data.
8430 if (ai < args.length - 1) {
8431 ai++;
8432 switch (args[ai]) {
8433 case PRIORITY_ARG_CRITICAL:
8434 filter.criticalPriority = true;
8435 break;
8436 case PRIORITY_ARG_NORMAL:
8437 filter.normalPriority = true;
8438 break;
8439 }
8440 }
Dan Sandlera1770312015-07-10 13:59:29 -04008441 }
John Spurlock25e2d242014-06-27 13:58:23 -04008442 }
Dan Sandlera1770312015-07-10 13:59:29 -04008443 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04008444 }
8445
8446 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04008447 if (!filtered) return true;
8448 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04008449 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04008450 }
8451
8452 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04008453 if (!filtered) return true;
8454 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04008455 }
8456
8457 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04008458 if (!filtered) return true;
8459 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04008460 }
8461
8462 @Override
8463 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04008464 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04008465 }
8466 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07008467
Beverly5a20a5e2018-03-06 15:02:44 -05008468 @VisibleForTesting
Tony Mak9a3c1f12019-03-04 16:04:42 +00008469 void resetAssistantUserSet(int userId) {
8470 mAssistants.setUserSet(userId, false);
8471 handleSavePolicyFile();
8472 }
8473
8474 @VisibleForTesting
8475 @Nullable
8476 ComponentName getApprovedAssistant(int userId) {
8477 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
8478 return CollectionUtils.firstOrNull(allowedComponents);
8479 }
8480
8481 @VisibleForTesting
Beverly5a20a5e2018-03-06 15:02:44 -05008482 protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
8483 // only use for testing: mimic receive broadcast that package is (un)suspended
8484 // but does not actually (un)suspend the package
8485 final Bundle extras = new Bundle();
8486 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
8487 new String[]{pkg});
8488
8489 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
Beverly3c707b42018-09-14 09:49:07 -04008490 : Intent.ACTION_PACKAGES_UNSUSPENDED;
Beverly5a20a5e2018-03-06 15:02:44 -05008491 final Intent intent = new Intent(action);
8492 intent.putExtras(extras);
8493
8494 mPackageIntentReceiver.onReceive(getContext(), intent);
8495 }
8496
Julia Reynolds0e5a3432019-01-17 09:40:46 -05008497 @VisibleForTesting
8498 protected void simulatePackageDistractionBroadcast(int flag, String[] pkgs) {
8499 // only use for testing: mimic receive broadcast that package is (un)distracting
8500 // but does not actually register that info with packagemanager
8501 final Bundle extras = new Bundle();
8502 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs);
8503 extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag);
8504
8505 final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
8506 intent.putExtras(extras);
8507
8508 mPackageIntentReceiver.onReceive(getContext(), intent);
8509 }
8510
Griff Hazen84a00ea2014-09-02 17:10:47 -07008511 /**
8512 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
8513 * binder without sending large amounts of data over a oneway transaction.
8514 */
8515 private static final class StatusBarNotificationHolder
8516 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07008517 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07008518
8519 public StatusBarNotificationHolder(StatusBarNotification value) {
8520 mValue = value;
8521 }
8522
Griff Hazene9aac5f2014-09-05 20:04:09 -07008523 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07008524 @Override
8525 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07008526 StatusBarNotification value = mValue;
8527 mValue = null;
8528 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07008529 }
8530 }
John Spurlock7c74f782015-06-04 13:01:42 -04008531
Zimuzob3b9c262018-10-31 11:54:20 +00008532 private void writeSecureNotificationsPolicy(XmlSerializer out) throws IOException {
8533 out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
8534 out.attribute(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
8535 Boolean.toString(mLockScreenAllowSecureNotifications));
8536 out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
8537 }
8538
8539 private static boolean safeBoolean(String val, boolean defValue) {
8540 if (TextUtils.isEmpty(val)) return defValue;
8541 return Boolean.parseBoolean(val);
8542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008543}