blob: e8c402c770c787e59268579d8dc8c955a6aed7e1 [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;
Julia Reynoldse5c60452018-04-30 14:41:36 -040020import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
Julia Reynoldsfc9767b2018-01-22 17:45:16 -050021import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050022import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
23import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
Julia Reynolds8617e4e2017-09-18 16:52:37 -040024import static android.app.NotificationManager.IMPORTANCE_LOW;
Julia Reynolds7c96b582017-05-25 12:35:36 -040025import static android.app.NotificationManager.IMPORTANCE_MIN;
Julia Reynolds85769912016-10-25 09:08:57 -040026import static android.app.NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -050027import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
28import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
29import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
30import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
31import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
32import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
33import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
34import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
35import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
36import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
Amith Yamasanie5bfeee2018-09-05 18:52:35 -070037import static android.content.Context.BIND_ADJUST_BELOW_PERCEPTIBLE;
38import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
39import static android.content.Context.BIND_AUTO_CREATE;
40import static android.content.Context.BIND_FOREGROUND_SERVICE;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -050041import static android.content.pm.PackageManager.FEATURE_LEANBACK;
42import static android.content.pm.PackageManager.FEATURE_TELEVISION;
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -040043import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
44import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
Julia Reynolds4db59552017-06-30 13:34:01 -040045import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Vishnu Naire3e4d252018-03-01 11:26:57 -080046import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
47import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
Julia Reynolds88a879f2017-07-26 17:06:46 -040048import static android.os.UserHandle.USER_NULL;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040049import static android.os.UserHandle.USER_SYSTEM;
Gus Prevas7306b902018-12-11 10:57:06 -050050import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050051import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
Gus Prevas7306b902018-12-11 10:57:06 -050052import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
53import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
54import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
55import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050056import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
57import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040058import static android.service.notification.NotificationListenerService.REASON_CANCEL;
59import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050060import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040061import static android.service.notification.NotificationListenerService.REASON_CLICK;
62import static android.service.notification.NotificationListenerService.REASON_ERROR;
Gus Prevas7306b902018-12-11 10:57:06 -050063import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050064import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
65import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
66import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
67import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
68import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
69import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
70import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
Julia Reynolds2a128742016-11-28 14:29:25 -050071import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050072import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
73import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
Christoph Studerb82bc782014-08-20 14:29:43 +020074import static android.service.notification.NotificationListenerService.TRIM_FULL;
75import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
Wale Ogunwaleac2561e2016-11-01 15:43:46 -070076import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
svetoslavganov75986cf2009-05-14 22:28:01 -070077
Michal Karpinskiac116df2018-12-10 17:51:42 +000078import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
79import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
Michal Karpinskic8aa91b2019-01-10 16:45:59 +000080import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
Vishnu Naire3e4d252018-03-01 11:26:57 -080081import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
82import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
83import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
84
Chris Wren51017d02015-12-15 15:34:46 -050085import android.Manifest;
Zimuzob3b9c262018-10-31 11:54:20 +000086import android.Manifest.permission;
Julia Reynoldsa78cdff2017-04-26 10:19:25 -040087import android.annotation.NonNull;
Wei Liu97e56662016-03-04 10:52:33 -080088import android.annotation.Nullable;
Dianne Hackborn41203752012-08-31 14:05:51 -070089import android.app.ActivityManager;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070090import android.app.ActivityManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -050091import android.app.AlarmManager;
John Spurlock7340fc82014-04-24 18:50:12 -040092import android.app.AppGlobals;
Daniel Sandler4a900ac2013-01-30 14:04:10 -050093import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040094import android.app.AutomaticZenRule;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.app.IActivityManager;
96import android.app.INotificationManager;
97import android.app.ITransientNotification;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070098import android.app.IUriGrantsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099import android.app.Notification;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400100import android.app.NotificationChannel;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500101import android.app.NotificationChannelGroup;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500102import android.app.NotificationManager;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500103import android.app.NotificationManager.Policy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104import android.app.PendingIntent;
105import android.app.StatusBarManager;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700106import android.app.UriGrantsManager;
Jason Parks50322ff2018-03-27 10:23:33 -0500107import android.app.admin.DeviceAdminInfo;
108import android.app.admin.DevicePolicyManagerInternal;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500109import android.app.backup.BackupManager;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700110import android.app.usage.UsageEvents;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700111import android.app.usage.UsageStatsManagerInternal;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400112import android.companion.ICompanionDeviceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113import android.content.BroadcastReceiver;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700114import android.content.ComponentName;
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400115import android.content.ContentProvider;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700116import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117import android.content.Context;
118import android.content.Intent;
119import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -0400120import android.content.pm.ApplicationInfo;
Kenny Guy70058402014-10-28 20:45:06 +0000121import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122import android.content.pm.PackageManager;
123import android.content.pm.PackageManager.NameNotFoundException;
Julia Reynoldsb40cd092019-01-25 09:35:02 -0500124import android.content.pm.PackageManagerInternal;
Christoph Studercee44ba2014-05-20 18:36:43 +0200125import android.content.pm.ParceledListSlice;
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400126import android.content.pm.UserInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700128import android.database.ContentObserver;
Beverly5d463b62017-07-26 14:13:40 -0400129import android.media.AudioAttributes;
svetoslavganov75986cf2009-05-14 22:28:01 -0700130import android.media.AudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500131import android.media.AudioManagerInternal;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700132import android.media.IRingtonePlayer;
Kenny Guy23991102018-04-05 21:18:38 +0100133import android.metrics.LogMaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135import android.os.Binder;
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -0400136import android.os.Build;
John Spurlock2b122f42014-08-27 16:29:47 -0400137import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -0400138import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139import android.os.Handler;
Chris Wrenf9536642014-04-17 10:01:54 -0400140import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141import android.os.IBinder;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800142import android.os.IDeviceIdleController;
John Spurlock7340fc82014-04-24 18:50:12 -0400143import android.os.IInterface;
Chris Wrenf9536642014-04-17 10:01:54 -0400144import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700146import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -0700147import android.os.RemoteException;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400148import android.os.ResultReceiver;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400149import android.os.ServiceManager;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400150import android.os.ShellCallback;
Chris Wrenc8673a82016-05-17 17:11:29 -0400151import android.os.SystemClock;
Selim Cinekb5605e52015-02-20 18:21:41 +0100152import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700153import android.os.UserHandle;
Michael Wright71216972017-01-31 18:33:54 +0000154import android.os.VibrationEffect;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500155import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156import android.provider.Settings;
Julia Reynoldse46bb372016-03-17 11:05:58 -0400157import android.service.notification.Adjustment;
Chris Wren333a61c2014-05-28 16:40:57 -0400158import android.service.notification.Condition;
John Spurlock7340fc82014-04-24 18:50:12 -0400159import android.service.notification.IConditionProvider;
Chris Wren333a61c2014-05-28 16:40:57 -0400160import android.service.notification.INotificationListener;
Griff Hazen84a00ea2014-09-02 17:10:47 -0700161import android.service.notification.IStatusBarNotificationHolder;
Kweku Adams93304b62017-09-20 17:03:00 -0700162import android.service.notification.ListenersDisablingEffectsProto;
Julia Reynolds77b2cc92016-11-08 14:41:09 -0500163import android.service.notification.NotificationAssistantService;
John Spurlock7340fc82014-04-24 18:50:12 -0400164import android.service.notification.NotificationListenerService;
Christoph Studer05ad4822014-05-16 14:16:03 +0200165import android.service.notification.NotificationRankingUpdate;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500166import android.service.notification.NotificationRecordProto;
167import android.service.notification.NotificationServiceDumpProto;
Julia Reynolds503ed942017-10-04 16:04:56 -0400168import android.service.notification.NotificationStats;
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500169import android.service.notification.NotifyingApp;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500170import android.service.notification.SnoozeCriterion;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700171import android.service.notification.StatusBarNotification;
John Spurlock056c5192014-04-20 21:52:01 -0400172import android.service.notification.ZenModeConfig;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500173import android.service.notification.ZenModeProto;
John Spurlock32fe4c62014-10-02 12:16:02 -0400174import android.telephony.PhoneStateListener;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500175import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -0700176import android.text.TextUtils;
John Spurlocka4294292014-03-24 18:02:32 -0400177import android.util.ArrayMap;
John Spurlock1fa865f2014-07-21 14:56:39 -0400178import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700179import android.util.AtomicFile;
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400180import android.util.IntArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -0800182import android.util.Slog;
Bryce Lee7219ada2016-04-08 10:54:23 -0700183import android.util.SparseArray;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400184import android.util.Xml;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500185import android.util.proto.ProtoOutputStream;
svetoslavganov75986cf2009-05-14 22:28:01 -0700186import android.view.accessibility.AccessibilityEvent;
187import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188import android.widget.Toast;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000189
Scott Greenwald9a05b312013-06-28 00:37:54 -0400190import com.android.internal.R;
Julia Reynolds88860ce2017-06-01 16:55:49 -0400191import com.android.internal.annotations.GuardedBy;
Chris Wren93bb8b82016-03-29 14:35:05 -0400192import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -0500193import com.android.internal.logging.MetricsLogger;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500194import com.android.internal.logging.nano.MetricsProto;
Chris Wren9eb5e102017-01-26 13:15:06 -0500195import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Beverly70dcd002018-03-29 17:09:16 -0400196import com.android.internal.notification.SystemNotificationChannels;
Eugene Suslaa25d17f2017-08-24 11:28:08 -0700197import com.android.internal.os.BackgroundThread;
Julia Reynoldsb0405592018-11-26 17:01:13 -0500198import com.android.internal.os.SomeArgs;
Chris Wrend1dbc922015-06-19 17:51:16 -0400199import com.android.internal.statusbar.NotificationVisibility;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400200import com.android.internal.util.ArrayUtils;
Fabian Kozynskid9425662019-01-29 13:08:30 -0500201import com.android.internal.util.CollectionUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600202import com.android.internal.util.DumpUtils;
John Spurlock056c5192014-04-20 21:52:01 -0400203import com.android.internal.util.FastXmlSerializer;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400204import com.android.internal.util.Preconditions;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400205import com.android.internal.util.XmlUtils;
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700206import com.android.server.DeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800207import com.android.server.EventLogTags;
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500208import com.android.server.IoThread;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700209import com.android.server.LocalServices;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800210import com.android.server.SystemService;
211import com.android.server.lights.Light;
212import com.android.server.lights.LightsManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400213import com.android.server.notification.ManagedServices.ManagedServiceInfo;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500214import com.android.server.notification.ManagedServices.UserProfiles;
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400215import com.android.server.pm.PackageManagerService;
Annie Meng8b646fd2019-02-01 18:46:42 +0000216import com.android.server.pm.UserManagerService;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700217import com.android.server.policy.PhoneWindowManager;
John Spurlockb408e8e2014-04-23 21:12:45 -0400218import com.android.server.statusbar.StatusBarManagerInternal;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700219import com.android.server.uri.UriGrantsManagerInternal;
Adrian Roose99bc052017-11-20 17:55:31 +0100220import com.android.server.wm.WindowManagerInternal;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800221
John Spurlockb408e8e2014-04-23 21:12:45 -0400222import libcore.io.IoUtils;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000223
Chris Wrene4b38802015-07-07 15:54:19 -0400224import org.json.JSONException;
225import org.json.JSONObject;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700226import org.xmlpull.v1.XmlPullParser;
227import org.xmlpull.v1.XmlPullParserException;
John Spurlock056c5192014-04-20 21:52:01 -0400228import org.xmlpull.v1.XmlSerializer;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700229
John Spurlock35ef0a62015-05-28 11:24:10 -0400230import java.io.ByteArrayInputStream;
231import java.io.ByteArrayOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400232import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400234import java.io.FileNotFoundException;
John Spurlock056c5192014-04-20 21:52:01 -0400235import java.io.FileOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400236import java.io.IOException;
John Spurlock35ef0a62015-05-28 11:24:10 -0400237import java.io.InputStream;
238import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100240import java.nio.charset.StandardCharsets;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500241import java.util.ArrayDeque;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242import java.util.ArrayList;
Michael Wrightbc4d0d92017-03-23 18:57:57 +0000243import java.util.Arrays;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500244import java.util.Iterator;
John Spurlock7c74f782015-06-04 13:01:42 -0400245import java.util.List;
Christoph Studer265c1052014-07-23 17:14:33 +0200246import java.util.Map.Entry;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500247import java.util.Objects;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400248import java.util.Set;
Chris Wren51017d02015-12-15 15:34:46 -0500249import java.util.concurrent.TimeUnit;
Tony Makeda84a72018-11-19 17:01:32 +0000250import java.util.function.BiConsumer;
Kristian Monsen30f59b22018-04-09 10:27:16 +0200251import java.util.function.Predicate;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400252
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400253/** {@hide} */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800254public class NotificationManagerService extends SystemService {
255 static final String TAG = "NotificationService";
Christoph Studer1f32c652014-11-26 15:32:20 +0100256 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Selim Cinek40412492015-12-08 18:03:22 -0800257 public static final boolean ENABLE_CHILD_NOTIFICATIONS
258 = SystemProperties.getBoolean("debug.child_notifs", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259
Dan Sandler7d67bd42018-05-15 14:06:38 -0400260 static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
261 "debug.notification.interruptiveness", false);
262
Adam Lesinski182f73f2013-12-05 16:48:06 -0800263 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
Julia Reynolds6ad0aec2017-07-05 08:47:03 -0400264 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
Joe Onoratobd73d012010-06-04 11:44:54 -0700265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 // message codes
Robert Carr997427342018-02-28 18:06:10 -0800267 static final int MESSAGE_DURATION_REACHED = 2;
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500268 // 3: removed to a different handler
Chris Wren51017d02015-12-15 15:34:46 -0500269 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
270 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
271 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
Robert Carr997427342018-02-28 18:06:10 -0800272 static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
Julia Reynoldsb0405592018-11-26 17:01:13 -0500273 static final int MESSAGE_ON_PACKAGE_CHANGED = 8;
Chris Wren51017d02015-12-15 15:34:46 -0500274
275 // ranking thread messages
276 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
277 private static final int MESSAGE_RANKING_SORT = 1001;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700279 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800280 static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800281
Robert Carr3406d462018-03-15 16:19:07 -0700282 // 1 second past the ANR timeout.
283 static final int FINISH_TOKEN_TIMEOUT = 11 * 1000;
284
Adam Lesinski182f73f2013-12-05 16:48:06 -0800285 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
Christoph Studer265c1052014-07-23 17:14:33 +0200286
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500287 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
288
Adam Lesinski182f73f2013-12-05 16:48:06 -0800289 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290
Adam Lesinski182f73f2013-12-05 16:48:06 -0800291 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler526fa0e2012-12-04 14:51:50 -0500292
Adam Lesinski182f73f2013-12-05 16:48:06 -0800293 static final boolean ENABLE_BLOCKED_TOASTS = true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400294
Christoph Studer12aeda82014-09-23 19:08:56 +0200295 // When #matchesCallFilter is called from the ringer, wait at most
296 // 3s to resolve the contacts. This timeout is required since
297 // ContactsProvider might take a long time to start up.
298 //
299 // Return STARRED_CONTACT when the timeout is hit in order to avoid
300 // missed calls in ZEN mode "Important".
301 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
302 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
303 ValidateNotificationPeople.STARRED_CONTACT;
304
Christoph Studer265c1052014-07-23 17:14:33 +0200305 /** notification_enqueue status value for a newly enqueued notification. */
306 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
307
308 /** notification_enqueue status value for an existing notification. */
309 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
310
311 /** notification_enqueue status value for an ignored notification. */
312 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
Chris Wrenc8673a82016-05-17 17:11:29 -0400313 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
Christoph Studer265c1052014-07-23 17:14:33 +0200314
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500315 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
316
Julia Reynolds2a128742016-11-28 14:29:25 -0500317 private static final String ACTION_NOTIFICATION_TIMEOUT =
318 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
319 private static final int REQUEST_CODE_TIMEOUT = 1;
320 private static final String SCHEME_TIMEOUT = "timeout";
321 private static final String EXTRA_KEY = "key";
322
Adam Lesinski182f73f2013-12-05 16:48:06 -0800323 private IActivityManager mAm;
Julia Reynolds68263d12017-06-21 14:21:19 -0400324 private ActivityManager mActivityManager;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500325 private IPackageManager mPackageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500326 private PackageManager mPackageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800327 AudioManager mAudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500328 AudioManagerInternal mAudioManagerInternal;
Wei Liu97e56662016-03-04 10:52:33 -0800329 @Nullable StatusBarManagerInternal mStatusBar;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800330 Vibrator mVibrator;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700331 private WindowManagerInternal mWindowManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -0500332 private AlarmManager mAlarmManager;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400333 private ICompanionDeviceManager mCompanionManager;
Julia Reynolds94187562017-10-10 13:58:49 -0400334 private AccessibilityManager mAccessibilityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800335 private IDeviceIdleController mDeviceIdleController;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700336 private IUriGrantsManager mUgm;
337 private UriGrantsManagerInternal mUgmInternal;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 final IBinder mForegroundToken = new Binder();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400340 private WorkerHandler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400341 private final HandlerThread mRankingThread = new HandlerThread("ranker",
342 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343
Adam Lesinski182f73f2013-12-05 16:48:06 -0800344 private Light mNotificationLight;
345 Light mAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800346
Daniel Sandleredbb3802012-11-13 20:49:47 -0800347 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400348 private boolean mUseAttentionLight;
Julia Reynolds28149f62018-07-03 10:43:35 -0400349 boolean mHasLight = true;
350 boolean mLightEnabled;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800351 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800352
John Spurlockd8afe3c2014-08-01 14:04:07 -0400353 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400354 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500355 private String mSoundNotificationKey;
356 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357
Julia Reynolds4703bac2018-09-12 10:39:30 -0400358 private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects =
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400359 new SparseArray<>();
360 private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400361 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500362 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400363
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500364 // for enabling and disabling notification pulse behavior
Julia Reynolds28149f62018-07-03 10:43:35 -0400365 boolean mScreenOn = true;
Beverly5d463b62017-07-26 14:13:40 -0400366 protected boolean mInCall = false;
Julia Reynolds28149f62018-07-03 10:43:35 -0400367 boolean mNotificationPulseEnabled;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500368
Beverly5d463b62017-07-26 14:13:40 -0400369 private Uri mInCallNotificationUri;
370 private AudioAttributes mInCallNotificationAudioAttributes;
371 private float mInCallNotificationVolume;
luochaojiang50e5273c2018-04-16 16:55:03 +0800372 private Binder mCallNotificationToken = null;
Marta Białka39c992f2011-03-10 10:27:24 +0100373
Daniel Sandler09a247e2013-02-14 10:24:17 -0500374 // used as a mutex for access to all active notifications & listeners
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500375 final Object mNotificationLock = new Object();
Julia Reynolds0839c022017-06-15 15:24:01 -0400376 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400377 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400378 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400379 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400380 @GuardedBy("mNotificationLock")
Chris Wren6676dab2016-12-21 18:26:27 -0500381 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400382 @GuardedBy("mNotificationLock")
Julia Reynoldseae43fb2016-05-09 12:42:58 -0400383 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400384 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
Christoph Studer265c1052014-07-23 17:14:33 +0200385 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500386 final ArrayMap<Integer, ArrayList<NotifyingApp>> mRecentApps = new ArrayMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387
Chris Wren6054e612014-11-25 17:16:46 -0500388 // The last key in this list owns the hardware.
389 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700390
Adam Lesinski182f73f2013-12-05 16:48:06 -0800391 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700392 private UsageStatsManagerInternal mAppUsageStats;
Jason Parks50322ff2018-03-27 10:23:33 -0500393 private DevicePolicyManagerInternal mDpm;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500394
Griff Hazen9f637d12014-06-10 11:13:51 -0700395 private Archive mArchive;
396
John Spurlock21258a32015-05-27 18:22:55 -0400397 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400398 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400399
Daniel Sandler0da673f2012-04-11 12:33:16 -0400400 private static final int DB_VERSION = 1;
401
John Spurlock21258a32015-05-27 18:22:55 -0400402 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400403 private static final String ATTR_VERSION = "version";
404
Zimuzob3b9c262018-10-31 11:54:20 +0000405 private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG =
406 "allow-secure-notifications-on-lockscreen";
407 private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE = "value";
408
Chris Wren54bbef42014-07-09 18:37:56 -0400409 private RankingHelper mRankingHelper;
Aaron Heuckrothe5bec152018-07-09 16:26:09 -0400410 private PreferencesHelper mPreferencesHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400411
John Spurlockb408e8e2014-04-23 21:12:45 -0400412 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400413 private NotificationListeners mListeners;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400414 private NotificationAssistants mAssistants;
John Spurlock7340fc82014-04-24 18:50:12 -0400415 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200416 private NotificationUsageStats mUsageStats;
Selim Cinek03362962018-11-20 16:19:12 -0800417 private boolean mLockScreenAllowSecureNotifications = true;
Christoph Studer546bec82014-03-14 12:17:12 +0100418
John Spurlocke6a7d932014-03-13 12:29:00 -0400419 private static final int MY_UID = Process.myUid();
420 private static final int MY_PID = Process.myPid();
Dianne Hackborn98305522017-05-05 17:53:53 -0700421 private static final IBinder WHITELIST_TOKEN = new Binder();
Chris Wren51017d02015-12-15 15:34:46 -0500422 private RankingHandler mRankingHandler;
Chris Wrenc8673a82016-05-17 17:11:29 -0400423 private long mLastOverRateLogTime;
Chris Wren763a9bb2016-05-31 17:14:12 -0400424 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
John Spurlocke6a7d932014-03-13 12:29:00 -0400425
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400426 private SnoozeHelper mSnoozeHelper;
Julia Reynolds8f488d32016-10-14 10:59:01 -0400427 private GroupHelper mGroupHelper;
Adora Zhang48dd614a82018-06-25 19:18:41 -0700428 private int mAutoGroupAtCount;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -0500429 private boolean mIsTelevision;
Adora Zhang963328f2018-11-15 18:17:19 -0800430 private boolean mIsAutomotive;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400431
Kenny Guy23991102018-04-05 21:18:38 +0100432 private MetricsLogger mMetricsLogger;
Kristian Monsen30f59b22018-04-09 10:27:16 +0200433 private Predicate<String> mAllowedManagedServicePackages;
Kenny Guy23991102018-04-05 21:18:38 +0100434
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500435 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700436 final int mBufferSize;
437 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500438
Griff Hazen9f637d12014-06-10 11:13:51 -0700439 public Archive(int size) {
440 mBufferSize = size;
441 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500442 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700443
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400444 public String toString() {
445 final StringBuilder sb = new StringBuilder();
446 final int N = mBuffer.size();
447 sb.append("Archive (");
448 sb.append(N);
449 sb.append(" notification");
450 sb.append((N==1)?")":"s)");
451 return sb.toString();
452 }
453
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500454 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700455 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500456 mBuffer.removeFirst();
457 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400458
459 // We don't want to store the heavy bits of the notification in the archive,
460 // but other clients in the system process might be using the object, so we
461 // store a (lightened) copy.
462 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500463 }
464
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500465 public Iterator<StatusBarNotification> descendingIterator() {
466 return mBuffer.descendingIterator();
467 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500468
469 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700470 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500471 final StatusBarNotification[] a
472 = new StatusBarNotification[Math.min(count, mBuffer.size())];
473 Iterator<StatusBarNotification> iter = descendingIterator();
474 int i=0;
475 while (iter.hasNext() && i < count) {
476 a[i++] = iter.next();
477 }
478 return a;
479 }
480
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500481 }
482
Julia Reynolds88a879f2017-07-26 17:06:46 -0400483 protected void readDefaultApprovedServices(int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400484 String defaultListenerAccess = getContext().getResources().getString(
485 com.android.internal.R.string.config_defaultListenerAccessPackages);
486 if (defaultListenerAccess != null) {
487 for (String whitelisted :
488 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
489 // Gather all notification listener components for candidate pkgs.
490 Set<ComponentName> approvedListeners =
491 mListeners.queryPackageForServices(whitelisted,
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400492 MATCH_DIRECT_BOOT_AWARE
493 | MATCH_DIRECT_BOOT_UNAWARE, userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400494 for (ComponentName cn : approvedListeners) {
495 try {
496 getBinderService().setNotificationListenerAccessGrantedForUser(cn,
497 userId, true);
498 } catch (RemoteException e) {
499 e.printStackTrace();
500 }
501 }
502 }
503 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500504
Julia Reynoldsb852e562017-06-06 16:14:18 -0400505 String defaultDndAccess = getContext().getResources().getString(
506 com.android.internal.R.string.config_defaultDndAccessPackages);
Edward Savage-Jones36a89422018-07-19 12:23:58 +0200507 if (defaultDndAccess != null) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400508 for (String whitelisted :
509 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
510 try {
511 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
512 } catch (RemoteException e) {
513 e.printStackTrace();
514 }
515 }
516 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500517
518 readDefaultAssistant(userId);
519 }
520
521 protected void readDefaultAssistant(int userId) {
522 String defaultAssistantAccess = getContext().getResources().getString(
523 com.android.internal.R.string.config_defaultAssistantAccessPackage);
524 if (defaultAssistantAccess != null) {
525 // Gather all notification assistant components for candidate pkg. There should
526 // only be one
527 Set<ComponentName> approvedAssistants =
528 mAssistants.queryPackageForServices(defaultAssistantAccess,
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400529 MATCH_DIRECT_BOOT_AWARE
530 | MATCH_DIRECT_BOOT_UNAWARE, userId);
Julia Reynolds7380d872018-01-12 10:28:26 -0500531 for (ComponentName cn : approvedAssistants) {
532 try {
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400533 getBinderService().setNotificationAssistantAccessGrantedForUser(
534 cn, userId, true);
Julia Reynolds7380d872018-01-12 10:28:26 -0500535 } catch (RemoteException e) {
536 e.printStackTrace();
537 }
538 }
539 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400540 }
541
Annie Meng8b646fd2019-02-01 18:46:42 +0000542 UserManagerService getUserManagerService() {
543 return UserManagerService.getInstance();
544 }
545
546 void readPolicyXml(InputStream stream, boolean forRestore, int userId)
John Spurlock35ef0a62015-05-28 11:24:10 -0400547 throws XmlPullParserException, NumberFormatException, IOException {
548 final XmlPullParser parser = Xml.newPullParser();
549 parser.setInput(stream, StandardCharsets.UTF_8.name());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400550 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
551 boolean migratedManagedServices = false;
Annie Meng8b646fd2019-02-01 18:46:42 +0000552 boolean ineligibleForManagedServices = forRestore
553 && getUserManagerService().isManagedProfile(userId);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400554 int outerDepth = parser.getDepth();
555 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
556 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000557 mZenModeHelper.readXml(parser, forRestore, userId);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -0400558 } else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){
Annie Meng8b646fd2019-02-01 18:46:42 +0000559 mPreferencesHelper.readXml(parser, forRestore, userId);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400560 }
Kristian Monsen30f59b22018-04-09 10:27:16 +0200561 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000562 if (ineligibleForManagedServices) {
563 continue;
564 }
565 mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
Kristian Monsen30f59b22018-04-09 10:27:16 +0200566 migratedManagedServices = true;
567 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000568 if (ineligibleForManagedServices) {
569 continue;
570 }
571 mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
Kristian Monsen30f59b22018-04-09 10:27:16 +0200572 migratedManagedServices = true;
573 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000574 if (ineligibleForManagedServices) {
575 continue;
576 }
577 mConditionProviders.readXml(
578 parser, mAllowedManagedServicePackages, forRestore, userId);
Kristian Monsen30f59b22018-04-09 10:27:16 +0200579 migratedManagedServices = true;
Julia Reynolds68263d12017-06-21 14:21:19 -0400580 }
Zimuzob3b9c262018-10-31 11:54:20 +0000581 if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000582 if (forRestore && userId != UserHandle.USER_SYSTEM) {
583 continue;
584 }
Zimuzob3b9c262018-10-31 11:54:20 +0000585 mLockScreenAllowSecureNotifications =
586 safeBoolean(parser.getAttributeValue(null,
587 LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE), true);
588 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400589 }
590
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400591 if (!migratedManagedServices) {
592 mListeners.migrateToXml();
593 mAssistants.migrateToXml();
594 mConditionProviders.migrateToXml();
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500595 handleSavePolicyFile();
John Spurlock35ef0a62015-05-28 11:24:10 -0400596 }
597 }
598
John Spurlock056c5192014-04-20 21:52:01 -0400599 private void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400600 if (DBG) Slog.d(TAG, "loadPolicyFile");
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500601 synchronized (mPolicyFile) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400602 InputStream infile = null;
John Spurlock056c5192014-04-20 21:52:01 -0400603 try {
604 infile = mPolicyFile.openRead();
Annie Meng8b646fd2019-02-01 18:46:42 +0000605 readPolicyXml(infile, false /*forRestore*/, UserHandle.USER_ALL);
John Spurlock056c5192014-04-20 21:52:01 -0400606 } catch (FileNotFoundException e) {
607 // No data yet
Julia Reynoldsb852e562017-06-06 16:14:18 -0400608 // Load default managed services approvals
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400609 readDefaultApprovedServices(USER_SYSTEM);
John Spurlock056c5192014-04-20 21:52:01 -0400610 } catch (IOException e) {
611 Log.wtf(TAG, "Unable to read notification policy", e);
612 } catch (NumberFormatException e) {
613 Log.wtf(TAG, "Unable to parse notification policy", e);
614 } catch (XmlPullParserException e) {
615 Log.wtf(TAG, "Unable to parse notification policy", e);
616 } finally {
617 IoUtils.closeQuietly(infile);
618 }
619 }
620 }
621
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500622 @VisibleForTesting
623 protected void handleSavePolicyFile() {
624 IoThread.getHandler().post(() -> {
625 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
626 synchronized (mPolicyFile) {
627 final FileOutputStream stream;
628 try {
629 stream = mPolicyFile.startWrite();
630 } catch (IOException e) {
631 Slog.w(TAG, "Failed to save policy file", e);
632 return;
633 }
John Spurlock056c5192014-04-20 21:52:01 -0400634
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500635 try {
Annie Meng8b646fd2019-02-01 18:46:42 +0000636 writePolicyXml(stream, false /*forBackup*/, UserHandle.USER_ALL);
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500637 mPolicyFile.finishWrite(stream);
638 } catch (IOException e) {
639 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
640 mPolicyFile.failWrite(stream);
641 }
Daniel Sandler0da673f2012-04-11 12:33:16 -0400642 }
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500643 BackupManager.dataChanged(getContext().getPackageName());
644 });
John Spurlock35ef0a62015-05-28 11:24:10 -0400645 }
646
Annie Meng8b646fd2019-02-01 18:46:42 +0000647 private void writePolicyXml(OutputStream stream, boolean forBackup, int userId)
648 throws IOException {
John Spurlock35ef0a62015-05-28 11:24:10 -0400649 final XmlSerializer out = new FastXmlSerializer();
650 out.setOutput(stream, StandardCharsets.UTF_8.name());
651 out.startDocument(null, true);
652 out.startTag(null, TAG_NOTIFICATION_POLICY);
653 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
Annie Meng8b646fd2019-02-01 18:46:42 +0000654 mZenModeHelper.writeXml(out, forBackup, null, userId);
655 mPreferencesHelper.writeXml(out, forBackup, userId);
656 mListeners.writeXml(out, forBackup, userId);
657 mAssistants.writeXml(out, forBackup, userId);
658 mConditionProviders.writeXml(out, forBackup, userId);
659 if (!forBackup || userId == UserHandle.USER_SYSTEM) {
660 writeSecureNotificationsPolicy(out);
661 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400662 out.endTag(null, TAG_NOTIFICATION_POLICY);
663 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400664 }
665
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 private static final class ToastRecord
667 {
668 final int pid;
669 final String pkg;
Beverly Taia7ed0ab2018-06-11 14:50:36 +0000670 final ITransientNotification callback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 int duration;
Jeff Chang48ecef42018-08-09 16:31:59 +0800672 int displayId;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700673 Binder token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700675 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
Jeff Chang48ecef42018-08-09 16:31:59 +0800676 Binder token, int displayId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 this.pid = pid;
678 this.pkg = pkg;
679 this.callback = callback;
680 this.duration = duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700681 this.token = token;
Jeff Chang48ecef42018-08-09 16:31:59 +0800682 this.displayId = displayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 }
684
685 void update(int duration) {
686 this.duration = duration;
687 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800688
John Spurlock25e2d242014-06-27 13:58:23 -0400689 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
690 if (filter != null && !filter.matches(pkg)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 pw.println(prefix + this);
692 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800693
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 @Override
695 public final String toString()
696 {
697 return "ToastRecord{"
698 + Integer.toHexString(System.identityHashCode(this))
699 + " pkg=" + pkg
700 + " callback=" + callback
701 + " duration=" + duration;
702 }
703 }
704
Beverly40239d92017-07-07 10:20:41 -0400705 @VisibleForTesting
706 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707
Adam Lesinski182f73f2013-12-05 16:48:06 -0800708 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 public void onSetDisabled(int status) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500710 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400711 mDisableNotificationEffects =
712 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
John Spurlock32fe4c62014-10-02 12:16:02 -0400713 if (disableNotificationEffects(null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 // cancel whatever's going on
715 long identity = Binder.clearCallingIdentity();
716 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800717 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700718 if (player != null) {
719 player.stopAsync();
720 }
721 } catch (RemoteException e) {
722 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 Binder.restoreCallingIdentity(identity);
724 }
725
726 identity = Binder.clearCallingIdentity();
727 try {
728 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700729 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 Binder.restoreCallingIdentity(identity);
731 }
732 }
733 }
734 }
735
Adam Lesinski182f73f2013-12-05 16:48:06 -0800736 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400737 public void onClearAll(int callingUid, int callingPid, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500738 synchronized (mNotificationLock) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400739 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
Kenny Guya263e4e2014-03-03 18:24:03 +0000740 /*includeCurrentProfiles*/ true);
Adam Lesinskie8240262014-03-26 16:01:00 -0700741 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 }
743
Adam Lesinski182f73f2013-12-05 16:48:06 -0800744 @Override
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400745 public void onNotificationClick(int callingUid, int callingPid, String key,
746 NotificationVisibility nv) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800747 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500748 synchronized (mNotificationLock) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200749 NotificationRecord r = mNotificationsByKey.get(key);
750 if (r == null) {
751 Log.w(TAG, "No notification with key: " + key);
752 return;
753 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400754 final long now = System.currentTimeMillis();
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400755 MetricsLogger.action(r.getItemLogMaker()
Dieter Hsud39f0d52018-04-14 02:08:30 +0800756 .setType(MetricsEvent.TYPE_ACTION)
757 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
758 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400759 EventLogTags.writeNotificationClicked(key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800760 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
761 nv.rank, nv.count);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400762
Christoph Studer03b87a22014-04-30 17:33:27 +0200763 StatusBarNotification sbn = r.sbn;
764 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
765 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400766 FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
Dieter Hsud39f0d52018-04-14 02:08:30 +0800767 REASON_CLICK, nv.rank, nv.count, null);
768 nv.recycle();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800769 reportUserInteraction(r);
Christoph Studer03b87a22014-04-30 17:33:27 +0200770 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 }
772
Adam Lesinski182f73f2013-12-05 16:48:06 -0800773 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200774 public void onNotificationActionClick(int callingUid, int callingPid, String key,
Tony Mak7d4b3a52018-11-27 17:29:36 +0000775 int actionIndex, Notification.Action action, NotificationVisibility nv,
776 boolean generatedByAssistant) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800777 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500778 synchronized (mNotificationLock) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200779 NotificationRecord r = mNotificationsByKey.get(key);
780 if (r == null) {
781 Log.w(TAG, "No notification with key: " + key);
782 return;
783 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400784 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500785 MetricsLogger.action(r.getLogMaker(now)
786 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
787 .setType(MetricsEvent.TYPE_ACTION)
Dieter Hsud39f0d52018-04-14 02:08:30 +0800788 .setSubtype(actionIndex)
789 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
Gustav Senntond25a64d2018-12-07 10:58:39 +0000790 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count)
791 .addTaggedData(MetricsEvent.NOTIFICATION_ACTION_IS_SMART,
Gustav Sennton005d7a02019-01-04 13:41:32 +0000792 action.isContextual() ? 1 : 0)
Gustav Senntond25a64d2018-12-07 10:58:39 +0000793 .addTaggedData(
794 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
Gustav Sennton72991962019-01-28 21:09:54 +0000795 generatedByAssistant ? 1 : 0)
796 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
797 nv.location.toMetricsEventEnum()));
798
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400799 EventLogTags.writeNotificationActionClicked(key, actionIndex,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800800 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
801 nv.rank, nv.count);
802 nv.recycle();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800803 reportUserInteraction(r);
Tony Mak7d4b3a52018-11-27 17:29:36 +0000804 mAssistants.notifyAssistantActionClicked(
805 r.sbn, actionIndex, action, generatedByAssistant);
Christoph Studer4da84cd2014-10-21 17:24:20 +0200806 }
807 }
808
809 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400810 public void onNotificationClear(int callingUid, int callingPid,
Julia Reynolds503ed942017-10-04 16:04:56 -0400811 String pkg, String tag, int id, int userId, String key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800812 @NotificationStats.DismissalSurface int dismissalSurface,
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400813 @NotificationStats.DismissalSentiment int dismissalSentiment,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800814 NotificationVisibility nv) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400815 synchronized (mNotificationLock) {
816 NotificationRecord r = mNotificationsByKey.get(key);
817 if (r != null) {
818 r.recordDismissalSurface(dismissalSurface);
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400819 r.recordDismissalSentiment(dismissalSentiment);
Julia Reynolds503ed942017-10-04 16:04:56 -0400820 }
821 }
John Spurlocke6a7d932014-03-13 12:29:00 -0400822 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400823 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800824 true, userId, REASON_CANCEL, nv.rank, nv.count,null);
825 nv.recycle();
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400826 }
827
Adam Lesinski182f73f2013-12-05 16:48:06 -0800828 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400829 public void onPanelRevealed(boolean clearEffects, int items) {
Chris Wren9eb5e102017-01-26 13:15:06 -0500830 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Chris Wren621933f2017-06-14 15:59:03 -0400831 MetricsLogger.histogram(getContext(), "note_load", items);
Chris Wrenb659c4f2015-06-25 17:12:27 -0400832 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100833 if (clearEffects) {
834 clearEffects();
835 }
836 }
837
838 @Override
839 public void onPanelHidden() {
Chris Wren9eb5e102017-01-26 13:15:06 -0500840 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Christoph Studer1f32c652014-11-26 15:32:20 +0100841 EventLogTags.writeNotificationPanelHidden();
842 }
843
844 @Override
845 public void clearEffects() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500846 synchronized (mNotificationLock) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100847 if (DBG) Slog.d(TAG, "clearEffects");
Chris Wren93bb8b82016-03-29 14:35:05 -0400848 clearSoundLocked();
849 clearVibrateLocked();
850 clearLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 }
852 }
Joe Onorato005847b2010-06-04 16:08:02 -0400853
Adam Lesinski182f73f2013-12-05 16:48:06 -0800854 @Override
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400855 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag,
856 int id, int uid, int initialPid, String message, int userId) {
John Spurlocke6a7d932014-03-13 12:29:00 -0400857 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400858 REASON_ERROR, null);
Joe Onorato005847b2010-06-04 16:08:02 -0400859 }
John Spurlocke677d712014-02-13 12:52:19 -0500860
861 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400862 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
863 NotificationVisibility[] noLongerVisibleKeys) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500864 synchronized (mNotificationLock) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400865 for (NotificationVisibility nv : newlyVisibleKeys) {
866 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200867 if (r == null) continue;
Amith Yamasani803eab692017-11-09 17:47:04 -0800868 if (!r.isSeen()) {
869 // Report to usage stats that notification was made visible
870 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
871 reportSeen(r);
872 }
Dieter Hsud39f0d52018-04-14 02:08:30 +0800873 r.setVisibility(true, nv.rank, nv.count);
Gustav Senntonc7d0d322019-01-07 15:36:41 +0000874 boolean isHun = (nv.location
875 == NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP);
Gustav Sennton44dc5882018-12-13 14:38:50 +0000876 // hasBeenVisiblyExpanded must be called after updating the expansion state of
877 // the NotificationRecord to ensure the expansion state is up-to-date.
Gustav Senntonc7d0d322019-01-07 15:36:41 +0000878 if (isHun || r.hasBeenVisiblyExpanded()) {
879 logSmartSuggestionsVisible(r, nv.location.toMetricsEventEnum());
Gustav Sennton44dc5882018-12-13 14:38:50 +0000880 }
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400881 maybeRecordInterruptionLocked(r);
Chris Wrend1dbc922015-06-19 17:51:16 -0400882 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200883 }
884 // Note that we might receive this event after notifications
885 // have already left the system, e.g. after dismissing from the
886 // shade. Hence not finding notifications in
887 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400888 for (NotificationVisibility nv : noLongerVisibleKeys) {
889 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200890 if (r == null) continue;
Dieter Hsud39f0d52018-04-14 02:08:30 +0800891 r.setVisibility(false, nv.rank, nv.count);
Chris Wrend1dbc922015-06-19 17:51:16 -0400892 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200893 }
894 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200895 }
Chris Wren78403d72014-07-28 10:23:24 +0100896
897 @Override
898 public void onNotificationExpansionChanged(String key,
Gustav Senntona8e38aa2019-01-22 14:55:39 +0000899 boolean userAction, boolean expanded, int notificationLocation) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500900 synchronized (mNotificationLock) {
Chris Wren78403d72014-07-28 10:23:24 +0100901 NotificationRecord r = mNotificationsByKey.get(key);
902 if (r != null) {
903 r.stats.onExpansionChanged(userAction, expanded);
Gustav Sennton44dc5882018-12-13 14:38:50 +0000904 // hasBeenVisiblyExpanded must be called after updating the expansion state of
905 // the NotificationRecord to ensure the expansion state is up-to-date.
906 if (r.hasBeenVisiblyExpanded()) {
Gustav Senntonc7d0d322019-01-07 15:36:41 +0000907 logSmartSuggestionsVisible(r, notificationLocation);
Gustav Sennton44dc5882018-12-13 14:38:50 +0000908 }
Chris Wrenf7342712017-09-14 10:55:55 -0400909 if (userAction) {
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400910 MetricsLogger.action(r.getItemLogMaker()
Chris Wrenf7342712017-09-14 10:55:55 -0400911 .setType(expanded ? MetricsEvent.TYPE_DETAIL
912 : MetricsEvent.TYPE_COLLAPSE));
Chris Wren377ac6d2017-09-12 14:15:23 -0400913 }
Julia Reynolds84dc96b2017-11-14 09:51:01 -0500914 if (expanded && userAction) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400915 r.recordExpanded();
Esteban Talavera917a71d2018-11-13 07:55:08 +0000916 reportUserInteraction(r);
Julia Reynolds503ed942017-10-04 16:04:56 -0400917 }
Tony Makeda84a72018-11-19 17:01:32 +0000918 mAssistants.notifyAssistantExpansionChangedLocked(r.sbn, userAction, expanded);
Chris Wren78403d72014-07-28 10:23:24 +0100919 }
920 }
921 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400922
923 @Override
924 public void onNotificationDirectReplied(String key) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800925 exitIdle();
Julia Reynolds503ed942017-10-04 16:04:56 -0400926 synchronized (mNotificationLock) {
927 NotificationRecord r = mNotificationsByKey.get(key);
928 if (r != null) {
929 r.recordDirectReplied();
Esteban Talaveraf9c53b62018-11-14 18:20:29 +0000930 mMetricsLogger.write(r.getLogMaker()
931 .setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION)
932 .setType(MetricsEvent.TYPE_ACTION));
Amith Yamasani7ec89412018-02-07 08:48:49 -0800933 reportUserInteraction(r);
Tony Makeda84a72018-11-19 17:01:32 +0000934 mAssistants.notifyAssistantNotificationDirectReplyLocked(r.sbn);
Julia Reynolds503ed942017-10-04 16:04:56 -0400935 }
936 }
937 }
938
939 @Override
Gustav Senntond25a64d2018-12-07 10:58:39 +0000940 public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount,
Milo Sredkov13d88112019-02-01 12:23:24 +0000941 int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) {
Kenny Guy23991102018-04-05 21:18:38 +0100942 synchronized (mNotificationLock) {
943 NotificationRecord r = mNotificationsByKey.get(key);
944 if (r != null) {
Gustav Senntond25a64d2018-12-07 10:58:39 +0000945 r.setNumSmartRepliesAdded(smartReplyCount);
946 r.setNumSmartActionsAdded(smartActionCount);
947 r.setSuggestionsGeneratedByAssistant(generatedByAssistant);
Milo Sredkov13d88112019-02-01 12:23:24 +0000948 r.setEditChoicesBeforeSending(editBeforeSending);
Kenny Guy23991102018-04-05 21:18:38 +0100949 }
950 }
951 }
952
953 @Override
Tony Mak29996702018-11-26 16:23:34 +0000954 public void onNotificationSmartReplySent(String key, int replyIndex, CharSequence reply,
Milo Sredkov13d88112019-02-01 12:23:24 +0000955 int notificationLocation, boolean modifiedBeforeSending) {
Gustav Senntond25a64d2018-12-07 10:58:39 +0000956
Kenny Guy23991102018-04-05 21:18:38 +0100957 synchronized (mNotificationLock) {
958 NotificationRecord r = mNotificationsByKey.get(key);
959 if (r != null) {
960 LogMaker logMaker = r.getLogMaker()
961 .setCategory(MetricsEvent.SMART_REPLY_ACTION)
Gustav Sennton13edb492019-01-28 21:40:04 +0000962 .setSubtype(replyIndex)
963 .addTaggedData(
964 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
Milo Sredkov13d88112019-02-01 12:23:24 +0000965 r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
Gustav Sennton13edb492019-01-28 21:40:04 +0000966 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
Milo Sredkov13d88112019-02-01 12:23:24 +0000967 notificationLocation)
968 .addTaggedData(
969 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
970 r.getEditChoicesBeforeSending() ? 1 : 0)
971 .addTaggedData(
972 MetricsEvent.NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING,
973 modifiedBeforeSending ? 1 : 0);
Kenny Guy23991102018-04-05 21:18:38 +0100974 mMetricsLogger.write(logMaker);
975 // Treat clicking on a smart reply as a user interaction.
976 reportUserInteraction(r);
Tony Mak29996702018-11-26 16:23:34 +0000977 mAssistants.notifyAssistantSuggestedReplySent(
Milo Sredkov13d88112019-02-01 12:23:24 +0000978 r.sbn, reply, r.getSuggestionsGeneratedByAssistant());
Kenny Guy23991102018-04-05 21:18:38 +0100979 }
980 }
981 }
982
983 @Override
Julia Reynolds503ed942017-10-04 16:04:56 -0400984 public void onNotificationSettingsViewed(String key) {
985 synchronized (mNotificationLock) {
986 NotificationRecord r = mNotificationsByKey.get(key);
987 if (r != null) {
988 r.recordViewedSettings();
989 }
990 }
991 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 };
993
Gustav Sennton44dc5882018-12-13 14:38:50 +0000994 @VisibleForTesting
Gustav Senntonc7d0d322019-01-07 15:36:41 +0000995 void logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation) {
Gustav Sennton44dc5882018-12-13 14:38:50 +0000996 // If the newly visible notification has smart suggestions
997 // then log that the user has seen them.
998 if ((r.getNumSmartRepliesAdded() > 0 || r.getNumSmartActionsAdded() > 0)
999 && !r.hasSeenSmartReplies()) {
1000 r.setSeenSmartReplies(true);
1001 LogMaker logMaker = r.getLogMaker()
1002 .setCategory(MetricsEvent.SMART_REPLY_VISIBLE)
1003 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT,
1004 r.getNumSmartRepliesAdded())
1005 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_ACTION_COUNT,
1006 r.getNumSmartActionsAdded())
1007 .addTaggedData(
1008 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
Gustav Senntonc7d0d322019-01-07 15:36:41 +00001009 r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
1010 // The fields in the NotificationVisibility.NotificationLocation enum map
1011 // directly to the fields in the MetricsEvent.NotificationLocation enum.
Milo Sredkov13d88112019-02-01 12:23:24 +00001012 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, notificationLocation)
1013 .addTaggedData(
1014 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
1015 r.getEditChoicesBeforeSending() ? 1 : 0);
Gustav Sennton44dc5882018-12-13 14:38:50 +00001016 mMetricsLogger.write(logMaker);
1017 }
1018 }
1019
Julia Reynolds88860ce2017-06-01 16:55:49 -04001020 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04001021 private void clearSoundLocked() {
1022 mSoundNotificationKey = null;
1023 long identity = Binder.clearCallingIdentity();
1024 try {
1025 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
1026 if (player != null) {
1027 player.stopAsync();
1028 }
1029 } catch (RemoteException e) {
1030 } finally {
1031 Binder.restoreCallingIdentity(identity);
1032 }
1033 }
1034
Julia Reynolds88860ce2017-06-01 16:55:49 -04001035 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04001036 private void clearVibrateLocked() {
1037 mVibrateNotificationKey = null;
1038 long identity = Binder.clearCallingIdentity();
1039 try {
1040 mVibrator.cancel();
1041 } finally {
1042 Binder.restoreCallingIdentity(identity);
1043 }
1044 }
1045
Julia Reynolds88860ce2017-06-01 16:55:49 -04001046 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04001047 private void clearLightsLocked() {
1048 // light
1049 mLights.clear();
1050 updateLightsLocked();
1051 }
1052
Beverlyd4f96492017-08-02 13:36:11 -04001053 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
1054 @Override
1055 public void onReceive(Context context, Intent intent) {
1056 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
Beverly70dcd002018-03-29 17:09:16 -04001057 // update system notification channels
1058 SystemNotificationChannels.createAll(context);
Beverlyd4f96492017-08-02 13:36:11 -04001059 mZenModeHelper.updateDefaultZenRules();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001060 mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
Beverlyd4f96492017-08-02 13:36:11 -04001061 }
1062 }
1063 };
1064
Julia Reynoldsb852e562017-06-06 16:14:18 -04001065 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
1066 @Override
1067 public void onReceive(Context context, Intent intent) {
1068 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
1069 try {
1070 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
1071 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
Michal Karpinski6135a262017-08-11 10:45:58 +01001072 int restoredFromSdkInt = intent.getIntExtra(
1073 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
Julia Reynoldsfa206a42017-08-14 13:22:23 -04001074 mListeners.onSettingRestored(
1075 element, newValue, restoredFromSdkInt, getSendingUserId());
1076 mConditionProviders.onSettingRestored(
1077 element, newValue, restoredFromSdkInt, getSendingUserId());
Julia Reynoldsb852e562017-06-06 16:14:18 -04001078 } catch (Exception e) {
1079 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
1080 }
1081 }
1082 }
1083 };
1084
Julia Reynolds2a128742016-11-28 14:29:25 -05001085 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
1086 @Override
1087 public void onReceive(Context context, Intent intent) {
1088 String action = intent.getAction();
1089 if (action == null) {
1090 return;
1091 }
1092 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
1093 final NotificationRecord record;
1094 synchronized (mNotificationLock) {
1095 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
1096 }
1097 if (record != null) {
1098 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
1099 record.sbn.getPackageName(), record.sbn.getTag(),
1100 record.sbn.getId(), 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -04001101 FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
Julia Reynolds2a128742016-11-28 14:29:25 -05001102 REASON_TIMEOUT, null);
1103 }
1104 }
1105 }
1106 };
1107
Kenny Guy70058402014-10-28 20:45:06 +00001108 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 @Override
1110 public void onReceive(Context context, Intent intent) {
1111 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -08001112 if (action == null) {
1113 return;
1114 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001116 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -04001117 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -04001118 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -04001119 boolean cancelNotifications = true;
Beverly5a20a5e2018-03-06 15:02:44 -05001120 boolean hideNotifications = false;
1121 boolean unhideNotifications = false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001122 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -04001123
Chris Wren3da73022013-05-10 14:41:21 -04001124 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -04001125 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001126 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -04001127 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001128 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001129 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
Beverly5a20a5e2018-03-06 15:02:44 -05001130 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
Julia Reynolds0e5a3432019-01-17 09:40:46 -05001131 || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)
1132 || action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
Kenny Guy70058402014-10-28 20:45:06 +00001133 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1134 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001135 String pkgList[] = null;
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001136 int uidList[] = null;
Julia Reynolds6434eb22016-08-08 17:19:26 -04001137 boolean removingPackage = queryRemove &&
1138 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
1139 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001140 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001141 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001142 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001143 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
1144 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4bc42b92018-08-14 11:27:35 -04001145 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Beverly5a20a5e2018-03-06 15:02:44 -05001146 cancelNotifications = false;
1147 hideNotifications = true;
1148 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
1149 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4bc42b92018-08-14 11:27:35 -04001150 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Beverly5a20a5e2018-03-06 15:02:44 -05001151 cancelNotifications = false;
1152 unhideNotifications = true;
Julia Reynolds0e5a3432019-01-17 09:40:46 -05001153 } else if (action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
1154 final int distractionRestrictions =
1155 intent.getIntExtra(Intent.EXTRA_DISTRACTION_RESTRICTIONS,
1156 PackageManager.RESTRICTION_NONE);
1157 if ((distractionRestrictions
1158 & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0) {
1159 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1160 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1161 cancelNotifications = false;
1162 hideNotifications = true;
1163 } else {
1164 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1165 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1166 cancelNotifications = false;
1167 unhideNotifications = true;
1168 }
1169
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001170 } else if (queryRestart) {
1171 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001172 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001173 } else {
1174 Uri uri = intent.getData();
1175 if (uri == null) {
1176 return;
1177 }
1178 String pkgName = uri.getSchemeSpecificPart();
1179 if (pkgName == null) {
1180 return;
1181 }
Daniel Sandler26ece572012-06-01 15:38:46 -04001182 if (packageChanged) {
1183 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -07001184 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001185 final int enabled = mPackageManager.getApplicationEnabledSetting(
1186 pkgName,
Kenny Guy70058402014-10-28 20:45:06 +00001187 changeUserId != UserHandle.USER_ALL ? changeUserId :
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001188 USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -07001189 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1190 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
1191 cancelNotifications = false;
1192 }
1193 } catch (IllegalArgumentException e) {
1194 // Package doesn't exist; probably racing with uninstall.
1195 // cancelNotifications is already true, so nothing to do here.
1196 if (DBG) {
1197 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
1198 }
Kenny Guy70058402014-10-28 20:45:06 +00001199 } catch (RemoteException e) {
1200 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -04001201 }
1202 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001203 pkgList = new String[]{pkgName};
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001204 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001205 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001206 if (pkgList != null && (pkgList.length > 0)) {
1207 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -04001208 if (cancelNotifications) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001209 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
1210 !queryRestart, changeUserId, reason, null);
Beverly5a20a5e2018-03-06 15:02:44 -05001211 } else if (hideNotifications) {
1212 hideNotificationsForPackages(pkgList);
1213 } else if (unhideNotifications) {
1214 unhideNotificationsForPackages(pkgList);
John Spurlock79f78922013-05-16 09:10:05 -04001215 }
Beverly5a20a5e2018-03-06 15:02:44 -05001216
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001217 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 }
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001219
Julia Reynoldsb0405592018-11-26 17:01:13 -05001220 mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001221 handleSavePolicyFile();
Kenny Guy70058402014-10-28 20:45:06 +00001222 }
1223 }
1224 };
1225
1226 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1227 @Override
1228 public void onReceive(Context context, Intent intent) {
1229 String action = intent.getAction();
1230
1231 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001232 // Keep track of screen on/off state, but do not turn off the notification light
1233 // until user passes through the lock screen or views the notification.
1234 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +01001235 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001236 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1237 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +01001238 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001239 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -05001240 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
1241 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001242 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001243 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
1244 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1245 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001246 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001247 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001248 }
Rubin Xue95057a2016-04-01 16:49:25 +01001249 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001250 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +01001251 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001252 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001253 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001254 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001255 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1256 // turn off LED when user passes through lock screen
1257 mNotificationLight.turnOff();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001258 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Julia Reynolds4ff97492018-09-24 14:53:54 -04001259 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
John Spurlockb408e8e2014-04-23 21:12:45 -04001260 mUserProfiles.updateCache(context);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001261 if (!mUserProfiles.isManagedProfile(userId)) {
1262 // reload per-user settings
1263 mSettingsObserver.update(null);
1264 // Refresh managed services
1265 mConditionProviders.onUserSwitched(userId);
1266 mListeners.onUserSwitched(userId);
1267 mZenModeHelper.onUserSwitched(userId);
Beverly0479cde22018-11-09 11:05:34 -05001268 mPreferencesHelper.onUserSwitched(userId);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001269 }
1270 // assistant is the only thing that cares about managed profiles specifically
1271 mAssistants.onUserSwitched(userId);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001272 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001273 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1274 if (userId != USER_NULL) {
1275 mUserProfiles.updateCache(context);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001276 if (!mUserProfiles.isManagedProfile(userId)) {
1277 readDefaultApprovedServices(userId);
1278 }
Julia Reynolds88a879f2017-07-26 17:06:46 -04001279 }
John Spurlock21258a32015-05-27 18:22:55 -04001280 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
Julia Reynolds4ff97492018-09-24 14:53:54 -04001281 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001282 mUserProfiles.updateCache(context);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001283 mZenModeHelper.onUserRemoved(userId);
1284 mPreferencesHelper.onUserRemoved(userId);
1285 mListeners.onUserRemoved(userId);
1286 mConditionProviders.onUserRemoved(userId);
1287 mAssistants.onUserRemoved(userId);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001288 handleSavePolicyFile();
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001289 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
Julia Reynolds4ff97492018-09-24 14:53:54 -04001290 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1291 mUserProfiles.updateCache(context);
1292 mAssistants.onUserUnlocked(userId);
1293 if (!mUserProfiles.isManagedProfile(userId)) {
1294 mConditionProviders.onUserUnlocked(userId);
1295 mListeners.onUserUnlocked(userId);
1296 mZenModeHelper.onUserUnlocked(userId);
Beverly0479cde22018-11-09 11:05:34 -05001297 mPreferencesHelper.onUserUnlocked(userId);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001298 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299 }
1300 }
1301 };
1302
John Spurlock7c74f782015-06-04 13:01:42 -04001303 private final class SettingsObserver extends ContentObserver {
Chris Wren89aa2262017-05-05 18:05:56 -04001304 private final Uri NOTIFICATION_BADGING_URI
1305 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
Julia Reynolds4509ce72019-01-31 13:12:43 -05001306 private final Uri NOTIFICATION_BUBBLES_URI
1307 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BUBBLES);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001308 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1309 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wren763a9bb2016-05-31 17:14:12 -04001310 private final Uri NOTIFICATION_RATE_LIMIT_URI
1311 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001312
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001313 SettingsObserver(Handler handler) {
1314 super(handler);
1315 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001316
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001317 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001318 ContentResolver resolver = getContext().getContentResolver();
Chris Wren89aa2262017-05-05 18:05:56 -04001319 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1320 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001321 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -07001322 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -04001323 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1324 false, this, UserHandle.USER_ALL);
Julia Reynolds4509ce72019-01-31 13:12:43 -05001325 resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI,
1326 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001327 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001328 }
1329
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001330 @Override public void onChange(boolean selfChange, Uri uri) {
1331 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001332 }
1333
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001334 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001335 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001336 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
zhoulei7e376972017-05-17 18:41:25 +08001337 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
Julia Reynolds28149f62018-07-03 10:43:35 -04001338 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT)
1339 != 0;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001340 if (mNotificationPulseEnabled != pulseEnabled) {
1341 mNotificationPulseEnabled = pulseEnabled;
1342 updateNotificationPulse();
1343 }
1344 }
Chris Wren763a9bb2016-05-31 17:14:12 -04001345 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1346 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1347 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1348 }
Chris Wren89aa2262017-05-05 18:05:56 -04001349 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001350 mPreferencesHelper.updateBadgingEnabled();
Chris Wren89aa2262017-05-05 18:05:56 -04001351 }
Julia Reynolds4509ce72019-01-31 13:12:43 -05001352 if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) {
1353 mPreferencesHelper.updateBubblesEnabled();
1354 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001355 }
1356 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001357
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001358 private SettingsObserver mSettingsObserver;
Beverlyd4f96492017-08-02 13:36:11 -04001359 protected ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001360
Daniel Sandleredbb3802012-11-13 20:49:47 -08001361 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1362 int[] ar = r.getIntArray(resid);
1363 if (ar == null) {
1364 return def;
1365 }
1366 final int len = ar.length > maxlen ? maxlen : ar.length;
1367 long[] out = new long[len];
1368 for (int i=0; i<len; i++) {
1369 out[i] = ar[i];
1370 }
1371 return out;
1372 }
1373
Jeff Brownb880d882014-02-10 19:47:07 -08001374 public NotificationManagerService(Context context) {
1375 super(context);
Dianne Hackborn98305522017-05-05 17:53:53 -07001376 Notification.processWhitelistToken = WHITELIST_TOKEN;
Jeff Brownb880d882014-02-10 19:47:07 -08001377 }
1378
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001379 // TODO - replace these methods with a single VisibleForTesting constructor
Chris Wren93bb8b82016-03-29 14:35:05 -04001380 @VisibleForTesting
1381 void setAudioManager(AudioManager audioMananger) {
1382 mAudioManager = audioMananger;
1383 }
1384
1385 @VisibleForTesting
Julia Reynoldsdb7081e2019-01-03 14:35:38 -05001386 void setHints(int hints) {
1387 mListenerHints = hints;
1388 }
1389
1390 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001391 void setVibrator(Vibrator vibrator) {
1392 mVibrator = vibrator;
1393 }
1394
1395 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001396 void setLights(Light light) {
1397 mNotificationLight = light;
1398 mAttentionLight = light;
Julia Reynolds033a4122017-01-31 16:50:38 -05001399 mNotificationPulseEnabled = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001400 }
1401
1402 @VisibleForTesting
1403 void setScreenOn(boolean on) {
1404 mScreenOn = on;
1405 }
1406
1407 @VisibleForTesting
Julia Reynolds080361e2017-07-13 11:23:12 -04001408 int getNotificationRecordCount() {
1409 synchronized (mNotificationLock) {
1410 int count = mNotificationList.size() + mNotificationsByKey.size()
1411 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1412 // subtract duplicates
1413 for (NotificationRecord posted : mNotificationList) {
1414 if (mNotificationsByKey.containsKey(posted.getKey())) {
1415 count--;
1416 }
1417 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001418 count--;
Julia Reynolds080361e2017-07-13 11:23:12 -04001419 }
1420 }
1421
1422 return count;
1423 }
1424 }
1425
Julia Reynolds7380d872018-01-12 10:28:26 -05001426 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001427 void clearNotifications() {
1428 mEnqueuedNotifications.clear();
1429 mNotificationList.clear();
1430 mNotificationsByKey.clear();
1431 mSummaryByGroupKey.clear();
1432 }
1433
Julia Reynolds080361e2017-07-13 11:23:12 -04001434 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001435 void addNotification(NotificationRecord r) {
1436 mNotificationList.add(r);
1437 mNotificationsByKey.put(r.sbn.getKey(), r);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001438 if (r.sbn.isGroup()) {
1439 mSummaryByGroupKey.put(r.getGroupKey(), r);
1440 }
1441 }
1442
1443 @VisibleForTesting
1444 void addEnqueuedNotification(NotificationRecord r) {
1445 mEnqueuedNotifications.add(r);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001446 }
1447
1448 @VisibleForTesting
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001449 NotificationRecord getNotificationRecord(String key) {
1450 return mNotificationsByKey.get(key);
1451 }
1452
1453
1454 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001455 void setSystemReady(boolean systemReady) {
1456 mSystemReady = systemReady;
1457 }
1458
1459 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001460 void setHandler(WorkerHandler handler) {
Chris Wren93bb8b82016-03-29 14:35:05 -04001461 mHandler = handler;
1462 }
1463
Chris Wrend4054312016-06-24 17:07:40 -04001464 @VisibleForTesting
Julia Reynolds0c299d42016-11-15 14:37:04 -05001465 void setFallbackVibrationPattern(long[] vibrationPattern) {
1466 mFallbackVibrationPattern = vibrationPattern;
Chris Wrend4054312016-06-24 17:07:40 -04001467 }
1468
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001469 @VisibleForTesting
1470 void setPackageManager(IPackageManager packageManager) {
1471 mPackageManager = packageManager;
1472 }
1473
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001474 @VisibleForTesting
1475 void setRankingHelper(RankingHelper rankingHelper) {
1476 mRankingHelper = rankingHelper;
1477 }
1478
1479 @VisibleForTesting
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001480 void setPreferencesHelper(PreferencesHelper prefHelper) { mPreferencesHelper = prefHelper; }
1481
1482 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001483 void setRankingHandler(RankingHandler rankingHandler) {
1484 mRankingHandler = rankingHandler;
1485 }
1486
1487 @VisibleForTesting
Adora Zhang963328f2018-11-15 18:17:19 -08001488 void setIsAutomotive(boolean isAutomotive) {
1489 mIsAutomotive = isAutomotive;
1490 }
1491
1492 @VisibleForTesting
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001493 void setIsTelevision(boolean isTelevision) {
1494 mIsTelevision = isTelevision;
1495 }
1496
Julia Reynolds76c096d2017-06-19 08:16:04 -04001497 @VisibleForTesting
1498 void setUsageStats(NotificationUsageStats us) {
1499 mUsageStats = us;
1500 }
1501
Julia Reynolds94187562017-10-10 13:58:49 -04001502 @VisibleForTesting
1503 void setAccessibilityManager(AccessibilityManager am) {
1504 mAccessibilityManager = am;
1505 }
1506
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001507 // TODO: All tests should use this init instead of the one-off setters above.
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001508 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001509 void init(Looper looper, IPackageManager packageManager,
1510 PackageManager packageManagerClient,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001511 LightsManager lightsManager, NotificationListeners notificationListeners,
Julia Reynoldsb852e562017-06-06 16:14:18 -04001512 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001513 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
Julia Reynolds68263d12017-06-21 14:21:19 -04001514 NotificationUsageStats usageStats, AtomicFile policyFile,
Julia Reynolds7217dc92018-03-07 12:12:09 -05001515 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001516 UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04001517 IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps) {
Chris Wren54bbef42014-07-09 18:37:56 -04001518 Resources resources = getContext().getResources();
Chris Wren763a9bb2016-05-31 17:14:12 -04001519 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1520 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1521 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1522
Julia Reynolds94187562017-10-10 13:58:49 -04001523 mAccessibilityManager =
1524 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001525 mAm = am;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001526 mUgm = ugm;
1527 mUgmInternal = ugmInternal;
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001528 mPackageManager = packageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001529 mPackageManagerClient = packageManagerClient;
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04001530 mAppOps = appOps;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001531 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Julia Reynolds7217dc92018-03-07 12:12:09 -05001532 mAppUsageStats = appUsageStats;
Julia Reynolds2a128742016-11-28 14:29:25 -05001533 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001534 mCompanionManager = companionManager;
Julia Reynolds68263d12017-06-21 14:21:19 -04001535 mActivityManager = activityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -08001536 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1537 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
Jason Parks50322ff2018-03-27 10:23:33 -05001538 mDpm = dpm;
1539
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001540 mHandler = new WorkerHandler(looper);
Chris Wrenf9536642014-04-17 10:01:54 -04001541 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -04001542 String[] extractorNames;
1543 try {
1544 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1545 } catch (Resources.NotFoundException e) {
1546 extractorNames = new String[0];
1547 }
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001548 mUsageStats = usageStats;
Kenny Guy23991102018-04-05 21:18:38 +01001549 mMetricsLogger = new MetricsLogger();
Chris Wren51017d02015-12-15 15:34:46 -05001550 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Julia Reynoldsb852e562017-06-06 16:14:18 -04001551 mConditionProviders = conditionProviders;
John Spurlockb2278d62015-04-07 12:47:12 -04001552 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -04001553 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -04001554 @Override
1555 public void onConfigChanged() {
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001556 handleSavePolicyFile();
John Spurlock056c5192014-04-20 21:52:01 -04001557 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001558
1559 @Override
1560 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001561 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -05001562 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -05001563 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1564 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -05001565 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001566 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02001567 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001568 }
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001569 mRankingHandler.requestSort();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001570 }
John Spurlock1fc476d2015-04-14 16:05:20 -04001571
1572 @Override
1573 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001574 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001575 mRankingHandler.requestSort();
John Spurlock80774932015-05-07 17:38:50 -04001576 }
John Spurlock056c5192014-04-20 21:52:01 -04001577 });
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001578 mPreferencesHelper = new PreferencesHelper(getContext(),
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001579 mPackageManagerClient,
1580 mRankingHandler,
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001581 mZenModeHelper);
1582 mRankingHelper = new RankingHelper(getContext(),
1583 mRankingHandler,
1584 mPreferencesHelper,
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001585 mZenModeHelper,
1586 mUsageStats,
1587 extractorNames);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001588 mSnoozeHelper = snoozeHelper;
Julia Reynolds8aebf352017-06-26 11:35:33 -04001589 mGroupHelper = groupHelper;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04001590
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001591 // This is a ManagedServices object that keeps track of the listeners.
1592 mListeners = notificationListeners;
Chris Wren0efdb882016-03-01 17:17:47 -05001593
Julia Reynolds77b2cc92016-11-08 14:41:09 -05001594 // This is a MangedServices object that keeps track of the assistant.
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001595 mAssistants = notificationAssistants;
Julia Reynoldsb852e562017-06-06 16:14:18 -04001596
Kristian Monsen30f59b22018-04-09 10:27:16 +02001597 // Needs to be set before loadPolicyFile
1598 mAllowedManagedServicePackages = this::canUseManagedServices;
1599
Julia Reynoldsb852e562017-06-06 16:14:18 -04001600 mPolicyFile = policyFile;
1601 loadPolicyFile();
Chris Wren0efdb882016-03-01 17:17:47 -05001602
Adam Lesinski182f73f2013-12-05 16:48:06 -08001603 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -08001604 if (mStatusBar != null) {
1605 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001608 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1609 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001610
Daniel Sandleredbb3802012-11-13 20:49:47 -08001611 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001612 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001613 VIBRATE_PATTERN_MAXLEN,
1614 DEFAULT_VIBRATE_PATTERN);
Beverly5d463b62017-07-26 14:13:40 -04001615 mInCallNotificationUri = Uri.parse("file://" +
1616 resources.getString(R.string.config_inCallNotificationSound));
1617 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1618 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1619 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
Beverly5d463b62017-07-26 14:13:40 -04001620 .build();
1621 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1622
Chris Wren5116a822014-06-04 15:59:50 -04001623 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
Julia Reynolds28149f62018-07-03 10:43:35 -04001624 mHasLight =
1625 resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
Chris Wren5116a822014-06-04 15:59:50 -04001626
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001627 // Don't start allowing notifications until the setup wizard has run once.
1628 // After that, including subsequent boots, init with notifications turned on.
1629 // This works on the first boot because the setup wizard will toggle this
1630 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001631 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001632 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001633 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001634 }
John Spurlockb2278d62015-04-07 12:47:12 -04001635 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001636 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001637
John Spurlockb408e8e2014-04-23 21:12:45 -04001638 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001639 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001640
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001641 mSettingsObserver = new SettingsObserver(mHandler);
1642
1643 mArchive = new Archive(resources.getInteger(
1644 R.integer.config_notificationServiceArchiveSize));
1645
1646 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1647 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
Adora Zhang963328f2018-11-15 18:17:19 -08001648
1649 mIsAutomotive =
1650 mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0);
Julia Reynolds413ba842019-01-11 10:38:08 -05001651
1652 mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray(
1653 com.android.internal.R.array.config_nonBlockableNotificationPackages));
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001654 }
1655
1656 @Override
1657 public void onStart() {
1658 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1659 @Override
1660 public void repost(int userId, NotificationRecord r) {
1661 try {
1662 if (DBG) {
1663 Slog.d(TAG, "Reposting " + r.getKey());
1664 }
1665 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1666 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1667 r.sbn.getNotification(), userId);
1668 } catch (Exception e) {
1669 Slog.e(TAG, "Cannot un-snooze notification", e);
1670 }
1671 }
1672 }, mUserProfiles);
1673
1674 final File systemDir = new File(Environment.getDataDirectory(), "system");
1675
1676 init(Looper.myLooper(),
1677 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1678 getLocalService(LightsManager.class),
1679 new NotificationListeners(AppGlobals.getPackageManager()),
Julia Reynolds7380d872018-01-12 10:28:26 -05001680 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
1681 AppGlobals.getPackageManager()),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001682 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1683 null, snoozeHelper, new NotificationUsageStats(getContext()),
Dianne Hackborne17b4452018-01-10 13:15:40 -08001684 new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001685 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
Julia Reynolds7217dc92018-03-07 12:12:09 -05001686 getGroupHelper(), ActivityManager.getService(),
Jason Parks50322ff2018-03-27 10:23:33 -05001687 LocalServices.getService(UsageStatsManagerInternal.class),
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001688 LocalServices.getService(DevicePolicyManagerInternal.class),
1689 UriGrantsManager.getService(),
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04001690 LocalServices.getService(UriGrantsManagerInternal.class),
1691 (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE));
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001692
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001693 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001694 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001695 filter.addAction(Intent.ACTION_SCREEN_ON);
1696 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001697 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001698 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001699 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001700 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001701 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001702 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001703 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001704 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001705 getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
Kenny Guy70058402014-10-28 20:45:06 +00001706
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001707 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001708 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001709 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001710 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001711 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1712 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1713 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001714 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1715 null);
1716
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001717 IntentFilter suspendedPkgFilter = new IntentFilter();
1718 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
Beverly5a20a5e2018-03-06 15:02:44 -05001719 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
Julia Reynolds0e5a3432019-01-17 09:40:46 -05001720 suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001721 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1722 suspendedPkgFilter, null, null);
1723
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001724 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001725 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1726 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001727
Julia Reynolds2a128742016-11-28 14:29:25 -05001728 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1729 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1730 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1731
Julia Reynoldsb852e562017-06-06 16:14:18 -04001732 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1733 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1734
Beverlyd4f96492017-08-02 13:36:11 -04001735 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1736 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1737
Vishnu Naire3e4d252018-03-01 11:26:57 -08001738 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
1739 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001740 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 }
1742
Julia Reynolds8aebf352017-06-26 11:35:33 -04001743 private GroupHelper getGroupHelper() {
Adora Zhang48dd614a82018-06-25 19:18:41 -07001744 mAutoGroupAtCount =
1745 getContext().getResources().getInteger(R.integer.config_autoGroupAtCount);
1746 return new GroupHelper(mAutoGroupAtCount, new GroupHelper.Callback() {
Julia Reynolds8aebf352017-06-26 11:35:33 -04001747 @Override
1748 public void addAutoGroup(String key) {
1749 synchronized (mNotificationLock) {
1750 addAutogroupKeyLocked(key);
1751 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001752 }
1753
1754 @Override
1755 public void removeAutoGroup(String key) {
1756 synchronized (mNotificationLock) {
1757 removeAutogroupKeyLocked(key);
1758 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001759 }
1760
1761 @Override
1762 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1763 createAutoGroupSummary(userId, pkg, triggeringKey);
1764 }
1765
1766 @Override
1767 public void removeAutoGroupSummary(int userId, String pkg) {
1768 synchronized (mNotificationLock) {
1769 clearAutogroupSummaryLocked(userId, pkg);
1770 }
1771 }
1772 });
1773 }
1774
John Spurlocke7a835b2015-05-13 10:47:05 -04001775 private void sendRegisteredOnlyBroadcast(String action) {
Julia Reynolds4c456dd2019-01-07 12:22:00 -05001776 Intent intent = new Intent(action);
1777 getContext().sendBroadcastAsUser(intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
1778 UserHandle.ALL, null);
1779 // explicitly send the broadcast to all DND packages, even if they aren't currently running
1780 intent.setFlags(0);
1781 final Set<String> dndApprovedPackages = mConditionProviders.getAllowedPackages();
1782 for (String pkg : dndApprovedPackages) {
1783 intent.setPackage(pkg);
1784 getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
1785 }
John Spurlocke7a835b2015-05-13 10:47:05 -04001786 }
1787
Adam Lesinski182f73f2013-12-05 16:48:06 -08001788 @Override
1789 public void onBootPhase(int phase) {
1790 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1791 // no beeping until we're basically done booting
1792 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001793
Adam Lesinski182f73f2013-12-05 16:48:06 -08001794 // Grab our optional AudioService
1795 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001796 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001797 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001798 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001799 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1800 // This observer will force an update when observe is called, causing us to
1801 // bind to listener services.
1802 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001803 mListeners.onBootPhaseAppsCanStart();
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001804 mAssistants.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001805 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 }
1807 }
1808
Julia Reynolds88860ce2017-06-01 16:55:49 -04001809 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04001810 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001811 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001812 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001813 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001814 mListenerHints = hints;
1815 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001816 }
1817
Julia Reynolds88860ce2017-06-01 16:55:49 -04001818 @GuardedBy("mNotificationLock")
John Spurlockb4782522014-08-22 14:54:46 -04001819 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001820 final long updatedSuppressedEffects = calculateSuppressedEffects();
1821 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1822 final List<ComponentName> suppressors = getSuppressors();
1823 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1824 mEffectsSuppressors = suppressors;
1825 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001826 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001827 }
1828
Amith Yamasani396a10c2018-01-19 10:58:07 -08001829 private void exitIdle() {
1830 try {
1831 if (mDeviceIdleController != null) {
1832 mDeviceIdleController.exitIdle("notification interaction");
1833 }
1834 } catch (RemoteException e) {
1835 }
1836 }
1837
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001838 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1839 boolean fromListener) {
Julia Reynolds924eed12017-01-19 09:52:07 -05001840 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1841 // cancel
1842 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001843 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
Julia Reynolds924eed12017-01-19 09:52:07 -05001844 null);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001845 if (isUidSystemOrPhone(uid)) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001846 IntArray profileIds = mUserProfiles.getCurrentProfileIds();
1847 int N = profileIds.size();
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001848 for (int i = 0; i < N; i++) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001849 int profileId = profileIds.get(i);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001850 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1851 profileId, REASON_CHANNEL_BANNED,
1852 null);
1853 }
1854 }
Julia Reynolds924eed12017-01-19 09:52:07 -05001855 }
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001856 final NotificationChannel preUpdate =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001857 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001858
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001859 mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001860 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
Julia Reynolds924eed12017-01-19 09:52:07 -05001861
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001862 if (!fromListener) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001863 final NotificationChannel modifiedChannel =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001864 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001865 mListeners.notifyNotificationChannelChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001866 pkg, UserHandle.getUserHandleForUid(uid),
1867 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001868 }
1869
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001870 handleSavePolicyFile();
Julia Reynolds924eed12017-01-19 09:52:07 -05001871 }
1872
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001873 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1874 NotificationChannel update) {
1875 try {
1876 if ((preUpdate.getImportance() == IMPORTANCE_NONE
1877 && update.getImportance() != IMPORTANCE_NONE)
1878 || (preUpdate.getImportance() != IMPORTANCE_NONE
1879 && update.getImportance() == IMPORTANCE_NONE)) {
1880 getContext().sendBroadcastAsUser(
1881 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001882 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001883 update.getId())
1884 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1885 update.getImportance() == IMPORTANCE_NONE)
1886 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1887 .setPackage(pkg),
1888 UserHandle.of(UserHandle.getUserId(uid)), null);
1889 }
1890 } catch (SecurityException e) {
1891 Slog.w(TAG, "Can't notify app about channel change", e);
1892 }
1893 }
1894
Julia Reynolds005c8b92017-08-24 10:35:53 -04001895 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
1896 boolean fromApp, boolean fromListener) {
1897 Preconditions.checkNotNull(group);
1898 Preconditions.checkNotNull(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001899
1900 final NotificationChannelGroup preUpdate =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001901 mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
1902 mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group,
Julia Reynolds005c8b92017-08-24 10:35:53 -04001903 fromApp);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001904 if (!fromApp) {
1905 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
1906 }
Julia Reynolds005c8b92017-08-24 10:35:53 -04001907 if (!fromListener) {
1908 mListeners.notifyNotificationChannelGroupChanged(pkg,
1909 UserHandle.of(UserHandle.getCallingUserId()), group,
1910 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1911 }
1912 }
1913
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001914 private void maybeNotifyChannelGroupOwner(String pkg, int uid,
1915 NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
1916 try {
1917 if (preUpdate.isBlocked() != update.isBlocked()) {
1918 getContext().sendBroadcastAsUser(
1919 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001920 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001921 update.getId())
1922 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1923 update.isBlocked())
1924 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1925 .setPackage(pkg),
1926 UserHandle.of(UserHandle.getUserId(uid)), null);
1927 }
1928 } catch (SecurityException e) {
1929 Slog.w(TAG, "Can't notify app about group change", e);
1930 }
1931 }
1932
Bryce Lee7219ada2016-04-08 10:54:23 -07001933 private ArrayList<ComponentName> getSuppressors() {
1934 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1935 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04001936 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07001937
Julia Reynolds4703bac2018-09-12 10:39:30 -04001938 for (ComponentName info : serviceInfoList) {
1939 names.add(info);
Bryce Lee7219ada2016-04-08 10:54:23 -07001940 }
1941 }
1942
1943 return names;
1944 }
1945
1946 private boolean removeDisabledHints(ManagedServiceInfo info) {
1947 return removeDisabledHints(info, 0);
1948 }
1949
1950 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1951 boolean removed = false;
1952
1953 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1954 final int hint = mListenersDisablingEffects.keyAt(i);
Julia Reynolds4703bac2018-09-12 10:39:30 -04001955 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07001956
1957 if (hints == 0 || (hint & hints) == hint) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04001958 removed |= listeners.remove(info.component);
Bryce Lee7219ada2016-04-08 10:54:23 -07001959 }
1960 }
1961
1962 return removed;
1963 }
1964
1965 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1966 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1967 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1968 }
1969
1970 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1971 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1972 }
1973
1974 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1975 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1976 }
1977 }
1978
1979 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1980 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04001981 mListenersDisablingEffects.put(hint, new ArraySet<>());
Bryce Lee7219ada2016-04-08 10:54:23 -07001982 }
1983
Julia Reynolds4703bac2018-09-12 10:39:30 -04001984 ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint);
1985 hintListeners.add(info.component);
Bryce Lee7219ada2016-04-08 10:54:23 -07001986 }
1987
1988 private int calculateHints() {
1989 int hints = 0;
1990 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1991 int hint = mListenersDisablingEffects.keyAt(i);
Julia Reynolds4703bac2018-09-12 10:39:30 -04001992 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07001993
1994 if (!serviceInfoList.isEmpty()) {
1995 hints |= hint;
1996 }
1997 }
1998
1999 return hints;
2000 }
2001
2002 private long calculateSuppressedEffects() {
2003 int hints = calculateHints();
2004 long suppressedEffects = 0;
2005
2006 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2007 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
2008 }
2009
2010 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
2011 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
2012 }
2013
2014 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
2015 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
2016 }
2017
2018 return suppressedEffects;
2019 }
2020
Julia Reynolds88860ce2017-06-01 16:55:49 -04002021 @GuardedBy("mNotificationLock")
Christoph Studer85a384b2014-08-27 20:16:15 +02002022 private void updateInterruptionFilterLocked() {
2023 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
2024 if (interruptionFilter == mInterruptionFilter) return;
2025 mInterruptionFilter = interruptionFilter;
2026 scheduleInterruptionFilterChanged(interruptionFilter);
2027 }
2028
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05002029 @VisibleForTesting
2030 INotificationManager getBinderService() {
2031 return INotificationManager.Stub.asInterface(mService);
2032 }
2033
Amith Yamasani7ec89412018-02-07 08:48:49 -08002034 /**
2035 * Report to usage stats that the notification was seen.
2036 * @param r notification record
2037 */
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002038 @GuardedBy("mNotificationLock")
Amith Yamasani803eab692017-11-09 17:47:04 -08002039 protected void reportSeen(NotificationRecord r) {
Julia Reynolds95334132018-12-19 11:15:35 -05002040 if (!r.isProxied()) {
2041 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2042 getRealUserId(r.sbn.getUserId()),
2043 UsageEvents.Event.NOTIFICATION_SEEN);
2044 }
Amith Yamasani803eab692017-11-09 17:47:04 -08002045 }
2046
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05002047 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
2048 int targetSdkVersion) {
2049 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
2050 return incomingPolicy.suppressedVisualEffects;
2051 }
2052 final int[] effectsIntroducedInP = {
2053 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
2054 SUPPRESSED_EFFECT_LIGHTS,
2055 SUPPRESSED_EFFECT_PEEK,
2056 SUPPRESSED_EFFECT_STATUS_BAR,
2057 SUPPRESSED_EFFECT_BADGE,
2058 SUPPRESSED_EFFECT_AMBIENT,
2059 SUPPRESSED_EFFECT_NOTIFICATION_LIST
2060 };
2061
2062 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06002063 if (targetSdkVersion < Build.VERSION_CODES.P) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05002064 // unset higher order bits introduced in P, maintain the user's higher order bits
2065 for (int i = 0; i < effectsIntroducedInP.length ; i++) {
2066 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
2067 newSuppressedVisualEffects |=
2068 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
2069 }
2070 // set higher order bits according to lower order bits
2071 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
2072 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
2073 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05002074 }
2075 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
2076 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
2077 }
2078 } else {
2079 boolean hasNewEffects = (newSuppressedVisualEffects
2080 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
2081 // if any of the new effects introduced in P are set
2082 if (hasNewEffects) {
2083 // clear out the deprecated effects
2084 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
2085 | SUPPRESSED_EFFECT_SCREEN_OFF);
2086
2087 // set the deprecated effects according to the new more specific effects
2088 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
2089 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
2090 }
2091 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
2092 && (newSuppressedVisualEffects
2093 & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
2094 && (newSuppressedVisualEffects
2095 & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
2096 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
2097 }
2098 } else {
2099 // set higher order bits according to lower order bits
2100 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
2101 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
2102 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
2103 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
2104 }
2105 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
2106 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
2107 }
2108 }
2109 }
2110
2111 return newSuppressedVisualEffects;
2112 }
2113
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002114 @GuardedBy("mNotificationLock")
2115 protected void maybeRecordInterruptionLocked(NotificationRecord r) {
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04002116 if (r.isInterruptive() && !r.hasRecordedInterruption()) {
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002117 mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
2118 r.getChannel().getId(),
2119 getRealUserId(r.sbn.getUserId()));
Julia Reynoldsad7d7132018-03-21 16:05:00 -04002120 logRecentLocked(r);
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04002121 r.setRecordedInterruption(true);
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002122 }
2123 }
2124
Amith Yamasani7ec89412018-02-07 08:48:49 -08002125 /**
Esteban Talavera917a71d2018-11-13 07:55:08 +00002126 * Report to usage stats that the user interacted with the notification.
Amith Yamasani7ec89412018-02-07 08:48:49 -08002127 * @param r notification record
2128 */
2129 protected void reportUserInteraction(NotificationRecord r) {
Amith Yamasani7ec89412018-02-07 08:48:49 -08002130 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002131 getRealUserId(r.sbn.getUserId()),
Amith Yamasani7ec89412018-02-07 08:48:49 -08002132 UsageEvents.Event.USER_INTERACTION);
2133 }
2134
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002135 private int getRealUserId(int userId) {
2136 return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
2137 }
2138
Geoffrey Pitsch415e4542017-04-10 13:12:58 -04002139 @VisibleForTesting
2140 NotificationManagerInternal getInternalService() {
2141 return mInternalService;
2142 }
2143
Beverly58b24532018-10-02 09:08:23 -04002144 @VisibleForTesting
2145 final IBinder mService = new INotificationManager.Stub() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002146 // Toasts
2147 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002149 @Override
Jeff Chang48ecef42018-08-09 16:31:59 +08002150 public void enqueueToast(String pkg, ITransientNotification callback, int duration,
2151 int displayId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002153 if (DBG) {
2154 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
Jeff Chang48ecef42018-08-09 16:31:59 +08002155 + " duration=" + duration + " displayId=" + displayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002157
2158 if (pkg == null || callback == null) {
Beverly58b24532018-10-02 09:08:23 -04002159 Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " callback=" + callback);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002160 return ;
2161 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002162
Beverly58b24532018-10-02 09:08:23 -04002163 final int callingUid = Binder.getCallingUid();
2164 final boolean isSystemToast = isCallerSystemOrPhone()
2165 || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg);
2166 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
2167 final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg,
2168 callingUid);
2169
2170 long callingIdentity = Binder.clearCallingIdentity();
2171 try {
2172 final boolean appIsForeground = mActivityManager.getUidImportance(callingUid)
2173 == IMPORTANCE_FOREGROUND;
2174 if (ENABLE_BLOCKED_TOASTS && !isSystemToast && ((notificationsDisabledForPackage
2175 && !appIsForeground) || isPackageSuspended)) {
2176 Slog.e(TAG, "Suppressing toast from package " + pkg
2177 + (isPackageSuspended ? " due to package suspended."
2178 : " by user request."));
2179 return;
2180 }
2181 } finally {
2182 Binder.restoreCallingIdentity(callingIdentity);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002183 }
2184
2185 synchronized (mToastQueue) {
2186 int callingPid = Binder.getCallingPid();
2187 long callingId = Binder.clearCallingIdentity();
2188 try {
2189 ToastRecord record;
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002190 int index = indexOfToastLocked(pkg, callback);
2191 // If it's already in the queue, we update it in place, we don't
2192 // move it to the end of the queue.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002193 if (index >= 0) {
2194 record = mToastQueue.get(index);
2195 record.update(duration);
2196 } else {
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002197 // Limit the number of toasts that any given package except the android
2198 // package can enqueue. Prevents DOS attacks and deals with leaks.
2199 if (!isSystemToast) {
2200 int count = 0;
2201 final int N = mToastQueue.size();
2202 for (int i=0; i<N; i++) {
2203 final ToastRecord r = mToastQueue.get(i);
2204 if (r.pkg.equals(pkg)) {
2205 count++;
2206 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2207 Slog.e(TAG, "Package has already posted " + count
2208 + " toasts. Not showing more. Package=" + pkg);
2209 return;
2210 }
2211 }
2212 }
2213 }
2214
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002215 Binder token = new Binder();
Jeff Chang48ecef42018-08-09 16:31:59 +08002216 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, displayId);
2217 record = new ToastRecord(callingPid, pkg, callback, duration, token,
2218 displayId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002219 mToastQueue.add(record);
2220 index = mToastQueue.size() - 1;
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002221 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002222 }
2223 // If it's at index 0, it's the current toast. It doesn't matter if it's
2224 // new or just been updated. Call back and tell it to show itself.
2225 // If the callback fails, this will remove it from the list, so don't
2226 // assume that it's valid after this.
2227 if (index == 0) {
2228 showNextToastLocked();
2229 }
2230 } finally {
2231 Binder.restoreCallingIdentity(callingId);
2232 }
2233 }
2234 }
2235
2236 @Override
2237 public void cancelToast(String pkg, ITransientNotification callback) {
2238 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
2239
2240 if (pkg == null || callback == null) {
2241 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
2242 return ;
2243 }
2244
2245 synchronized (mToastQueue) {
2246 long callingId = Binder.clearCallingIdentity();
2247 try {
2248 int index = indexOfToastLocked(pkg, callback);
2249 if (index >= 0) {
2250 cancelToastLocked(index);
2251 } else {
2252 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
2253 + " callback=" + callback);
2254 }
2255 } finally {
2256 Binder.restoreCallingIdentity(callingId);
2257 }
2258 }
2259 }
2260
2261 @Override
Robert Carr997427342018-02-28 18:06:10 -08002262 public void finishToken(String pkg, ITransientNotification callback) {
2263 synchronized (mToastQueue) {
2264 long callingId = Binder.clearCallingIdentity();
2265 try {
2266 int index = indexOfToastLocked(pkg, callback);
2267 if (index >= 0) {
2268 ToastRecord record = mToastQueue.get(index);
Jeff Chang48ecef42018-08-09 16:31:59 +08002269 finishTokenLocked(record.token, record.displayId);
Robert Carr997427342018-02-28 18:06:10 -08002270 } else {
2271 Slog.w(TAG, "Toast already killed. pkg=" + pkg
2272 + " callback=" + callback);
2273 }
2274 } finally {
2275 Binder.restoreCallingIdentity(callingId);
2276 }
2277 }
2278 }
2279
2280 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002281 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002282 Notification notification, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002283 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002284 Binder.getCallingPid(), tag, id, notification, userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002285 }
2286
2287 @Override
2288 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002289 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002290 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2291 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002292 // Don't allow client applications to cancel foreground service notis or autobundled
2293 // summaries.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002294 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
Julia Reynoldse5c60452018-04-30 14:41:36 -04002295 (FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
John Spurlocke6a7d932014-03-13 12:29:00 -04002296 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002297 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002298 }
2299
2300 @Override
2301 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002302 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002303
2304 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2305 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
2306
2307 // Calling from user space, don't allow the canceling of actively
2308 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04002309 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
Julia Reynoldse5c60452018-04-30 14:41:36 -04002310 pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05002311 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002312 }
2313
2314 @Override
2315 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
Rohan Shahca0447e2018-03-30 15:18:27 -07002316 enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002317
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002318 mPreferencesHelper.setEnabled(pkg, uid, enabled);
Howard Ro8b56f752018-08-07 15:44:25 -07002319 mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
2320 .setType(MetricsEvent.TYPE_ACTION)
2321 .setPackageName(pkg)
2322 .setSubtype(enabled ? 1 : 0));
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002323 // Now, cancel any outstanding notifications that are part of a just-disabled app
Julia Reynolds4da79702017-06-01 11:06:10 -04002324 if (!enabled) {
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002325 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
2326 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
2327 }
Julia Reynoldsfc9767b2018-01-22 17:45:16 -05002328
2329 try {
2330 getContext().sendBroadcastAsUser(
2331 new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
2332 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
2333 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2334 .setPackage(pkg),
2335 UserHandle.of(UserHandle.getUserId(uid)), null);
2336 } catch (SecurityException e) {
2337 Slog.w(TAG, "Can't notify app about app block change", e);
2338 }
2339
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002340 handleSavePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002341 }
2342
2343 /**
Rohan Shah590e1b22018-04-10 23:48:47 -04002344 * Updates the enabled state for notifications for the given package (and uid).
2345 * Additionally, this method marks the app importance as locked by the user, which means
2346 * that notifications from the app will <b>not</b> be considered for showing a
2347 * blocking helper.
2348 *
2349 * @param pkg package that owns the notifications to update
2350 * @param uid uid of the app providing notifications
2351 * @param enabled whether notifications should be enabled for the app
2352 *
2353 * @see #setNotificationsEnabledForPackage(String, int, boolean)
2354 */
2355 @Override
2356 public void setNotificationsEnabledWithImportanceLockForPackage(
2357 String pkg, int uid, boolean enabled) {
2358 setNotificationsEnabledForPackage(pkg, uid, enabled);
2359
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002360 mPreferencesHelper.setAppImportanceLocked(pkg, uid);
Rohan Shah590e1b22018-04-10 23:48:47 -04002361 }
2362
2363 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002364 * Use this when you just want to know if notifications are OK for this package.
2365 */
2366 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002367 public boolean areNotificationsEnabled(String pkg) {
2368 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
2369 }
2370
2371 /**
2372 * Use this when you just want to know if notifications are OK for this package.
2373 */
2374 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002375 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002376 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002377
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002378 return mPreferencesHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002379 }
2380
Chris Wren54bbef42014-07-09 18:37:56 -04002381 @Override
Mady Mellorc39b4ae2019-01-09 17:11:37 -08002382 public boolean areBubblesAllowed(String pkg) {
2383 return areBubblesAllowedForPackage(pkg, Binder.getCallingUid());
Julia Reynolds33ab8a02018-12-17 16:19:52 -05002384 }
2385
2386 @Override
Mady Mellorc39b4ae2019-01-09 17:11:37 -08002387 public boolean areBubblesAllowedForPackage(String pkg, int uid) {
2388 enforceSystemOrSystemUIOrSamePackage(pkg,
2389 "Caller not system or systemui or same package");
Mady Mellor9db685a2019-01-23 13:23:37 -08002390 return mPreferencesHelper.areBubblesAllowed(pkg, uid);
Julia Reynolds33ab8a02018-12-17 16:19:52 -05002391 }
2392
2393 @Override
Mady Mellorc39b4ae2019-01-09 17:11:37 -08002394 public void setBubblesAllowed(String pkg, int uid, boolean allowed) {
Mady Mellor9db685a2019-01-23 13:23:37 -08002395 enforceSystemOrSystemUI("Caller not system or systemui");
Mady Mellorc39b4ae2019-01-09 17:11:37 -08002396 mPreferencesHelper.setBubblesAllowed(pkg, uid, allowed);
Julia Reynolds33ab8a02018-12-17 16:19:52 -05002397 handleSavePolicyFile();
2398 }
2399
2400 @Override
Mady Mellor9db685a2019-01-23 13:23:37 -08002401 public boolean hasUserApprovedBubblesForPackage(String pkg, int uid) {
2402 enforceSystemOrSystemUI("Caller not system or systemui");
2403 int lockedFields = mPreferencesHelper.getAppLockedFields(pkg, uid);
2404 return (lockedFields & PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE) != 0;
2405 }
2406
2407 @Override
Julia Reynolds12ad7ca2019-01-28 09:29:16 -05002408 public boolean shouldHideSilentStatusIcons(String callingPkg) {
2409 checkCallerIsSameApp(callingPkg);
2410
2411 if (isCallerSystemOrPhone()
2412 || mListeners.isListenerPackage(callingPkg)) {
2413 return mPreferencesHelper.shouldHideSilentStatusIcons();
2414 } else {
2415 throw new SecurityException("Only available for notification listeners");
2416 }
2417 }
2418
2419 @Override
2420 public void setHideSilentStatusIcons(boolean hide) {
2421 checkCallerIsSystem();
2422
2423 mPreferencesHelper.setHideSilentStatusIcons(hide);
2424 handleSavePolicyFile();
2425
2426 mListeners.onStatusBarIconsBehaviorChanged(hide);
2427 }
2428
2429 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05002430 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002431 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002432 return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002433 }
2434
2435 @Override
Julia Reynolds924eed12017-01-19 09:52:07 -05002436 public boolean canShowBadge(String pkg, int uid) {
2437 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002438 return mPreferencesHelper.canShowBadge(pkg, uid);
Julia Reynolds924eed12017-01-19 09:52:07 -05002439 }
2440
2441 @Override
2442 public void setShowBadge(String pkg, int uid, boolean showBadge) {
2443 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002444 mPreferencesHelper.setShowBadge(pkg, uid, showBadge);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002445 handleSavePolicyFile();
Julia Reynolds924eed12017-01-19 09:52:07 -05002446 }
2447
2448 @Override
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002449 public void setNotificationDelegate(String callingPkg, String delegate) {
2450 checkCallerIsSameApp(callingPkg);
2451 final int callingUid = Binder.getCallingUid();
2452 UserHandle user = UserHandle.getUserHandleForUid(callingUid);
2453 try {
2454 ApplicationInfo info =
2455 mPackageManager.getApplicationInfo(delegate,
2456 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
2457 user.getIdentifier());
2458 if (info != null) {
2459 mPreferencesHelper.setNotificationDelegate(
2460 callingPkg, callingUid, delegate, info.uid);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002461 handleSavePolicyFile();
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002462 }
2463 } catch (RemoteException e) {
2464 // :(
2465 }
2466 }
2467
2468 @Override
2469 public void revokeNotificationDelegate(String callingPkg) {
2470 checkCallerIsSameApp(callingPkg);
2471 mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid());
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002472 handleSavePolicyFile();
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002473 }
2474
2475 @Override
2476 public String getNotificationDelegate(String callingPkg) {
2477 // callable by Settings also
2478 checkCallerIsSystemOrSameApp(callingPkg);
2479 return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid());
2480 }
2481
2482 @Override
2483 public boolean canNotifyAsPackage(String callingPkg, String targetPkg) {
2484 checkCallerIsSameApp(callingPkg);
2485 final int callingUid = Binder.getCallingUid();
2486 UserHandle user = UserHandle.getUserHandleForUid(callingUid);
2487 try {
2488 ApplicationInfo info =
2489 mPackageManager.getApplicationInfo(targetPkg,
2490 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
2491 user.getIdentifier());
2492 if (info != null) {
2493 return mPreferencesHelper.isDelegateAllowed(
2494 targetPkg, info.uid, callingPkg, callingUid);
2495 }
2496 } catch (RemoteException e) {
2497 // :(
2498 }
2499 return false;
2500 }
2501
2502 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002503 public void updateNotificationChannelGroupForPackage(String pkg, int uid,
2504 NotificationChannelGroup group) throws RemoteException {
2505 enforceSystemOrSystemUI("Caller not system or systemui");
2506 createNotificationChannelGroup(pkg, uid, group, false, false);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002507 handleSavePolicyFile();
Julia Reynolds005c8b92017-08-24 10:35:53 -04002508 }
2509
2510 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002511 public void createNotificationChannelGroups(String pkg,
2512 ParceledListSlice channelGroupList) throws RemoteException {
2513 checkCallerIsSystemOrSameApp(pkg);
2514 List<NotificationChannelGroup> groups = channelGroupList.getList();
2515 final int groupSize = groups.size();
2516 for (int i = 0; i < groupSize; i++) {
2517 final NotificationChannelGroup group = groups.get(i);
Julia Reynolds005c8b92017-08-24 10:35:53 -04002518 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002519 }
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002520 handleSavePolicyFile();
Julia Reynolds59e152e2017-01-25 17:42:53 -05002521 }
2522
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002523 private void createNotificationChannelsImpl(String pkg, int uid,
2524 ParceledListSlice channelsList) {
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002525 List<NotificationChannel> channels = channelsList.getList();
2526 final int channelsSize = channels.size();
2527 for (int i = 0; i < channelsSize; i++) {
2528 final NotificationChannel channel = channels.get(i);
2529 Preconditions.checkNotNull(channel, "channel in list is null");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002530 mPreferencesHelper.createNotificationChannel(pkg, uid, channel,
Julia Reynolds1fe10942018-03-28 12:46:51 -04002531 true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed(
2532 pkg, UserHandle.getUserId(uid)));
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002533 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002534 UserHandle.getUserHandleForUid(uid),
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002535 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002536 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002537 }
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002538 handleSavePolicyFile();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002539 }
2540
2541 @Override
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002542 public void createNotificationChannels(String pkg,
2543 ParceledListSlice channelsList) throws RemoteException {
2544 checkCallerIsSystemOrSameApp(pkg);
2545 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
2546 }
2547
2548 @Override
2549 public void createNotificationChannelsForPackage(String pkg, int uid,
2550 ParceledListSlice channelsList) throws RemoteException {
2551 checkCallerIsSystem();
2552 createNotificationChannelsImpl(pkg, uid, channelsList);
2553 }
2554
2555 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002556 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002557 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002558 return mPreferencesHelper.getNotificationChannel(
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002559 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002560 }
2561
2562 @Override
2563 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002564 String channelId, boolean includeDeleted) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002565 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002566 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002567 }
2568
2569 @Override
2570 public void deleteNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002571 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002572 final int callingUid = Binder.getCallingUid();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002573 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
2574 throw new IllegalArgumentException("Cannot delete default channel");
2575 }
2576 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002577 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002578 mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002579 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002580 UserHandle.getUserHandleForUid(callingUid),
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002581 mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002582 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002583 handleSavePolicyFile();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002584 }
2585
2586 @Override
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002587 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
2588 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002589 return mPreferencesHelper.getNotificationChannelGroupWithChannels(
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002590 pkg, Binder.getCallingUid(), groupId, false);
2591 }
2592
2593 @Override
Julia Reynolds9bfba592017-03-15 14:03:55 -04002594 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
2595 String pkg) {
2596 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002597 return mPreferencesHelper.getNotificationChannelGroups(
Julia Reynolds13ed28b2018-09-21 15:20:13 -04002598 pkg, Binder.getCallingUid(), false, false, true);
Julia Reynolds9bfba592017-03-15 14:03:55 -04002599 }
2600
2601 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002602 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04002603 checkCallerIsSystemOrSameApp(pkg);
2604
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002605 final int callingUid = Binder.getCallingUid();
2606 NotificationChannelGroup groupToDelete =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002607 mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002608 if (groupToDelete != null) {
2609 List<NotificationChannel> deletedChannels =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002610 mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002611 for (int i = 0; i < deletedChannels.size(); i++) {
2612 final NotificationChannel deletedChannel = deletedChannels.get(i);
2613 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2614 true,
2615 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2616 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002617 mListeners.notifyNotificationChannelChanged(pkg,
2618 UserHandle.getUserHandleForUid(callingUid),
2619 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002620 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2621 }
2622 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002623 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2624 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002625 handleSavePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002626 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04002627 }
2628
2629 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002630 public void updateNotificationChannelForPackage(String pkg, int uid,
2631 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002632 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05002633 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002634 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002635 }
2636
2637 @Override
2638 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002639 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002640 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002641 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002642 }
2643
2644 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002645 public int getNumNotificationChannelsForPackage(String pkg, int uid,
2646 boolean includeDeleted) {
2647 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002648 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted)
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002649 .getList().size();
2650 }
2651
2652 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04002653 public boolean onlyHasDefaultChannel(String pkg, int uid) {
2654 enforceSystemOrSystemUI("onlyHasDefaultChannel");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002655 return mPreferencesHelper.onlyHasDefaultChannel(pkg, uid);
Julia Reynolds17717f52017-05-09 11:46:06 -04002656 }
2657
2658 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04002659 public int getDeletedChannelCount(String pkg, int uid) {
2660 enforceSystemOrSystemUI("getDeletedChannelCount");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002661 return mPreferencesHelper.getDeletedChannelCount(pkg, uid);
Julia Reynolds41103f42017-03-15 11:36:35 -04002662 }
2663
2664 @Override
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002665 public int getBlockedChannelCount(String pkg, int uid) {
2666 enforceSystemOrSystemUI("getBlockedChannelCount");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002667 return mPreferencesHelper.getBlockedChannelCount(pkg, uid);
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002668 }
2669
2670 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002671 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2672 String pkg, int uid, boolean includeDeleted) {
2673 checkCallerIsSystem();
Julia Reynolds13ed28b2018-09-21 15:20:13 -04002674 return mPreferencesHelper.getNotificationChannelGroups(
2675 pkg, uid, includeDeleted, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002676 }
2677
2678 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002679 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2680 String pkg, int uid, String groupId, boolean includeDeleted) {
2681 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002682 return mPreferencesHelper.getNotificationChannelGroupWithChannels(
Julia Reynolds005c8b92017-08-24 10:35:53 -04002683 pkg, uid, groupId, includeDeleted);
2684 }
2685
2686 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002687 public NotificationChannelGroup getNotificationChannelGroupForPackage(
2688 String groupId, String pkg, int uid) {
2689 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002690 return mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, uid);
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002691 }
2692
2693 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002694 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
2695 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002696 return mPreferencesHelper.getNotificationChannels(
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002697 pkg, Binder.getCallingUid(), false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002698 }
2699
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002700 @Override
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05002701 public ParceledListSlice<NotifyingApp> getRecentNotifyingAppsForUser(int userId) {
2702 checkCallerIsSystem();
2703 synchronized (mNotificationLock) {
2704 List<NotifyingApp> apps = new ArrayList<>(
2705 mRecentApps.getOrDefault(userId, new ArrayList<>()));
2706 return new ParceledListSlice<>(apps);
2707 }
2708 }
2709
2710 @Override
Julia Reynoldse273f082018-04-12 13:48:49 -04002711 public int getBlockedAppCount(int userId) {
2712 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002713 return mPreferencesHelper.getBlockedAppCount(userId);
Julia Reynoldse273f082018-04-12 13:48:49 -04002714 }
2715
2716 @Override
Beverly0479cde22018-11-09 11:05:34 -05002717 public int getAppsBypassingDndCount(int userId) {
2718 checkCallerIsSystem();
2719 return mPreferencesHelper.getAppsBypassingDndCount(userId);
2720 }
2721
2722 @Override
2723 public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd(
2724 String pkg, int userId) {
2725 checkCallerIsSystem();
2726 return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, userId);
2727 }
2728
2729 @Override
Beverly86d076f2018-04-17 14:44:52 -04002730 public boolean areChannelsBypassingDnd() {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002731 return mPreferencesHelper.areChannelsBypassingDnd();
Beverly86d076f2018-04-17 14:44:52 -04002732 }
2733
2734 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05002735 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002736 checkCallerIsSystem();
2737
2738 // Cancel posted notifications
2739 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2740 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2741
Julia Reynoldsb852e562017-06-06 16:14:18 -04002742 final String[] packages = new String[] {packageName};
2743 final int[] uids = new int[] {uid};
2744
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002745 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04002746 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002747 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002748
2749 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04002750 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002751
Julia Reynolds67c1e962019-01-04 14:01:10 -05002752 // Snoozing
2753 mSnoozeHelper.clearData(UserHandle.getUserId(uid), packageName);
2754
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002755 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05002756 if (!fromApp) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002757 mPreferencesHelper.onPackagesChanged(
Julia Reynoldsb852e562017-06-06 16:14:18 -04002758 true, UserHandle.getCallingUserId(), packages, uids);
Julia Reynolds5355e852017-02-07 14:54:13 -05002759 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002760
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002761 handleSavePolicyFile();
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002762 }
2763
2764
Adam Lesinski182f73f2013-12-05 16:48:06 -08002765 /**
2766 * System-only API for getting a list of current (i.e. not cleared) notifications.
2767 *
2768 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04002769 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002770 */
2771 @Override
2772 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2773 // enforce() will ensure the calling uid has the correct permission
2774 getContext().enforceCallingOrSelfPermission(
2775 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2776 "NotificationManagerService.getActiveNotifications");
2777
2778 StatusBarNotification[] tmp = null;
2779 int uid = Binder.getCallingUid();
2780
2781 // noteOp will check to make sure the callingPkg matches the uid
2782 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2783 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002784 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002785 tmp = new StatusBarNotification[mNotificationList.size()];
2786 final int N = mNotificationList.size();
2787 for (int i=0; i<N; i++) {
2788 tmp[i] = mNotificationList.get(i).sbn;
2789 }
2790 }
2791 }
2792 return tmp;
2793 }
2794
2795 /**
Dan Sandler994349c2015-04-15 11:02:54 -04002796 * Public API for getting a list of current notifications for the calling package/uid.
2797 *
Julia Reynolds573c6532017-01-24 17:44:38 -05002798 * Note that since notification posting is done asynchronously, this will not return
2799 * notifications that are in the process of being posted.
2800 *
Julia Reynoldsd12392c2018-12-17 14:06:04 -05002801 * From {@link Build.VERSION_CODES#Q}, will also return notifications you've posted as
2802 * an app's notification delegate via
2803 * {@link NotificationManager#notifyAsPackage(String, String, int, Notification)}.
2804 *
Dan Sandler994349c2015-04-15 11:02:54 -04002805 * @returns A list of all the package's notifications, in natural order.
2806 */
2807 @Override
2808 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2809 int incomingUserId) {
2810 checkCallerIsSystemOrSameApp(pkg);
2811 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2812 Binder.getCallingUid(), incomingUserId, true, false,
2813 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002814 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002815 final ArrayMap<String, StatusBarNotification> map
2816 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002817 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002818 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002819 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2820 mNotificationList.get(i).sbn);
2821 if (sbn != null) {
2822 map.put(sbn.getKey(), sbn);
2823 }
2824 }
2825 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2826 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2827 if (sbn != null) {
2828 map.put(sbn.getKey(), sbn);
2829 }
2830 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002831 final int M = mEnqueuedNotifications.size();
2832 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002833 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2834 mEnqueuedNotifications.get(i).sbn);
2835 if (sbn != null) {
2836 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04002837 }
2838 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002839 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2840 list.addAll(map.values());
2841 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04002842 }
Dan Sandler994349c2015-04-15 11:02:54 -04002843 }
2844
Chris Wren6676dab2016-12-21 18:26:27 -05002845 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2846 StatusBarNotification sbn) {
Julia Reynoldsd12392c2018-12-17 14:06:04 -05002847 if (sbn.getUserId() == userId) {
2848 if (sbn.getPackageName().equals(pkg) || sbn.getOpPkg().equals(pkg)) {
2849 // We could pass back a cloneLight() but clients might get confused and
2850 // try to send this thing back to notify() again, which would not work
2851 // very well.
2852 return new StatusBarNotification(
2853 sbn.getPackageName(),
2854 sbn.getOpPkg(),
2855 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2856 sbn.getNotification().clone(),
2857 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2858 }
Chris Wren6676dab2016-12-21 18:26:27 -05002859 }
2860 return null;
2861 }
2862
Dan Sandler994349c2015-04-15 11:02:54 -04002863 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002864 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2865 *
2866 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2867 */
2868 @Override
2869 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2870 // enforce() will ensure the calling uid has the correct permission
2871 getContext().enforceCallingOrSelfPermission(
2872 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2873 "NotificationManagerService.getHistoricalNotifications");
2874
2875 StatusBarNotification[] tmp = null;
2876 int uid = Binder.getCallingUid();
2877
2878 // noteOp will check to make sure the callingPkg matches the uid
2879 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2880 == AppOpsManager.MODE_ALLOWED) {
2881 synchronized (mArchive) {
2882 tmp = mArchive.getArray(count);
2883 }
2884 }
2885 return tmp;
2886 }
2887
2888 /**
2889 * Register a listener binder directly with the notification manager.
2890 *
2891 * Only works with system callers. Apps should extend
2892 * {@link android.service.notification.NotificationListenerService}.
2893 */
2894 @Override
2895 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05002896 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02002897 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05002898 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002899 }
2900
2901 /**
2902 * Remove a listener binder directly
2903 */
2904 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002905 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05002906 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002907 }
2908
2909 /**
2910 * Allow an INotificationListener to simulate a "clear all" operation.
2911 *
2912 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2913 *
2914 * @param token The binder for the listener, to check that the caller is allowed
2915 */
2916 @Override
John Spurlocka4294292014-03-24 18:02:32 -04002917 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002918 final int callingUid = Binder.getCallingUid();
2919 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002920 long identity = Binder.clearCallingIdentity();
2921 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002922 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002923 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Beverly5a20a5e2018-03-06 15:02:44 -05002924
John Spurlocka4294292014-03-24 18:02:32 -04002925 if (keys != null) {
2926 final int N = keys.length;
2927 for (int i = 0; i < N; i++) {
2928 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07002929 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00002930 final int userId = r.sbn.getUserId();
2931 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04002932 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00002933 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04002934 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00002935 }
Griff Hazen335e1f02014-09-11 14:49:31 -07002936 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2937 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2938 userId);
John Spurlocka4294292014-03-24 18:02:32 -04002939 }
2940 } else {
2941 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00002942 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04002943 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002944 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002945 } finally {
2946 Binder.restoreCallingIdentity(identity);
2947 }
2948 }
2949
Chris Wrenab41eec2016-01-04 18:01:27 -05002950 /**
2951 * Handle request from an approved listener to re-enable itself.
2952 *
2953 * @param component The componenet to be re-enabled, caller must match package.
2954 */
2955 @Override
2956 public void requestBindListener(ComponentName component) {
2957 checkCallerIsSystemOrSameApp(component.getPackageName());
2958 long identity = Binder.clearCallingIdentity();
2959 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002960 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002961 mAssistants.isComponentEnabledForCurrentProfiles(component)
2962 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05002963 : mListeners;
2964 manager.setComponentState(component, true);
2965 } finally {
2966 Binder.restoreCallingIdentity(identity);
2967 }
2968 }
2969
2970 @Override
2971 public void requestUnbindListener(INotificationListener token) {
2972 long identity = Binder.clearCallingIdentity();
2973 try {
2974 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002975 synchronized (mNotificationLock) {
2976 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2977 info.getOwner().setComponentState(info.component, false);
2978 }
Chris Wrenab41eec2016-01-04 18:01:27 -05002979 } finally {
2980 Binder.restoreCallingIdentity(identity);
2981 }
2982 }
2983
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002984 @Override
2985 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002986 long identity = Binder.clearCallingIdentity();
2987 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002988 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002989 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04002990 if (keys == null) {
2991 return;
2992 }
2993 ArrayList<NotificationRecord> seen = new ArrayList<>();
2994 final int n = keys.length;
2995 for (int i = 0; i < n; i++) {
2996 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2997 if (r == null) continue;
2998 final int userId = r.sbn.getUserId();
2999 if (userId != info.userid && userId != UserHandle.USER_ALL
3000 && !mUserProfiles.isCurrentProfile(userId)) {
3001 throw new SecurityException("Disallowed call from listener: "
3002 + info.service);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07003003 }
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04003004 seen.add(r);
3005 if (!r.isSeen()) {
3006 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
3007 reportSeen(r);
3008 r.setSeen();
3009 maybeRecordInterruptionLocked(r);
3010 }
3011 }
3012 if (!seen.isEmpty()) {
3013 mAssistants.onNotificationsSeenLocked(seen);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07003014 }
3015 }
3016 } finally {
3017 Binder.restoreCallingIdentity(identity);
3018 }
3019 }
3020
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003021 /**
3022 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
3023 *
3024 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
3025 *
Julia Reynolds79672302017-01-12 08:30:16 -05003026 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003027 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04003028 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04003029 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00003030 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04003031 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -04003032 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
John Spurlocka4294292014-03-24 18:02:32 -04003033 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00003034 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04003035 }
3036
Adam Lesinski182f73f2013-12-05 16:48:06 -08003037 /**
Julia Reynolds79672302017-01-12 08:30:16 -05003038 * Allow an INotificationListener to snooze a single notification until a context.
3039 *
3040 * @param token The binder for the listener, to check that the caller is allowed
3041 */
3042 @Override
3043 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
3044 String key, String snoozeCriterionId) {
3045 long identity = Binder.clearCallingIdentity();
3046 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003047 synchronized (mNotificationLock) {
3048 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3049 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
3050 }
Julia Reynolds79672302017-01-12 08:30:16 -05003051 } finally {
3052 Binder.restoreCallingIdentity(identity);
3053 }
3054 }
3055
3056 /**
3057 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003058 *
3059 * @param token The binder for the listener, to check that the caller is allowed
3060 */
3061 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003062 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05003063 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003064 long identity = Binder.clearCallingIdentity();
3065 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003066 synchronized (mNotificationLock) {
3067 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3068 snoozeNotificationInt(key, duration, null, info);
3069 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003070 } finally {
3071 Binder.restoreCallingIdentity(identity);
3072 }
3073 }
3074
3075 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05003076 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003077 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05003078 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003079 */
3080 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05003081 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003082 long identity = Binder.clearCallingIdentity();
3083 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003084 synchronized (mNotificationLock) {
3085 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003086 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003087 unsnoozeNotificationInt(key, info);
3088 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003089 } finally {
3090 Binder.restoreCallingIdentity(identity);
3091 }
3092 }
3093
3094 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08003095 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
3096 *
3097 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
3098 *
3099 * @param token The binder for the listener, to check that the caller is allowed
3100 */
3101 @Override
3102 public void cancelNotificationFromListener(INotificationListener token, String pkg,
3103 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04003104 final int callingUid = Binder.getCallingUid();
3105 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08003106 long identity = Binder.clearCallingIdentity();
3107 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003108 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04003109 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00003110 if (info.supportsProfiles()) {
3111 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
3112 + "from " + info.component
3113 + " use cancelNotification(key) instead.");
3114 } else {
3115 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
3116 pkg, tag, id, info.userid);
3117 }
Adam Lesinskie8240262014-03-26 16:01:00 -07003118 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003119 } finally {
3120 Binder.restoreCallingIdentity(identity);
3121 }
3122 }
3123
3124 /**
3125 * Allow an INotificationListener to request the list of outstanding notifications seen by
3126 * the current user. Useful when starting up, after which point the listener callbacks
3127 * should be used.
3128 *
3129 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04003130 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04003131 * @returns The return value will contain the notifications specified in keys, in that
3132 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08003133 */
3134 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02003135 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02003136 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003137 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04003138 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04003139 final boolean getKeys = keys != null;
3140 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02003141 final ArrayList<StatusBarNotification> list
3142 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02003143 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04003144 final NotificationRecord r = getKeys
3145 ? mNotificationsByKey.get(keys[i])
3146 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02003147 if (r == null) continue;
3148 StatusBarNotification sbn = r.sbn;
3149 if (!isVisibleToListener(sbn, info)) continue;
3150 StatusBarNotification sbnToSend =
3151 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
3152 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003153 }
Christoph Studercee44ba2014-05-20 18:36:43 +02003154 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003155 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003156 }
3157
Julia Reynoldscf63ff12017-01-24 13:55:48 -05003158 /**
3159 * Allow an INotificationListener to request the list of outstanding snoozed notifications
3160 * seen by the current user. Useful when starting up, after which point the listener
3161 * callbacks should be used.
3162 *
3163 * @param token The binder for the listener, to check that the caller is allowed
3164 * @returns The return value will contain the notifications specified in keys, in that
3165 * order, or if keys is null, all the notifications, in natural order.
3166 */
3167 @Override
3168 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
3169 INotificationListener token, int trim) {
3170 synchronized (mNotificationLock) {
3171 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3172 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
3173 final int N = snoozedRecords.size();
3174 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
3175 for (int i=0; i < N; i++) {
3176 final NotificationRecord r = snoozedRecords.get(i);
3177 if (r == null) continue;
3178 StatusBarNotification sbn = r.sbn;
3179 if (!isVisibleToListener(sbn, info)) continue;
3180 StatusBarNotification sbnToSend =
3181 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
3182 list.add(sbnToSend);
3183 }
3184 return new ParceledListSlice<>(list);
3185 }
3186 }
3187
Adam Lesinski182f73f2013-12-05 16:48:06 -08003188 @Override
Julia Reynolds4703bac2018-09-12 10:39:30 -04003189 public void clearRequestedListenerHints(INotificationListener token) {
3190 final long identity = Binder.clearCallingIdentity();
3191 try {
3192 synchronized (mNotificationLock) {
3193 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3194 removeDisabledHints(info);
3195 updateListenerHintsLocked();
3196 updateEffectsSuppressorLocked();
3197 }
3198 } finally {
3199 Binder.restoreCallingIdentity(identity);
3200 }
3201 }
3202
3203 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04003204 public void requestHintsFromListener(INotificationListener token, int hints) {
3205 final long identity = Binder.clearCallingIdentity();
3206 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003207 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003208 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07003209 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
3210 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
3211 | HINT_HOST_DISABLE_CALL_EFFECTS;
3212 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04003213 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003214 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003215 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07003216 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003217 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04003218 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04003219 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04003220 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04003221 } finally {
3222 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04003223 }
3224 }
3225
3226 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04003227 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003228 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003229 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04003230 }
3231 }
3232
3233 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02003234 public void requestInterruptionFilterFromListener(INotificationListener token,
3235 int interruptionFilter) throws RemoteException {
3236 final long identity = Binder.clearCallingIdentity();
3237 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003238 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05003239 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3240 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02003241 updateInterruptionFilterLocked();
3242 }
3243 } finally {
3244 Binder.restoreCallingIdentity(identity);
3245 }
3246 }
3247
3248 @Override
3249 public int getInterruptionFilterFromListener(INotificationListener token)
3250 throws RemoteException {
3251 synchronized (mNotificationLight) {
3252 return mInterruptionFilter;
3253 }
3254 }
3255
3256 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02003257 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
3258 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003259 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02003260 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3261 if (info == null) return;
3262 mListeners.setOnNotificationPostedTrimLocked(info, trim);
3263 }
3264 }
3265
3266 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04003267 public int getZenMode() {
3268 return mZenModeHelper.getZenMode();
3269 }
3270
3271 @Override
John Spurlock056c5192014-04-20 21:52:01 -04003272 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003273 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04003274 return mZenModeHelper.getConfig();
3275 }
3276
3277 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04003278 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003279 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05003280 final long identity = Binder.clearCallingIdentity();
3281 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04003282 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05003283 } finally {
3284 Binder.restoreCallingIdentity(identity);
3285 }
3286 }
3287
3288 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05003289 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003290 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05003291 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003292 }
3293
3294 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003295 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
3296 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003297 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003298 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003299 }
3300
3301 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05003302 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003303 throws RemoteException {
3304 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
3305 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
Julia Reynolds68062072018-08-06 15:38:21 -04003306 if (automaticZenRule.getOwner() == null
3307 && automaticZenRule.getConfigurationActivity() == null) {
3308 throw new NullPointerException(
3309 "Rule must have a conditionproviderservice and/or configuration activity");
3310 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003311 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003312 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003313
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003314 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
3315 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003316 }
3317
3318 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05003319 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003320 throws RemoteException {
3321 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
3322 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
Julia Reynolds68062072018-08-06 15:38:21 -04003323 if (automaticZenRule.getOwner() == null
3324 && automaticZenRule.getConfigurationActivity() == null) {
3325 throw new NullPointerException(
3326 "Rule must have a conditionproviderservice and/or configuration activity");
3327 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003328 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
3329 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003330
Julia Reynolds361e82d32016-02-26 18:19:49 -05003331 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003332 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003333 }
3334
3335 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003336 public boolean removeAutomaticZenRule(String id) throws RemoteException {
3337 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003338 // Verify that they can modify zen rules.
3339 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
3340
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003341 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003342 }
3343
3344 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05003345 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
3346 Preconditions.checkNotNull(packageName, "Package name is null");
3347 enforceSystemOrSystemUI("removeAutomaticZenRules");
3348
3349 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
3350 }
3351
3352 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05003353 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
3354 Preconditions.checkNotNull(owner, "Owner is null");
3355 enforceSystemOrSystemUI("getRuleInstanceCount");
3356
3357 return mZenModeHelper.getCurrentInstanceCount(owner);
3358 }
3359
3360 @Override
Julia Reynolds68062072018-08-06 15:38:21 -04003361 public void setAutomaticZenRuleState(String id, Condition condition) {
3362 Preconditions.checkNotNull(id, "id is null");
3363 Preconditions.checkNotNull(condition, "Condition is null");
3364
3365 enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
3366
3367 mZenModeHelper.setAutomaticZenRuleState(id, condition);
3368 }
3369
3370 @Override
John Spurlock80774932015-05-07 17:38:50 -04003371 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
3372 enforcePolicyAccess(pkg, "setInterruptionFilter");
3373 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
3374 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
3375 final long identity = Binder.clearCallingIdentity();
3376 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04003377 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04003378 } finally {
3379 Binder.restoreCallingIdentity(identity);
3380 }
3381 }
3382
3383 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04003384 public void notifyConditions(final String pkg, IConditionProvider provider,
3385 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04003386 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3387 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04003388 mHandler.post(new Runnable() {
3389 @Override
3390 public void run() {
3391 mConditionProviders.notifyConditions(pkg, info, conditions);
3392 }
3393 });
John Spurlocke77bb362014-04-26 10:24:59 -04003394 }
3395
Julia Reynolds38e6ca42016-08-08 08:38:09 -04003396 @Override
3397 public void requestUnbindProvider(IConditionProvider provider) {
3398 long identity = Binder.clearCallingIdentity();
3399 try {
3400 // allow bound services to disable themselves
3401 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3402 info.getOwner().setComponentState(info.component, false);
3403 } finally {
3404 Binder.restoreCallingIdentity(identity);
3405 }
3406 }
3407
3408 @Override
3409 public void requestBindProvider(ComponentName component) {
3410 checkCallerIsSystemOrSameApp(component.getPackageName());
3411 long identity = Binder.clearCallingIdentity();
3412 try {
3413 mConditionProviders.setComponentState(component, true);
3414 } finally {
3415 Binder.restoreCallingIdentity(identity);
3416 }
3417 }
3418
John Spurlocke77bb362014-04-26 10:24:59 -04003419 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003420 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04003421 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
3422 message);
John Spurlock7340fc82014-04-24 18:50:12 -04003423 }
3424
Julia Reynolds48034f82016-03-09 10:15:16 -05003425 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
3426 try {
3427 checkCallerIsSystemOrSameApp(pkg);
3428 } catch (SecurityException e) {
3429 getContext().enforceCallingPermission(
3430 android.Manifest.permission.STATUS_BAR_SERVICE,
3431 message);
3432 }
3433 }
3434
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003435 private void enforcePolicyAccess(int uid, String method) {
3436 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3437 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3438 return;
3439 }
3440 boolean accessAllowed = false;
3441 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
3442 final int packageCount = packages.length;
3443 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003444 if (mConditionProviders.isPackageOrComponentAllowed(
3445 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003446 accessAllowed = true;
3447 }
3448 }
3449 if (!accessAllowed) {
3450 Slog.w(TAG, "Notification policy access denied calling " + method);
3451 throw new SecurityException("Notification policy access denied");
3452 }
3453 }
3454
John Spurlock80774932015-05-07 17:38:50 -04003455 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04003456 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3457 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3458 return;
3459 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04003460 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003461 if (!checkPolicyAccess(pkg)) {
3462 Slog.w(TAG, "Notification policy access denied calling " + method);
3463 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04003464 }
3465 }
3466
John Spurlock80774932015-05-07 17:38:50 -04003467 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003468 return mConditionProviders.isPackageOrComponentAllowed(
3469 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04003470 }
3471
3472 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003473 try {
Jason Parks50322ff2018-03-27 10:23:33 -05003474 int uid = getContext().getPackageManager().getPackageUidAsUser(pkg,
3475 UserHandle.getCallingUserId());
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003476 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
3477 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
3478 -1, true)) {
3479 return true;
3480 }
3481 } catch (NameNotFoundException e) {
3482 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003483 }
Jason Parks50322ff2018-03-27 10:23:33 -05003484 return checkPackagePolicyAccess(pkg)
3485 || mListeners.isComponentEnabledForPackage(pkg)
3486 || (mDpm != null &&
3487 mDpm.isActiveAdminWithPolicy(Binder.getCallingUid(),
3488 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER));
John Spurlock1fc476d2015-04-14 16:05:20 -04003489 }
3490
John Spurlock7340fc82014-04-24 18:50:12 -04003491 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08003492 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003493 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04003494 final DumpFilter filter = DumpFilter.parseFromArguments(args);
Makoto Onukibbb4b222018-06-25 16:01:02 -07003495 final long token = Binder.clearCallingIdentity();
3496 try {
3497 if (filter.stats) {
3498 dumpJson(pw, filter);
3499 } else if (filter.proto) {
3500 dumpProto(fd, filter);
3501 } else if (filter.criticalPriority) {
3502 dumpNotificationRecords(pw, filter);
3503 } else {
3504 dumpImpl(pw, filter);
3505 }
3506 } finally {
3507 Binder.restoreCallingIdentity(token);
Chris Wrene4b38802015-07-07 15:54:19 -04003508 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003509 }
John Spurlockb4782522014-08-22 14:54:46 -04003510
3511 @Override
3512 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07003513 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04003514 }
John Spurlock2b122f42014-08-27 16:29:47 -04003515
3516 @Override
3517 public boolean matchesCallFilter(Bundle extras) {
3518 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02003519 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003520 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02003521 extras,
3522 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
3523 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
3524 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04003525 }
John Spurlock530052a2014-11-30 16:26:19 -05003526
3527 @Override
3528 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003529 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04003530 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05003531 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003532
Christopher Tatef9767d62015-04-08 14:35:43 -07003533 // Backup/restore interface
3534 @Override
3535 public byte[] getBackupPayload(int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003536 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003537 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Julia Reynolds8a613f82018-12-13 14:25:13 -05003538 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
3539 try {
Annie Meng8b646fd2019-02-01 18:46:42 +00003540 writePolicyXml(baos, true /*forBackup*/, user);
Julia Reynolds8a613f82018-12-13 14:25:13 -05003541 return baos.toByteArray();
3542 } catch (IOException e) {
3543 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
John Spurlock35ef0a62015-05-28 11:24:10 -04003544 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003545 return null;
3546 }
3547
3548 @Override
3549 public void applyRestore(byte[] payload, int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003550 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003551 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
3552 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
3553 if (payload == null) {
3554 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
3555 return;
3556 }
Julia Reynolds8a613f82018-12-13 14:25:13 -05003557 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
3558 try {
Annie Meng8b646fd2019-02-01 18:46:42 +00003559 readPolicyXml(bais, true /*forRestore*/, user);
Julia Reynolds8a613f82018-12-13 14:25:13 -05003560 handleSavePolicyFile();
3561 } catch (NumberFormatException | XmlPullParserException | IOException e) {
3562 Slog.w(TAG, "applyRestore: error reading payload", e);
John Spurlock35ef0a62015-05-28 11:24:10 -04003563 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003564 }
3565
John Spurlock1fc476d2015-04-14 16:05:20 -04003566 @Override
John Spurlock80774932015-05-07 17:38:50 -04003567 public boolean isNotificationPolicyAccessGranted(String pkg) {
3568 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04003569 }
3570
3571 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05003572 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
3573 enforceSystemOrSystemUIOrSamePackage(pkg,
3574 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003575 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003576 }
3577
3578 @Override
John Spurlock80774932015-05-07 17:38:50 -04003579 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
3580 throws RemoteException {
Julia Reynolds92febc32017-10-26 11:30:31 -04003581 setNotificationPolicyAccessGrantedForUser(
3582 pkg, getCallingUserHandle().getIdentifier(), granted);
3583 }
3584
3585 @Override
3586 public void setNotificationPolicyAccessGrantedForUser(
3587 String pkg, int userId, boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003588 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003589 final long identity = Binder.clearCallingIdentity();
3590 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003591 if (mAllowedManagedServicePackages.test(pkg)) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003592 mConditionProviders.setPackageOrComponentEnabled(
Julia Reynolds92febc32017-10-26 11:30:31 -04003593 pkg, userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003594
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003595 getContext().sendBroadcastAsUser(new Intent(
3596 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3597 .setPackage(pkg)
Julia Reynolds99f72072019-01-14 09:35:22 -05003598 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Julia Reynolds92febc32017-10-26 11:30:31 -04003599 UserHandle.of(userId), null);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05003600 handleSavePolicyFile();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003601 }
3602 } finally {
3603 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003604 }
John Spurlock80774932015-05-07 17:38:50 -04003605 }
3606
3607 @Override
3608 public Policy getNotificationPolicy(String pkg) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003609 final long identity = Binder.clearCallingIdentity();
3610 try {
3611 return mZenModeHelper.getNotificationPolicy();
3612 } finally {
3613 Binder.restoreCallingIdentity(identity);
3614 }
3615 }
3616
Beverlyff2df9b2018-10-10 16:54:10 -04003617 @Override
3618 public Policy getConsolidatedNotificationPolicy() {
3619 final long identity = Binder.clearCallingIdentity();
3620 try {
3621 return mZenModeHelper.getConsolidatedNotificationPolicy();
3622 } finally {
3623 Binder.restoreCallingIdentity(identity);
3624 }
3625 }
3626
Beverly6697eff2017-12-14 15:00:27 -05003627 /**
3628 * Sets the notification policy. Apps that target API levels below
Beverly98ef61b2018-02-15 10:36:28 -05003629 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
Beverlyd6964762018-02-16 14:07:03 -05003630 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3631 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3632 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
Beverly6697eff2017-12-14 15:00:27 -05003633 */
John Spurlock1fc476d2015-04-14 16:05:20 -04003634 @Override
John Spurlock80774932015-05-07 17:38:50 -04003635 public void setNotificationPolicy(String pkg, Policy policy) {
3636 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04003637 final long identity = Binder.clearCallingIdentity();
3638 try {
Beverly6697eff2017-12-14 15:00:27 -05003639 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3640 0, UserHandle.getUserId(MY_UID));
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003641 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
Beverly6697eff2017-12-14 15:00:27 -05003642
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06003643 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
Beverly98ef61b2018-02-15 10:36:28 -05003644 int priorityCategories = policy.priorityCategories;
3645 // ignore alarm and media values from new policy
3646 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
Beverlyd6964762018-02-16 14:07:03 -05003647 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3648 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003649 // use user-designated values
Beverlyd6964762018-02-16 14:07:03 -05003650 priorityCategories |= currPolicy.priorityCategories
3651 & Policy.PRIORITY_CATEGORY_ALARMS;
3652 priorityCategories |= currPolicy.priorityCategories
3653 & Policy.PRIORITY_CATEGORY_MEDIA;
3654 priorityCategories |= currPolicy.priorityCategories
3655 & Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003656
Beverly6697eff2017-12-14 15:00:27 -05003657 policy = new Policy(priorityCategories,
3658 policy.priorityCallSenders, policy.priorityMessageSenders,
3659 policy.suppressedVisualEffects);
3660 }
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003661 int newVisualEffects = calculateSuppressedVisualEffects(
3662 policy, currPolicy, applicationInfo.targetSdkVersion);
3663 policy = new Policy(policy.priorityCategories,
3664 policy.priorityCallSenders, policy.priorityMessageSenders,
3665 newVisualEffects);
Beverly5e073222018-03-08 10:36:25 -05003666 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
John Spurlock1fc476d2015-04-14 16:05:20 -04003667 mZenModeHelper.setNotificationPolicy(policy);
Beverly6697eff2017-12-14 15:00:27 -05003668 } catch (RemoteException e) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003669 } finally {
3670 Binder.restoreCallingIdentity(identity);
3671 }
3672 }
Chris Wren51017d02015-12-15 15:34:46 -05003673
3674 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003675 public List<String> getEnabledNotificationListenerPackages() {
3676 checkCallerIsSystem();
3677 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3678 }
3679
3680 @Override
3681 public List<ComponentName> getEnabledNotificationListeners(int userId) {
3682 checkCallerIsSystem();
3683 return mListeners.getAllowedComponents(userId);
3684 }
3685
3686 @Override
Fabian Kozynskid9425662019-01-29 13:08:30 -05003687 public ComponentName getAllowedNotificationAssistantForUser(int userId) {
3688 checkCallerIsSystem();
3689 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
3690 if (allowedComponents.size() > 1) {
3691 throw new IllegalStateException(
3692 "At most one NotificationAssistant: " + allowedComponents.size());
3693 }
3694 return CollectionUtils.firstOrNull(allowedComponents);
3695 }
3696
3697 @Override
3698 public ComponentName getAllowedNotificationAssistant() {
3699 return getAllowedNotificationAssistantForUser(getCallingUserHandle().getIdentifier());
3700 }
3701
3702 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003703 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3704 Preconditions.checkNotNull(listener);
3705 checkCallerIsSystemOrSameApp(listener.getPackageName());
3706 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3707 getCallingUserHandle().getIdentifier());
3708 }
3709
3710 @Override
3711 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3712 int userId) {
3713 Preconditions.checkNotNull(listener);
3714 checkCallerIsSystem();
3715 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3716 userId);
3717 }
3718
3719 @Override
3720 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3721 Preconditions.checkNotNull(assistant);
3722 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003723 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04003724 getCallingUserHandle().getIdentifier());
3725 }
3726
3727 @Override
3728 public void setNotificationListenerAccessGranted(ComponentName listener,
3729 boolean granted) throws RemoteException {
3730 setNotificationListenerAccessGrantedForUser(
3731 listener, getCallingUserHandle().getIdentifier(), granted);
3732 }
3733
3734 @Override
3735 public void setNotificationAssistantAccessGranted(ComponentName assistant,
3736 boolean granted) throws RemoteException {
3737 setNotificationAssistantAccessGrantedForUser(
3738 assistant, getCallingUserHandle().getIdentifier(), granted);
3739 }
3740
3741 @Override
3742 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3743 boolean granted) throws RemoteException {
3744 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04003745 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003746 final long identity = Binder.clearCallingIdentity();
3747 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003748 if (mAllowedManagedServicePackages.test(listener.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003749 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3750 userId, false, granted);
3751 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3752 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003753
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003754 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds92febc32017-10-26 11:30:31 -04003755 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003756 .setPackage(listener.getPackageName())
3757 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003758 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003759
Julia Reynoldsb62dad42018-11-26 16:33:02 -05003760 handleSavePolicyFile();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003761 }
3762 } finally {
3763 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003764 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003765 }
3766
3767 @Override
3768 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3769 int userId, boolean granted) throws RemoteException {
Julia Reynolds0d217642017-08-11 11:26:04 -04003770 checkCallerIsSystemOrShell();
Fabian Kozynskid9425662019-01-29 13:08:30 -05003771 if (assistant == null) {
3772 ComponentName allowedAssistant = CollectionUtils.firstOrNull(
3773 mAssistants.getAllowedComponents(userId));
3774 if (allowedAssistant != null) {
3775 setNotificationAssistantAccessGrantedForUser(allowedAssistant, userId, false);
3776 }
3777 return;
3778 }
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003779 final long identity = Binder.clearCallingIdentity();
3780 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003781 if (mAllowedManagedServicePackages.test(assistant.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003782 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
3783 userId, false, granted);
3784 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
3785 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003786
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003787 getContext().sendBroadcastAsUser(new Intent(
3788 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3789 .setPackage(assistant.getPackageName())
3790 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003791 UserHandle.of(userId), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003792
Julia Reynoldsb62dad42018-11-26 16:33:02 -05003793 handleSavePolicyFile();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003794 }
3795 } finally {
3796 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003797 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003798 }
3799
3800 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003801 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003802 Adjustment adjustment) {
3803 boolean foundEnqueued = false;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003804 final long identity = Binder.clearCallingIdentity();
3805 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003806 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003807 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003808 int N = mEnqueuedNotifications.size();
3809 for (int i = 0; i < N; i++) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003810 final NotificationRecord r = mEnqueuedNotifications.get(i);
3811 if (Objects.equals(adjustment.getKey(), r.getKey())
Julia Reynolds70aaea72018-07-13 13:38:34 -04003812 && Objects.equals(adjustment.getUser(), r.getUserId())
3813 && mAssistants.isSameUser(token, r.getUserId())) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003814 applyAdjustment(r, adjustment);
3815 r.applyAdjustments();
Julia Reynolds27c0a962018-12-10 12:37:28 -05003816 // importance is checked at the beginning of the
3817 // PostNotificationRunnable, before the signal extractors are run, so
3818 // calculate the final importance here
3819 r.calculateImportance();
Julia Reynolds666ccf02018-06-18 10:19:20 -04003820 foundEnqueued = true;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003821 break;
3822 }
3823 }
Julia Reynolds666ccf02018-06-18 10:19:20 -04003824 if (!foundEnqueued) {
3825 // adjustment arrived too late to apply to enqueued; apply to posted
Julia Reynolds27c0a962018-12-10 12:37:28 -05003826 // However, since the notification is now posted and may have alerted,
3827 // ignore any importance related adjustments
3828 adjustment.getSignals().remove(Adjustment.KEY_IMPORTANCE);
Julia Reynolds666ccf02018-06-18 10:19:20 -04003829 applyAdjustmentFromAssistant(token, adjustment);
3830 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003831 }
3832 } finally {
3833 Binder.restoreCallingIdentity(identity);
3834 }
3835 }
3836
3837 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003838 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003839 Adjustment adjustment) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003840 List<Adjustment> adjustments = new ArrayList<>();
3841 adjustments.add(adjustment);
3842 applyAdjustmentsFromAssistant(token, adjustments);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003843 }
3844
3845 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003846 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003847 List<Adjustment> adjustments) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003848
Julia Reynoldsefcdff42018-08-09 09:42:56 -04003849 boolean needsSort = false;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003850 final long identity = Binder.clearCallingIdentity();
3851 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003852 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003853 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003854 for (Adjustment adjustment : adjustments) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003855 NotificationRecord r = mNotificationsByKey.get(adjustment.getKey());
3856 if (r != null && mAssistants.isSameUser(token, r.getUserId())) {
3857 applyAdjustment(r, adjustment);
Julia Reynolds27c0a962018-12-10 12:37:28 -05003858 // If the assistant has blocked the notification, cancel it
3859 // This will trigger a sort, so we don't have to explicitly ask for
3860 // one here.
3861 if (adjustment.getSignals().containsKey(Adjustment.KEY_IMPORTANCE)
3862 && adjustment.getSignals().getInt(Adjustment.KEY_IMPORTANCE)
3863 == IMPORTANCE_NONE) {
Julia Reynoldsefcdff42018-08-09 09:42:56 -04003864 cancelNotificationsFromListener(token, new String[]{r.getKey()});
3865 } else {
3866 needsSort = true;
3867 }
Julia Reynolds70aaea72018-07-13 13:38:34 -04003868 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003869 }
3870 }
Julia Reynoldsefcdff42018-08-09 09:42:56 -04003871 if (needsSort) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003872 mRankingHandler.requestSort();
3873 }
Chris Wren51017d02015-12-15 15:34:46 -05003874 } finally {
3875 Binder.restoreCallingIdentity(identity);
3876 }
3877 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003878
3879 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04003880 public void updateNotificationChannelGroupFromPrivilegedListener(
3881 INotificationListener token, String pkg, UserHandle user,
3882 NotificationChannelGroup group) throws RemoteException {
3883 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003884 verifyPrivilegedListener(token, user, false);
Julia Reynolds005c8b92017-08-24 10:35:53 -04003885 createNotificationChannelGroup(
3886 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05003887 handleSavePolicyFile();
Julia Reynolds005c8b92017-08-24 10:35:53 -04003888 }
3889
3890 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003891 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003892 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003893 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003894 Preconditions.checkNotNull(pkg);
3895 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003896
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003897 verifyPrivilegedListener(token, user, false);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003898 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003899 }
3900
3901 @Override
3902 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003903 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3904 Preconditions.checkNotNull(pkg);
3905 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003906 verifyPrivilegedListener(token, user, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003907
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003908 return mPreferencesHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003909 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003910 }
3911
3912 @Override
3913 public ParceledListSlice<NotificationChannelGroup>
3914 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003915 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3916 Preconditions.checkNotNull(pkg);
3917 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003918 verifyPrivilegedListener(token, user, true);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003919
3920 List<NotificationChannelGroup> groups = new ArrayList<>();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003921 groups.addAll(mPreferencesHelper.getNotificationChannelGroups(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003922 pkg, getUidForPackageAndUser(pkg, user)));
3923 return new ParceledListSlice<>(groups);
3924 }
3925
Zimuzob3b9c262018-10-31 11:54:20 +00003926 @Override
3927 public void setPrivateNotificationsAllowed(boolean allow) {
3928 if (PackageManager.PERMISSION_GRANTED
3929 != getContext().checkCallingPermission(
3930 permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
3931 throw new SecurityException(
3932 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
3933 }
3934 if (allow != mLockScreenAllowSecureNotifications) {
3935 mLockScreenAllowSecureNotifications = allow;
Julia Reynoldsb62dad42018-11-26 16:33:02 -05003936 handleSavePolicyFile();
Zimuzob3b9c262018-10-31 11:54:20 +00003937 }
3938 }
3939
3940 @Override
3941 public boolean getPrivateNotificationsAllowed() {
3942 if (PackageManager.PERMISSION_GRANTED
3943 != getContext().checkCallingPermission(
3944 permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
3945 throw new SecurityException(
3946 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
3947 }
3948 return mLockScreenAllowSecureNotifications;
3949 }
3950
Julia Reynoldsb40cd092019-01-25 09:35:02 -05003951 @Override
3952 public boolean isPackagePaused(String pkg) {
3953 Preconditions.checkNotNull(pkg);
3954 checkCallerIsSameApp(pkg);
3955
3956 boolean isPaused;
3957
3958 final PackageManagerInternal pmi = LocalServices.getService(
3959 PackageManagerInternal.class);
3960 int flags = pmi.getDistractingPackageRestrictions(
3961 pkg, Binder.getCallingUserHandle().getIdentifier());
3962 isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
3963
3964 isPaused |= isPackageSuspendedForUser(pkg, Binder.getCallingUid());
3965
3966 return isPaused;
3967 }
3968
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003969 private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
3970 boolean assistantAllowed) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003971 ManagedServiceInfo info;
3972 synchronized (mNotificationLock) {
3973 info = mListeners.checkServiceTokenLocked(token);
3974 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003975 if (!hasCompanionDevice(info)) {
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003976 synchronized (mNotificationLock) {
3977 if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) {
3978 throw new SecurityException(info + " does not have access");
3979 }
3980 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003981 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003982 if (!info.enabledAndUserMatches(user.getIdentifier())) {
3983 throw new SecurityException(info + " does not have access");
3984 }
3985 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003986
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003987 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3988 int uid = 0;
3989 long identity = Binder.clearCallingIdentity();
3990 try {
3991 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3992 } finally {
3993 Binder.restoreCallingIdentity(identity);
3994 }
3995 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003996 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003997
3998 @Override
3999 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
4000 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
4001 throws RemoteException {
Dan Sandler7647f1d2018-11-26 09:56:26 -05004002 new NotificationShellCmd(NotificationManagerService.this)
4003 .exec(this, in, out, err, args, callback, resultReceiver);
Julia Reynoldsb852e562017-06-06 16:14:18 -04004004 }
John Spurlock1fc476d2015-04-14 16:05:20 -04004005 };
John Spurlocka4294292014-03-24 18:02:32 -04004006
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004007 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
4008 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04004009 return;
4010 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04004011 if (adjustment.getSignals() != null) {
4012 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004013 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04004014 }
4015 }
4016
Julia Reynolds88860ce2017-06-01 16:55:49 -04004017 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004018 void addAutogroupKeyLocked(String key) {
4019 NotificationRecord r = mNotificationsByKey.get(key);
4020 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04004021 return;
4022 }
Julia Reynolds51710712017-07-19 13:48:07 -04004023 if (r.sbn.getOverrideGroupKey() == null) {
4024 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
4025 EventLogTags.writeNotificationAutogrouped(key);
4026 mRankingHandler.requestSort();
4027 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04004028 }
4029
Julia Reynolds88860ce2017-06-01 16:55:49 -04004030 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004031 void removeAutogroupKeyLocked(String key) {
4032 NotificationRecord r = mNotificationsByKey.get(key);
4033 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04004034 return;
4035 }
Julia Reynolds51710712017-07-19 13:48:07 -04004036 if (r.sbn.getOverrideGroupKey() != null) {
4037 addAutoGroupAdjustment(r, null);
4038 EventLogTags.writeNotificationUnautogrouped(key);
4039 mRankingHandler.requestSort();
4040 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004041 }
4042
4043 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
4044 Bundle signals = new Bundle();
4045 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
4046 Adjustment adjustment =
4047 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
4048 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004049 }
4050
4051 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04004052 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04004053 private void clearAutogroupSummaryLocked(int userId, String pkg) {
4054 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
4055 if (summaries != null && summaries.containsKey(pkg)) {
4056 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004057 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04004058 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04004059 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004060 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04004061 }
4062 }
4063 }
4064
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04004065 @GuardedBy("mNotificationLock")
4066 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
4067 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
4068 return summaries != null && summaries.containsKey(sbn.getPackageName());
4069 }
4070
Julia Reynoldse46bb372016-03-17 11:05:58 -04004071 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04004072 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
4073 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004074 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04004075 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
4076 if (notificationRecord == null) {
4077 // The notification could have been cancelled again already. A successive
4078 // adjustment will post a summary if needed.
4079 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04004080 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04004081 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
4082 userId = adjustedSbn.getUser().getIdentifier();
4083 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
4084 if (summaries == null) {
4085 summaries = new ArrayMap<>();
4086 }
4087 mAutobundledSummaries.put(userId, summaries);
4088 if (!summaries.containsKey(pkg)) {
4089 // Add summary
4090 final ApplicationInfo appInfo =
4091 adjustedSbn.getNotification().extras.getParcelable(
4092 Notification.EXTRA_BUILDER_APPLICATION_INFO);
4093 final Bundle extras = new Bundle();
4094 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004095 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04004096 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004097 new Notification.Builder(getContext(), channelId)
4098 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04004099 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04004100 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04004101 .setGroup(GroupHelper.AUTOGROUP_KEY)
4102 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
4103 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
4104 .setColor(adjustedSbn.getNotification().color)
4105 .setLocalOnly(true)
4106 .build();
4107 summaryNotification.extras.putAll(extras);
4108 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
4109 if (appIntent != null) {
4110 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
4111 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
4112 }
4113 final StatusBarNotification summarySbn =
4114 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004115 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004116 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04004117 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
4118 adjustedSbn.getInitialPid(), summaryNotification,
4119 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
4120 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05004121 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004122 notificationRecord.getChannel());
Rohan Shah590e1b22018-04-10 23:48:47 -04004123 summaryRecord.setIsAppImportanceLocked(
4124 notificationRecord.getIsAppImportanceLocked());
Julia Reynolds8f488d32016-10-14 10:59:01 -04004125 summaries.put(pkg, summarySbn.getKey());
4126 }
4127 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004128 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04004129 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04004130 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04004131 }
4132 }
4133
John Spurlock32fe4c62014-10-02 12:16:02 -04004134 private String disableNotificationEffects(NotificationRecord record) {
4135 if (mDisableNotificationEffects) {
4136 return "booleanState";
4137 }
4138 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
4139 return "listenerHints";
4140 }
Julia Reynoldsdb7081e2019-01-03 14:35:38 -05004141 if (record != null && record.getAudioAttributes() != null) {
4142 if ((mListenerHints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
4143 if (record.getAudioAttributes().getUsage()
4144 != AudioAttributes.USAGE_VOICE_COMMUNICATION) {
4145 return "listenerNoti";
4146 }
4147 }
4148 if ((mListenerHints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
4149 if (record.getAudioAttributes().getUsage()
4150 == AudioAttributes.USAGE_VOICE_COMMUNICATION) {
4151 return "listenerCall";
4152 }
4153 }
4154 }
John Spurlock32fe4c62014-10-02 12:16:02 -04004155 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
4156 return "callState";
4157 }
4158 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04004159 };
4160
Kweku Adams887f09c2017-11-13 17:12:20 -08004161 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
Chris Wrene4b38802015-07-07 15:54:19 -04004162 JSONObject dump = new JSONObject();
4163 try {
4164 dump.put("service", "Notification Manager");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004165 dump.put("bans", mPreferencesHelper.dumpBansJson(filter));
4166 dump.put("ranking", mPreferencesHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04004167 dump.put("stats", mUsageStats.dumpJson(filter));
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004168 dump.put("channels", mPreferencesHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04004169 } catch (JSONException e) {
4170 e.printStackTrace();
4171 }
4172 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04004173 }
4174
Kweku Adams887f09c2017-11-13 17:12:20 -08004175 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004176 final ProtoOutputStream proto = new ProtoOutputStream(fd);
4177 synchronized (mNotificationLock) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004178 int N = mNotificationList.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08004179 for (int i = 0; i < N; i++) {
4180 final NotificationRecord nr = mNotificationList.get(i);
4181 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4182 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
4183 NotificationRecordProto.POSTED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004184 }
4185 N = mEnqueuedNotifications.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08004186 for (int i = 0; i < N; i++) {
4187 final NotificationRecord nr = mEnqueuedNotifications.get(i);
4188 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4189 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
4190 NotificationRecordProto.ENQUEUED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004191 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004192 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
4193 N = snoozed.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08004194 for (int i = 0; i < N; i++) {
4195 final NotificationRecord nr = snoozed.get(i);
4196 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4197 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
4198 NotificationRecordProto.SNOOZED);
Julia Reynolds520df6e2017-02-13 09:05:10 -05004199 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004200
Kweku Adams93304b62017-09-20 17:03:00 -07004201 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
4202 mZenModeHelper.dump(proto);
4203 for (ComponentName suppressor : mEffectsSuppressors) {
Kweku Adams99546332018-01-24 17:03:50 -08004204 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
Kweku Adams93304b62017-09-20 17:03:00 -07004205 }
4206 proto.end(zenLog);
4207
4208 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
4209 mListeners.dump(proto, filter);
4210 proto.end(listenersToken);
4211
4212 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
4213
4214 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
4215 long effectsToken = proto.start(
4216 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
4217
4218 proto.write(
4219 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
Julia Reynolds4703bac2018-09-12 10:39:30 -04004220 final ArraySet<ComponentName> listeners =
Kweku Adams93304b62017-09-20 17:03:00 -07004221 mListenersDisablingEffects.valueAt(i);
4222 for (int j = 0; j < listeners.size(); j++) {
Kweku Adamsf2169532018-12-20 04:15:49 -08004223 final ComponentName componentName = listeners.valueAt(j);
Julia Reynolds4703bac2018-09-12 10:39:30 -04004224 componentName.writeToProto(proto,
4225 ListenersDisablingEffectsProto.LISTENER_COMPONENTS);
Kweku Adams93304b62017-09-20 17:03:00 -07004226 }
4227
4228 proto.end(effectsToken);
4229 }
4230
4231 long assistantsToken = proto.start(
4232 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
4233 mAssistants.dump(proto, filter);
4234 proto.end(assistantsToken);
4235
4236 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
4237 mConditionProviders.dump(proto, filter);
4238 proto.end(conditionsToken);
Kweku Adams62b42242017-09-25 12:54:02 -07004239
4240 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
4241 mRankingHelper.dump(proto, filter);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004242 mPreferencesHelper.dump(proto, filter);
Kweku Adams62b42242017-09-25 12:54:02 -07004243 proto.end(rankingToken);
Julia Reynolds520df6e2017-02-13 09:05:10 -05004244 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004245
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004246 proto.flush();
4247 }
4248
Vishnu Naire3e4d252018-03-01 11:26:57 -08004249 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
4250 synchronized (mNotificationLock) {
4251 int N;
4252 N = mNotificationList.size();
4253 if (N > 0) {
4254 pw.println(" Notification List:");
4255 for (int i = 0; i < N; i++) {
4256 final NotificationRecord nr = mNotificationList.get(i);
4257 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4258 nr.dump(pw, " ", getContext(), filter.redact);
4259 }
4260 pw.println(" ");
4261 }
4262 }
4263 }
4264
Kweku Adams887f09c2017-11-13 17:12:20 -08004265 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
John Spurlock25e2d242014-06-27 13:58:23 -04004266 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04004267 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04004268 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04004269 }
4270 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08004271 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04004272 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08004273
John Spurlock50806fc2014-07-15 10:22:02 -04004274 if (!zenOnly) {
4275 synchronized (mToastQueue) {
4276 N = mToastQueue.size();
4277 if (N > 0) {
4278 pw.println(" Toast Queue:");
4279 for (int i=0; i<N; i++) {
4280 mToastQueue.get(i).dump(pw, " ", filter);
4281 }
4282 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08004283 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004284 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004285 }
4286
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004287 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04004288 if (!zenOnly) {
Vishnu Naire3e4d252018-03-01 11:26:57 -08004289 // Priority filters are only set when called via bugreport. If set
4290 // skip sections that are part of the critical section.
4291 if (!filter.normalPriority) {
4292 dumpNotificationRecords(pw, filter);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004293 }
Julia Reynoldse6b53e62015-07-31 09:25:10 -04004294 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04004295 N = mLights.size();
4296 if (N > 0) {
4297 pw.println(" Lights List:");
4298 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05004299 if (i == N - 1) {
4300 pw.print(" > ");
4301 } else {
4302 pw.print(" ");
4303 }
4304 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04004305 }
4306 pw.println(" ");
4307 }
John Spurlockcb566aa2014-08-03 22:58:28 -04004308 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
Julia Reynolds28149f62018-07-03 10:43:35 -04004309 pw.println(" mHasLight=" + mHasLight);
John Spurlockcb566aa2014-08-03 22:58:28 -04004310 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05004311 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
4312 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04004313 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04004314 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04004315 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04004316 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04004317 }
4318 pw.println(" mArchive=" + mArchive.toString());
4319 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004320 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04004321 while (iter.hasNext()) {
4322 final StatusBarNotification sbn = iter.next();
4323 if (filter != null && !filter.matches(sbn)) continue;
4324 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004325 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04004326 if (iter.hasNext()) pw.println(" ...");
4327 break;
4328 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004329 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004330
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004331 if (!zenOnly) {
4332 N = mEnqueuedNotifications.size();
4333 if (N > 0) {
4334 pw.println(" Enqueued Notification List:");
4335 for (int i = 0; i < N; i++) {
4336 final NotificationRecord nr = mEnqueuedNotifications.get(i);
4337 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4338 nr.dump(pw, " ", getContext(), filter.redact);
4339 }
4340 pw.println(" ");
4341 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004342
4343 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004344 }
4345 }
4346
John Spurlock50806fc2014-07-15 10:22:02 -04004347 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04004348 pw.println("\n Ranking Config:");
4349 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04004350
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004351 pw.println("\n Notification Preferences:");
4352 mPreferencesHelper.dump(pw, " ", filter);
4353
John Spurlock50806fc2014-07-15 10:22:02 -04004354 pw.println("\n Notification listeners:");
4355 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04004356 pw.print(" mListenerHints: "); pw.println(mListenerHints);
4357 pw.print(" mListenersDisablingEffects: (");
4358 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04004359 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07004360 final int hint = mListenersDisablingEffects.keyAt(i);
4361 if (i > 0) pw.print(';');
4362 pw.print("hint[" + hint + "]:");
4363
Julia Reynolds4703bac2018-09-12 10:39:30 -04004364 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07004365 final int listenerSize = listeners.size();
4366
4367 for (int j = 0; j < listenerSize; j++) {
Kweku Adamsf2169532018-12-20 04:15:49 -08004368 if (j > 0) pw.print(',');
4369 final ComponentName listener = listeners.valueAt(j);
Julia Reynolds1f580572018-04-27 14:48:36 -04004370 if (listener != null) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04004371 pw.print(listener);
Julia Reynolds1f580572018-04-27 14:48:36 -04004372 }
Bryce Lee7219ada2016-04-08 10:54:23 -07004373 }
John Spurlock1fa865f2014-07-21 14:56:39 -04004374 }
4375 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05004376 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004377 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04004378 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004379
Julia Reynolds520df6e2017-02-13 09:05:10 -05004380 if (!filter.filtered || zenOnly) {
4381 pw.println("\n Zen Mode:");
4382 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
4383 mZenModeHelper.dump(pw, " ");
4384
4385 pw.println("\n Zen Log:");
4386 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004387 }
4388
John Spurlocke77bb362014-04-26 10:24:59 -04004389 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04004390 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02004391
4392 pw.println("\n Group summaries:");
4393 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
4394 NotificationRecord r = entry.getValue();
4395 pw.println(" " + entry.getKey() + " -> " + r.getKey());
4396 if (mNotificationsByKey.get(r.getKey()) != r) {
4397 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04004398 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02004399 }
4400 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004401
4402 if (!zenOnly) {
4403 pw.println("\n Usage Stats:");
4404 mUsageStats.dump(pw, " ", filter);
4405 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004406 }
4407 }
4408
Adam Lesinski182f73f2013-12-05 16:48:06 -08004409 /**
4410 * The private API only accessible to the system process.
4411 */
4412 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
4413 @Override
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04004414 public NotificationChannel getNotificationChannel(String pkg, int uid, String
4415 channelId) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004416 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false);
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04004417 }
4418
4419 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004420 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004421 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004422 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004423 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004424 }
Christoph Studer365e4c32014-09-18 20:35:36 +02004425
4426 @Override
4427 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
4428 int userId) {
4429 checkCallerIsSystem();
Julia Reynolds564273f2018-09-13 15:53:11 -04004430 mHandler.post(() -> {
4431 synchronized (mNotificationLock) {
4432 // strip flag from all enqueued notifications. listeners will be informed
4433 // in post runnable.
4434 List<NotificationRecord> enqueued = findNotificationsByListLocked(
4435 mEnqueuedNotifications, pkg, null, notificationId, userId);
4436 for (int i = 0; i < enqueued.size(); i++) {
4437 removeForegroundServiceFlagLocked(enqueued.get(i));
4438 }
4439
4440 // if posted notification exists, strip its flag and tell listeners
4441 NotificationRecord r = findNotificationByListLocked(
4442 mNotificationList, pkg, null, notificationId, userId);
4443 if (r != null) {
4444 removeForegroundServiceFlagLocked(r);
4445 mRankingHelper.sort(mNotificationList);
4446 mListeners.notifyPostedLocked(r, r);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004447 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004448 }
4449 });
4450 }
4451
Julia Reynolds88860ce2017-06-01 16:55:49 -04004452 @GuardedBy("mNotificationLock")
Julia Reynolds564273f2018-09-13 15:53:11 -04004453 private void removeForegroundServiceFlagLocked(NotificationRecord r) {
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004454 if (r == null) {
4455 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02004456 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004457 StatusBarNotification sbn = r.sbn;
4458 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
4459 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
4460 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
4461 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
4462 sbn.getNotification().flags =
Julia Reynoldse5c60452018-04-30 14:41:36 -04004463 (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
Christoph Studer365e4c32014-09-18 20:35:36 +02004464 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004465 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004466
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004467 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04004468 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004469 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04004470 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08004471 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
4472 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04004473 }
Dianne Hackborn41203752012-08-31 14:05:51 -07004474
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004475 if (pkg == null || notification == null) {
4476 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
4477 + " id=" + id + " notification=" + notification);
4478 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004479
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004480 final int userId = ActivityManager.handleIncomingUser(callingPid,
4481 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
4482 final UserHandle user = UserHandle.of(userId);
4483
4484 // Can throw a SecurityException if the calling uid doesn't have permission to post
4485 // as "pkg"
4486 final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
4487
4488 checkRestrictedCategories(notification);
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004489
Julia Reynoldse46bb372016-03-17 11:05:58 -04004490 // Fix the notification as best we can.
4491 try {
Julia Reynolds47fd15f2018-11-28 10:16:00 -05004492 fixNotification(notification, pkg, userId);
Julia Reynolds4db59552017-06-30 13:34:01 -04004493
Julia Reynoldse46bb372016-03-17 11:05:58 -04004494 } catch (NameNotFoundException e) {
4495 Slog.e(TAG, "Cannot create a context for sending app", e);
4496 return;
4497 }
4498
Chris Wren888b7a82016-06-17 15:47:19 -04004499 mUsageStats.registerEnqueuedByApp(pkg);
4500
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004501 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04004502 String channelId = notification.getChannelId();
4503 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
4504 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05004505 }
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004506 final NotificationChannel channel = mPreferencesHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004507 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004508 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004509 final String noChannelStr = "No Channel found for "
4510 + "pkg=" + pkg
4511 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04004512 + ", id=" + id
4513 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004514 + ", opPkg=" + opPkg
4515 + ", callingUid=" + callingUid
4516 + ", userId=" + userId
4517 + ", incomingUserId=" + incomingUserId
4518 + ", notificationUid=" + notificationUid
4519 + ", notification=" + notification;
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004520 Log.e(TAG, noChannelStr);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004521 boolean appNotificationsOff = mPreferencesHelper.getImportance(pkg, notificationUid)
Beverly5d4564b2018-04-10 20:09:23 -04004522 == NotificationManager.IMPORTANCE_NONE;
4523
4524 if (!appNotificationsOff) {
4525 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
4526 "Failed to post notification on channel \"" + channelId + "\"\n" +
4527 "See log for more details");
4528 }
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004529 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004530 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004531
Chris Wrena61f1792016-08-04 11:24:42 -04004532 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004533 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004534 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004535 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004536 r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
Chris Wrena61f1792016-08-04 11:24:42 -04004537
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004538 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4539 final boolean fgServiceShown = channel.isFgServiceShown();
4540 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
4541 || !fgServiceShown)
4542 && (r.getImportance() == IMPORTANCE_MIN
4543 || r.getImportance() == IMPORTANCE_NONE)) {
4544 // Increase the importance of foreground service notifications unless the user had
4545 // an opinion otherwise (and the channel hasn't yet shown a fg service).
4546 if (TextUtils.isEmpty(channelId)
4547 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004548 r.setSystemImportance(IMPORTANCE_LOW);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004549 } else {
4550 channel.setImportance(IMPORTANCE_LOW);
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004551 r.setSystemImportance(IMPORTANCE_LOW);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004552 if (!fgServiceShown) {
4553 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
4554 channel.setFgServiceShown(true);
4555 }
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004556 mPreferencesHelper.updateNotificationChannel(
4557 pkg, notificationUid, channel, false);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004558 r.updateNotificationChannel(channel);
4559 }
4560 } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
4561 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4562 channel.setFgServiceShown(true);
Julia Reynolds8617e4e2017-09-18 16:52:37 -04004563 r.updateNotificationChannel(channel);
4564 }
4565 }
4566
Julia Reynolds5e702192017-08-18 09:22:40 -04004567 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
4568 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004569 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07004570 }
4571
Felipe Lemedd85da62016-06-28 11:29:54 -07004572 // Whitelist pending intents.
4573 if (notification.allPendingIntents != null) {
4574 final int intentCount = notification.allPendingIntents.size();
4575 if (intentCount > 0) {
4576 final ActivityManagerInternal am = LocalServices
4577 .getService(ActivityManagerInternal.class);
4578 final long duration = LocalServices.getService(
4579 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
4580 for (int i = 0; i < intentCount; i++) {
4581 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4582 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07004583 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4584 WHITELIST_TOKEN, duration);
Michal Karpinskiac116df2018-12-10 17:51:42 +00004585 am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
Michal Karpinskic8aa91b2019-01-10 16:45:59 +00004586 WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
4587 | FLAG_SERVICE_SENDER));
Felipe Lemedd85da62016-06-28 11:29:54 -07004588 }
4589 }
4590 }
4591 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07004592
Chris Wren47633422016-01-22 09:56:59 -05004593 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004594 }
4595
Julia Reynolds47fd15f2018-11-28 10:16:00 -05004596 @VisibleForTesting
4597 protected void fixNotification(Notification notification, String pkg, int userId)
4598 throws NameNotFoundException {
4599 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
4600 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
4601 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
4602 Notification.addFieldsFromContext(ai, notification);
4603
4604 int canColorize = mPackageManagerClient.checkPermission(
4605 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
4606 if (canColorize == PERMISSION_GRANTED) {
4607 notification.flags |= Notification.FLAG_CAN_COLORIZE;
4608 } else {
4609 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
4610 }
4611
Takamasa Kuramitsu3dd7b2d2018-12-14 20:46:02 +09004612 if (notification.fullScreenIntent != null && ai.targetSdkVersion >= Build.VERSION_CODES.Q) {
Julia Reynolds47fd15f2018-11-28 10:16:00 -05004613 int fullscreenIntentPermission = mPackageManagerClient.checkPermission(
4614 android.Manifest.permission.USE_FULL_SCREEN_INTENT, pkg);
4615 if (fullscreenIntentPermission != PERMISSION_GRANTED) {
4616 notification.fullScreenIntent = null;
4617 Log.w(TAG, "Package " + pkg +
4618 ": Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission");
4619 }
4620 }
4621 }
4622
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04004623 private void doChannelWarningToast(CharSequence toastText) {
Julia Reynoldsbba26b12018-10-11 09:21:11 -04004624 Binder.withCleanCallingIdentity(() -> {
4625 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
4626 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
4627 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4628 if (warningEnabled) {
4629 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
4630 Toast.LENGTH_SHORT);
4631 toast.show();
4632 }
4633 });
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004634 }
4635
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004636 @VisibleForTesting
4637 int resolveNotificationUid(String callingPkg, String targetPkg,
4638 int callingUid, int userId) {
Julia Reynoldsb6634872018-09-25 13:19:53 -04004639 if (userId == UserHandle.USER_ALL) {
4640 userId = USER_SYSTEM;
4641 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004642 // posted from app A on behalf of app A
Julia Reynoldsb6634872018-09-25 13:19:53 -04004643 if (isCallerSameApp(targetPkg, callingUid, userId)
Julia Reynoldsecc1b572018-10-01 16:19:24 -04004644 && (TextUtils.equals(callingPkg, targetPkg)
4645 || isCallerSameApp(callingPkg, callingUid, userId))) {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004646 return callingUid;
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004647 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004648
4649 int targetUid = -1;
4650 try {
4651 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
4652 } catch (NameNotFoundException e) {
4653 /* ignore */
4654 }
4655 // posted from app A on behalf of app B
4656 if (targetUid != -1 && (isCallerAndroid(callingPkg, callingUid)
4657 || mPreferencesHelper.isDelegateAllowed(
4658 targetPkg, targetUid, callingPkg, callingUid))) {
4659 return targetUid;
4660 }
4661
Julia Reynoldsecc1b572018-10-01 16:19:24 -04004662 throw new SecurityException("Caller " + callingPkg + ":" + callingUid
4663 + " cannot post for pkg " + targetPkg + " in user " + userId);
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004664 }
4665
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004666 /**
4667 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4668 *
4669 * Has side effects.
4670 */
Julia Reynolds268647a2018-10-25 16:54:27 -04004671 private boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04004672 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004673 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004674 final boolean isSystemNotification =
Julia Reynolds268647a2018-10-25 16:54:27 -04004675 isUidSystemOrPhone(uid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004676 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
4677
4678 // Limit the number of notifications that any given package except the android
4679 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
4680 if (!isSystemNotification && !isNotificationFromListener) {
4681 synchronized (mNotificationLock) {
Julia Reynolds268647a2018-10-25 16:54:27 -04004682 final int callingUid = Binder.getCallingUid();
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004683 if (mNotificationsByKey.get(r.sbn.getKey()) == null
Julia Reynolds268647a2018-10-25 16:54:27 -04004684 && isCallerInstantApp(callingUid, userId)) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004685 // Ephemeral apps have some special constraints for notifications.
4686 // They are not allowed to create new notifications however they are allowed to
4687 // update notifications created by the system (e.g. a foreground service
4688 // notification).
4689 throw new SecurityException("Instant app " + pkg
4690 + " cannot create notifications");
4691 }
4692
4693 // rate limit updates that aren't completed progress notifications
4694 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04004695 && !r.getNotification().hasCompletedProgress()
4696 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004697
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004698 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
4699 if (appEnqueueRate > mMaxPackageEnqueueRate) {
4700 mUsageStats.registerOverRateQuota(pkg);
4701 final long now = SystemClock.elapsedRealtime();
4702 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
4703 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04004704 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004705 mLastOverRateLogTime = now;
4706 }
4707 return false;
4708 }
4709 }
4710
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004711 // limit the number of outstanding notificationrecords an app can have
4712 int count = getNotificationCountLocked(pkg, userId, id, tag);
4713 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
4714 mUsageStats.registerOverCountQuota(pkg);
4715 Slog.e(TAG, "Package has already posted or enqueued " + count
4716 + " notifications. Not showing more. package=" + pkg);
4717 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004718 }
4719 }
4720 }
4721
4722 // snoozed apps
4723 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05004724 MetricsLogger.action(r.getLogMaker()
4725 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
4726 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004727 if (DBG) {
4728 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
4729 }
4730 mSnoozeHelper.update(userId, r);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05004731 handleSavePolicyFile();
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004732 return false;
4733 }
4734
4735
4736 // blocked apps
4737 if (isBlocked(r, mUsageStats)) {
4738 return false;
4739 }
4740
4741 return true;
4742 }
4743
Andreas Gampea36dc622018-02-05 17:19:22 -08004744 @GuardedBy("mNotificationLock")
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004745 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
4746 String excludedTag) {
4747 int count = 0;
4748 final int N = mNotificationList.size();
4749 for (int i = 0; i < N; i++) {
4750 final NotificationRecord existing = mNotificationList.get(i);
4751 if (existing.sbn.getPackageName().equals(pkg)
4752 && existing.sbn.getUserId() == userId) {
4753 if (existing.sbn.getId() == excludedId
4754 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
4755 continue;
4756 }
4757 count++;
4758 }
4759 }
4760 final int M = mEnqueuedNotifications.size();
4761 for (int i = 0; i < M; i++) {
4762 final NotificationRecord existing = mEnqueuedNotifications.get(i);
4763 if (existing.sbn.getPackageName().equals(pkg)
4764 && existing.sbn.getUserId() == userId) {
4765 count++;
4766 }
4767 }
4768 return count;
4769 }
4770
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004771 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
Beverly3c707b42018-09-14 09:49:07 -04004772 if (isBlocked(r)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004773 Slog.e(TAG, "Suppressing notification from package by user request.");
4774 usageStats.registerBlocked(r);
Beverly3c707b42018-09-14 09:49:07 -04004775 return true;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004776 }
Beverly3c707b42018-09-14 09:49:07 -04004777 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004778 }
4779
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004780 private boolean isBlocked(NotificationRecord r) {
4781 final String pkg = r.sbn.getPackageName();
4782 final int callingUid = r.sbn.getUid();
4783 return mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
4784 || mPreferencesHelper.getImportance(pkg, callingUid)
4785 == NotificationManager.IMPORTANCE_NONE
4786 || r.getImportance() == NotificationManager.IMPORTANCE_NONE;
4787 }
4788
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004789 protected class SnoozeNotificationRunnable implements Runnable {
4790 private final String mKey;
4791 private final long mDuration;
4792 private final String mSnoozeCriterionId;
4793
4794 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
4795 mKey = key;
4796 mDuration = duration;
4797 mSnoozeCriterionId = snoozeCriterionId;
4798 }
4799
4800 @Override
4801 public void run() {
4802 synchronized (mNotificationLock) {
4803 final NotificationRecord r = findNotificationByKeyLocked(mKey);
4804 if (r != null) {
4805 snoozeLocked(r);
4806 }
4807 }
4808 }
4809
Julia Reynolds88860ce2017-06-01 16:55:49 -04004810 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004811 void snoozeLocked(NotificationRecord r) {
4812 if (r.sbn.isGroup()) {
4813 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
4814 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
4815 if (r.getNotification().isGroupSummary()) {
4816 // snooze summary and all children
4817 for (int i = 0; i < groupNotifications.size(); i++) {
4818 snoozeNotificationLocked(groupNotifications.get(i));
4819 }
4820 } else {
4821 // if there is a valid summary for this group, and we are snoozing the only
4822 // child, also snooze the summary
4823 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
4824 if (groupNotifications.size() != 2) {
4825 snoozeNotificationLocked(r);
4826 } else {
4827 // snooze summary and the one child
4828 for (int i = 0; i < groupNotifications.size(); i++) {
4829 snoozeNotificationLocked(groupNotifications.get(i));
4830 }
4831 }
4832 } else {
4833 snoozeNotificationLocked(r);
4834 }
4835 }
4836 } else {
4837 // just snooze the one notification
4838 snoozeNotificationLocked(r);
4839 }
4840 }
4841
Julia Reynolds88860ce2017-06-01 16:55:49 -04004842 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004843 void snoozeNotificationLocked(NotificationRecord r) {
4844 MetricsLogger.action(r.getLogMaker()
4845 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4846 .setType(MetricsEvent.TYPE_CLOSE)
Chris Wren21a2e722017-10-02 17:44:53 -04004847 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
4848 mDuration)
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004849 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4850 mSnoozeCriterionId == null ? 0 : 1));
Esteban Talavera5d603892018-11-15 10:55:24 +00004851 reportUserInteraction(r);
Julia Reynolds0839c022017-06-15 15:24:01 -04004852 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004853 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004854 updateLightsLocked();
4855 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004856 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004857 mSnoozeHelper.snooze(r);
4858 } else {
4859 mSnoozeHelper.snooze(r, mDuration);
4860 }
Julia Reynolds503ed942017-10-04 16:04:56 -04004861 r.recordSnoozed();
Julia Reynoldsb62dad42018-11-26 16:33:02 -05004862 handleSavePolicyFile();
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004863 }
4864 }
4865
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004866 protected class CancelNotificationRunnable implements Runnable {
4867 private final int mCallingUid;
4868 private final int mCallingPid;
4869 private final String mPkg;
4870 private final String mTag;
4871 private final int mId;
4872 private final int mMustHaveFlags;
4873 private final int mMustNotHaveFlags;
4874 private final boolean mSendDelete;
4875 private final int mUserId;
4876 private final int mReason;
4877 private final int mRank;
4878 private final int mCount;
4879 private final ManagedServiceInfo mListener;
4880
4881 CancelNotificationRunnable(final int callingUid, final int callingPid,
4882 final String pkg, final String tag, final int id,
4883 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
4884 final int userId, final int reason, int rank, int count,
4885 final ManagedServiceInfo listener) {
4886 this.mCallingUid = callingUid;
4887 this.mCallingPid = callingPid;
4888 this.mPkg = pkg;
4889 this.mTag = tag;
4890 this.mId = id;
4891 this.mMustHaveFlags = mustHaveFlags;
4892 this.mMustNotHaveFlags = mustNotHaveFlags;
4893 this.mSendDelete = sendDelete;
4894 this.mUserId = userId;
4895 this.mReason = reason;
4896 this.mRank = rank;
4897 this.mCount = count;
4898 this.mListener = listener;
4899 }
4900
4901 @Override
4902 public void run() {
4903 String listenerName = mListener == null ? null : mListener.component.toShortString();
4904 if (DBG) {
4905 EventLogTags.writeNotificationCancel(mCallingUid, mCallingPid, mPkg, mId, mTag,
4906 mUserId, mMustHaveFlags, mMustNotHaveFlags, mReason, listenerName);
4907 }
4908
4909 synchronized (mNotificationLock) {
4910 // Look for the notification, searching both the posted and enqueued lists.
4911 NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId);
4912 if (r != null) {
4913 // The notification was found, check if it should be removed.
4914
4915 // Ideally we'd do this in the caller of this method. However, that would
4916 // require the caller to also find the notification.
4917 if (mReason == REASON_CLICK) {
4918 mUsageStats.registerClickedByUser(r);
4919 }
4920
4921 if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) {
4922 return;
4923 }
4924 if ((r.getNotification().flags & mMustNotHaveFlags) != 0) {
4925 return;
4926 }
4927
4928 // Cancel the notification.
4929 boolean wasPosted = removeFromNotificationListsLocked(r);
4930 cancelNotificationLocked(
4931 r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName);
4932 cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
4933 mSendDelete, null);
4934 updateLightsLocked();
4935 } else {
4936 // No notification was found, assume that it is snoozed and cancel it.
4937 if (mReason != REASON_SNOOZED) {
4938 final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId);
4939 if (wasSnoozed) {
Julia Reynoldsb62dad42018-11-26 16:33:02 -05004940 handleSavePolicyFile();
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004941 }
4942 }
4943 }
4944 }
4945 }
4946 }
4947
Julia Reynoldsbaff4002016-12-15 11:34:26 -05004948 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05004949 private final NotificationRecord r;
4950 private final int userId;
4951
4952 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
4953 this.userId = userId;
4954 this.r = r;
4955 };
4956
4957 @Override
4958 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004959 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05004960 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05004961 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05004962
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004963 final StatusBarNotification n = r.sbn;
4964 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
4965 NotificationRecord old = mNotificationsByKey.get(n.getKey());
4966 if (old != null) {
4967 // Retain ranking information from previous record
4968 r.copyRankingInformation(old);
4969 }
4970
4971 final int callingUid = n.getUid();
4972 final int callingPid = n.getInitialPid();
4973 final Notification notification = n.getNotification();
4974 final String pkg = n.getPackageName();
4975 final int id = n.getId();
4976 final String tag = n.getTag();
4977
4978 // Handle grouped notifications and bail out early if we
4979 // can to avoid extracting signals.
4980 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
4981
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004982 // if this is a group child, unsnooze parent summary
4983 if (n.isGroup() && notification.isGroupChild()) {
4984 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
4985 }
4986
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004987 // This conditional is a dirty hack to limit the logging done on
4988 // behalf of the download manager without affecting other apps.
4989 if (!pkg.equals("com.android.providers.downloads")
4990 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
4991 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05004992 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004993 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05004994 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004995 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
4996 pkg, id, tag, userId, notification.toString(),
4997 enqueueStatus);
4998 }
Chris Wren6676dab2016-12-21 18:26:27 -05004999
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005000 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04005001 if (mAssistants.isEnabled()) {
Tony Makeda84a72018-11-19 17:01:32 +00005002 mAssistants.onNotificationEnqueuedLocked(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005003 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005004 DELAY_FOR_ASSISTANT_TIME);
5005 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005006 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005007 }
5008 }
5009 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005010 }
5011
Beverly5a20a5e2018-03-06 15:02:44 -05005012 @GuardedBy("mNotificationLock")
5013 private boolean isPackageSuspendedLocked(NotificationRecord r) {
5014 final String pkg = r.sbn.getPackageName();
5015 final int callingUid = r.sbn.getUid();
5016
5017 return isPackageSuspendedForUser(pkg, callingUid);
5018 }
5019
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005020 protected class PostNotificationRunnable implements Runnable {
5021 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005022
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005023 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005024 this.key = key;
5025 }
5026
5027 @Override
5028 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005029 synchronized (mNotificationLock) {
5030 try {
5031 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005032 int N = mEnqueuedNotifications.size();
5033 for (int i = 0; i < N; i++) {
5034 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
5035 if (Objects.equals(key, enqueued.getKey())) {
5036 r = enqueued;
5037 break;
Chris Wren6676dab2016-12-21 18:26:27 -05005038 }
Chris Wren6676dab2016-12-21 18:26:27 -05005039 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005040 if (r == null) {
5041 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
5042 return;
5043 }
Beverly5a20a5e2018-03-06 15:02:44 -05005044
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005045 if (isBlocked(r)) {
5046 Slog.i(TAG, "notification blocked by assistant request");
5047 return;
5048 }
5049
Beverly3c707b42018-09-14 09:49:07 -04005050 final boolean isPackageSuspended = isPackageSuspendedLocked(r);
5051 r.setHidden(isPackageSuspended);
5052 if (isPackageSuspended) {
5053 mUsageStats.registerSuspendedByAdmin(r);
5054 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005055 NotificationRecord old = mNotificationsByKey.get(key);
5056 final StatusBarNotification n = r.sbn;
5057 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05005058 int index = indexOfNotificationLocked(n.getKey());
5059 if (index < 0) {
5060 mNotificationList.add(r);
5061 mUsageStats.registerPostedByApp(r);
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04005062 r.setInterruptive(isVisuallyInterruptive(null, r));
Chris Wren6676dab2016-12-21 18:26:27 -05005063 } else {
5064 old = mNotificationList.get(index);
5065 mNotificationList.set(index, r);
5066 mUsageStats.registerUpdatedByApp(r, old);
5067 // Make sure we don't lose the foreground service state.
5068 notification.flags |=
Julia Reynoldse5c60452018-04-30 14:41:36 -04005069 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
Chris Wren6676dab2016-12-21 18:26:27 -05005070 r.isUpdate = true;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04005071 r.setTextChanged(isVisuallyInterruptive(old, r));
Chris Wren6676dab2016-12-21 18:26:27 -05005072 }
5073
5074 mNotificationsByKey.put(n.getKey(), r);
5075
5076 // Ensure if this is a foreground service that the proper additional
5077 // flags are set.
Julia Reynoldse5c60452018-04-30 14:41:36 -04005078 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
Chris Wren6676dab2016-12-21 18:26:27 -05005079 notification.flags |= Notification.FLAG_ONGOING_EVENT
5080 | Notification.FLAG_NO_CLEAR;
5081 }
5082
Julia Reynolds27c0a962018-12-10 12:37:28 -05005083 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05005084 mRankingHelper.sort(mNotificationList);
5085
Gus Prevasa3226492018-10-23 11:10:09 -04005086 if (!r.isHidden()) {
5087 buzzBeepBlinkLocked(r);
5088 }
5089
Chris Wren6676dab2016-12-21 18:26:27 -05005090 if (notification.getSmallIcon() != null) {
5091 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005092 mListeners.notifyPostedLocked(r, old);
Brad Stenningd2e7a972018-10-01 09:08:42 -07005093 if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()))
5094 && !isCritical(r)) {
Julia Reynolds8aebf352017-06-26 11:35:33 -04005095 mHandler.post(new Runnable() {
5096 @Override
5097 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04005098 mGroupHelper.onNotificationPosted(
5099 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04005100 }
5101 });
5102 }
Chris Wren6676dab2016-12-21 18:26:27 -05005103 } else {
5104 Slog.e(TAG, "Not posting notification without small icon: " + notification);
5105 if (old != null && !old.isCanceled) {
Beverly5a20a5e2018-03-06 15:02:44 -05005106 mListeners.notifyRemovedLocked(r,
Julia Reynolds3207e2f2018-12-20 09:39:53 -05005107 NotificationListenerService.REASON_ERROR, r.getStats());
Chris Wren6676dab2016-12-21 18:26:27 -05005108 mHandler.post(new Runnable() {
5109 @Override
5110 public void run() {
5111 mGroupHelper.onNotificationRemoved(n);
5112 }
5113 });
5114 }
5115 // ATTENTION: in a future release we will bail out here
5116 // so that we do not play sounds, show lights, etc. for invalid
5117 // notifications
5118 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
5119 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05005120 }
Chris Wren47633422016-01-22 09:56:59 -05005121
Julia Reynolds1fac86e2018-03-07 08:30:37 -05005122 maybeRecordInterruptionLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005123 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005124 int N = mEnqueuedNotifications.size();
5125 for (int i = 0; i < N; i++) {
5126 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
5127 if (Objects.equals(key, enqueued.getKey())) {
5128 mEnqueuedNotifications.remove(i);
5129 break;
5130 }
5131 }
Chris Wren6676dab2016-12-21 18:26:27 -05005132 }
Chris Wren47633422016-01-22 09:56:59 -05005133 }
5134 }
5135 }
5136
Christoph Studer265c1052014-07-23 17:14:33 +02005137 /**
Julia Reynolds7217dc92018-03-07 12:12:09 -05005138 * If the notification differs enough visually, consider it a new interruptive notification.
5139 */
5140 @GuardedBy("mNotificationLock")
5141 @VisibleForTesting
5142 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
Julia Reynolds760fa762018-06-19 15:39:23 -04005143 // Ignore summary updates because we don't display most of the information.
5144 if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
5145 if (DEBUG_INTERRUPTIVENESS) {
5146 Log.v(TAG, "INTERRUPTIVENESS: "
5147 + r.getKey() + " is not interruptive: summary");
5148 }
5149 return false;
5150 }
5151
Dan Sandler7d67bd42018-05-15 14:06:38 -04005152 if (old == null) {
5153 if (DEBUG_INTERRUPTIVENESS) {
5154 Log.v(TAG, "INTERRUPTIVENESS: "
5155 + r.getKey() + " is interruptive: new notification");
5156 }
5157 return true;
5158 }
5159
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04005160 if (r == null) {
5161 if (DEBUG_INTERRUPTIVENESS) {
5162 Log.v(TAG, "INTERRUPTIVENESS: "
5163 + r.getKey() + " is not interruptive: null");
5164 }
5165 return false;
5166 }
5167
Julia Reynolds7217dc92018-03-07 12:12:09 -05005168 Notification oldN = old.sbn.getNotification();
5169 Notification newN = r.sbn.getNotification();
Dan Sandler7d67bd42018-05-15 14:06:38 -04005170
Julia Reynolds7217dc92018-03-07 12:12:09 -05005171 if (oldN.extras == null || newN.extras == null) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005172 if (DEBUG_INTERRUPTIVENESS) {
5173 Log.v(TAG, "INTERRUPTIVENESS: "
5174 + r.getKey() + " is not interruptive: no extras");
5175 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005176 return false;
5177 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04005178
5179 // Ignore visual interruptions from foreground services because users
5180 // consider them one 'session'. Count them for everything else.
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04005181 if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005182 if (DEBUG_INTERRUPTIVENESS) {
5183 Log.v(TAG, "INTERRUPTIVENESS: "
5184 + r.getKey() + " is not interruptive: foreground service");
5185 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04005186 return false;
5187 }
5188
Dan Sandler7d67bd42018-05-15 14:06:38 -04005189 final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
5190 final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
5191 if (!Objects.equals(oldTitle, newTitle)) {
5192 if (DEBUG_INTERRUPTIVENESS) {
5193 Log.v(TAG, "INTERRUPTIVENESS: "
5194 + r.getKey() + " is interruptive: changed title");
5195 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)",
5196 oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
5197 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)",
5198 newTitle, newTitle.getClass(), newTitle.hashCode()));
5199 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005200 return true;
5201 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04005202 // Do not compare Spannables (will always return false); compare unstyled Strings
5203 final String oldText = String.valueOf(oldN.extras.get(Notification.EXTRA_TEXT));
5204 final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT));
5205 if (!Objects.equals(oldText, newText)) {
5206 if (DEBUG_INTERRUPTIVENESS) {
5207 Log.v(TAG, "INTERRUPTIVENESS: "
5208 + r.getKey() + " is interruptive: changed text");
5209 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)",
5210 oldText, oldText.getClass(), oldText.hashCode()));
5211 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)",
5212 newText, newText.getClass(), newText.hashCode()));
5213 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005214 return true;
5215 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04005216 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
5217 if (DEBUG_INTERRUPTIVENESS) {
5218 Log.v(TAG, "INTERRUPTIVENESS: "
5219 + r.getKey() + " is interruptive: completed progress");
5220 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005221 return true;
5222 }
5223 // Actions
5224 if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005225 if (DEBUG_INTERRUPTIVENESS) {
5226 Log.v(TAG, "INTERRUPTIVENESS: "
5227 + r.getKey() + " is interruptive: changed actions");
5228 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005229 return true;
5230 }
5231
5232 try {
5233 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
5234 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
5235
5236 // Style based comparisons
5237 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005238 if (DEBUG_INTERRUPTIVENESS) {
5239 Log.v(TAG, "INTERRUPTIVENESS: "
5240 + r.getKey() + " is interruptive: styles differ");
5241 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005242 return true;
5243 }
5244
5245 // Remote views
5246 if (Notification.areRemoteViewsChanged(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005247 if (DEBUG_INTERRUPTIVENESS) {
5248 Log.v(TAG, "INTERRUPTIVENESS: "
5249 + r.getKey() + " is interruptive: remoteviews differ");
5250 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005251 return true;
5252 }
5253 } catch (Exception e) {
5254 Slog.w(TAG, "error recovering builder", e);
5255 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04005256
Julia Reynolds7217dc92018-03-07 12:12:09 -05005257 return false;
5258 }
5259
5260 /**
Brad Stenningd2e7a972018-10-01 09:08:42 -07005261 * Check if the notification is classified as critical.
5262 *
5263 * @param record the record to test for criticality
5264 * @return {@code true} if notification is considered critical
5265 *
5266 * @see CriticalNotificationExtractor for criteria
5267 */
5268 private boolean isCritical(NotificationRecord record) {
5269 // 0 is the most critical
5270 return record.getCriticality() < CriticalNotificationExtractor.NORMAL;
5271 }
5272
5273 /**
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05005274 * Keeps the last 5 packages that have notified, by user.
5275 */
5276 @GuardedBy("mNotificationLock")
5277 @VisibleForTesting
5278 protected void logRecentLocked(NotificationRecord r) {
5279 if (r.isUpdate) {
5280 return;
5281 }
5282 ArrayList<NotifyingApp> recentAppsForUser =
5283 mRecentApps.getOrDefault(r.getUser().getIdentifier(), new ArrayList<>(6));
5284 NotifyingApp na = new NotifyingApp()
5285 .setPackage(r.sbn.getPackageName())
5286 .setUid(r.sbn.getUid())
5287 .setLastNotified(r.sbn.getPostTime());
5288 // A new notification gets an app moved to the front of the list
5289 for (int i = recentAppsForUser.size() - 1; i >= 0; i--) {
5290 NotifyingApp naExisting = recentAppsForUser.get(i);
5291 if (na.getPackage().equals(naExisting.getPackage())
5292 && na.getUid() == naExisting.getUid()) {
5293 recentAppsForUser.remove(i);
5294 break;
5295 }
5296 }
5297 // time is always increasing, so always add to the front of the list
5298 recentAppsForUser.add(0, na);
5299 if (recentAppsForUser.size() > 5) {
5300 recentAppsForUser.remove(recentAppsForUser.size() -1);
5301 }
5302 mRecentApps.put(r.getUser().getIdentifier(), recentAppsForUser);
5303 }
5304
5305 /**
Christoph Studer265c1052014-07-23 17:14:33 +02005306 * Ensures that grouped notification receive their special treatment.
5307 *
5308 * <p>Cancels group children if the new notification causes a group to lose
5309 * its summary.</p>
5310 *
5311 * <p>Updates mSummaryByGroupKey.</p>
5312 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005313 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02005314 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
5315 int callingUid, int callingPid) {
5316 StatusBarNotification sbn = r.sbn;
5317 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07005318 if (n.isGroupSummary() && !sbn.isAppGroup()) {
5319 // notifications without a group shouldn't be a summary, otherwise autobundling can
5320 // lead to bugs
5321 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
5322 }
5323
Christoph Studer265c1052014-07-23 17:14:33 +02005324 String group = sbn.getGroupKey();
5325 boolean isSummary = n.isGroupSummary();
5326
5327 Notification oldN = old != null ? old.sbn.getNotification() : null;
5328 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
5329 boolean oldIsSummary = old != null && oldN.isGroupSummary();
5330
5331 if (oldIsSummary) {
5332 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
5333 if (removedSummary != old) {
5334 String removedKey =
5335 removedSummary != null ? removedSummary.getKey() : "<null>";
5336 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
5337 ", removed=" + removedKey);
5338 }
5339 }
5340 if (isSummary) {
5341 mSummaryByGroupKey.put(group, r);
5342 }
5343
5344 // Clear out group children of the old notification if the update
5345 // causes the group summary to go away. This happens when the old
5346 // notification was a summary and the new one isn't, or when the old
5347 // notification was a summary and its group key changed.
5348 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04005349 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
5350 null);
Christoph Studer265c1052014-07-23 17:14:33 +02005351 }
5352 }
5353
Chris Wren93bb8b82016-03-29 14:35:05 -04005354 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04005355 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05005356 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04005357 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05005358 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
5359 REQUEST_CODE_TIMEOUT,
5360 new Intent(ACTION_NOTIFICATION_TIMEOUT)
5361 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
5362 .appendPath(record.getKey()).build())
5363 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
5364 .putExtra(EXTRA_KEY, record.getKey()),
5365 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05005366 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04005367 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05005368 }
5369 }
5370
5371 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04005372 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04005373 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04005374 boolean buzz = false;
5375 boolean beep = false;
5376 boolean blink = false;
5377
Chris Wrena3446562014-06-03 18:11:47 -04005378 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04005379 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04005380
5381 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04005382 final boolean aboveThreshold =
Adora Zhang963328f2018-11-15 18:17:19 -08005383 mIsAutomotive
5384 ? record.getImportance() > NotificationManager.IMPORTANCE_DEFAULT
5385 : record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04005386
5387 // Remember if this notification already owns the notification channels.
5388 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
5389 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04005390 // These are set inside the conditional if the notification is allowed to make noise.
5391 boolean hasValidVibrate = false;
5392 boolean hasValidSound = false;
Julia Reynolds94187562017-10-10 13:58:49 -04005393 boolean sentAccessibilityEvent = false;
5394 // If the notification will appear in the status bar, it should send an accessibility
5395 // event
5396 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
5397 sendAccessibilityEvent(notification, record.sbn.getPackageName());
5398 sentAccessibilityEvent = true;
5399 }
Chris Wrena3446562014-06-03 18:11:47 -04005400
Julia Reynolds76c096d2017-06-19 08:16:04 -04005401 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04005402
Julia Reynolds76c096d2017-06-19 08:16:04 -04005403 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04005404 Uri soundUri = record.getSound();
5405 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
5406 long[] vibration = record.getVibration();
5407 // Demote sound to vibration if vibration missing & phone in vibration mode.
5408 if (vibration == null
5409 && hasValidSound
5410 && (mAudioManager.getRingerModeInternal()
Julia Reynolds85896572017-09-20 12:54:52 -04005411 == AudioManager.RINGER_MODE_VIBRATE)
5412 && mAudioManager.getStreamVolume(
5413 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04005414 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04005415 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04005416 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01005417
Julia Reynolds76c096d2017-06-19 08:16:04 -04005418 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
Julia Reynolds76c096d2017-06-19 08:16:04 -04005419 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04005420 if (!sentAccessibilityEvent) {
5421 sendAccessibilityEvent(notification, record.sbn.getPackageName());
5422 sentAccessibilityEvent = true;
5423 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005424 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04005425 if (hasValidSound) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04005426 if (mInCall) {
5427 playInCallNotification();
5428 beep = true;
5429 } else {
5430 beep = playSound(record, soundUri);
5431 }
Seungho Lee55102a82018-12-09 19:27:36 +09005432 if(beep) {
5433 mSoundNotificationKey = key;
5434 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04005435 }
Chris Wren93bb8b82016-03-29 14:35:05 -04005436
Julia Reynolds7c96b582017-05-25 12:35:36 -04005437 final boolean ringerModeSilent =
5438 mAudioManager.getRingerModeInternal()
5439 == AudioManager.RINGER_MODE_SILENT;
5440 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005441 buzz = playVibration(record, vibration, hasValidSound);
Seungho Lee55102a82018-12-09 19:27:36 +09005442 if(buzz) {
5443 mVibrateNotificationKey = key;
5444 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04005445 }
Tyler Gunn48f86272018-07-03 12:38:49 -07005446 } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
5447 hasValidSound = false;
Chris Wrena3446562014-06-03 18:11:47 -04005448 }
5449 }
Chris Wren93bb8b82016-03-29 14:35:05 -04005450 }
5451 // If a notification is updated to remove the actively playing sound or vibrate,
5452 // cancel that feedback now
5453 if (wasBeep && !hasValidSound) {
5454 clearSoundLocked();
5455 }
5456 if (wasBuzz && !hasValidVibrate) {
5457 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04005458 }
5459
5460 // light
5461 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04005462 boolean wasShowLights = mLights.remove(key);
Julia Reynolds28149f62018-07-03 10:43:35 -04005463 if (canShowLightsLocked(record, aboveThreshold)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04005464 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04005465 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04005466 if (mUseAttentionLight) {
5467 mAttentionLight.pulse();
5468 }
Chris Wren82ba59d2015-06-05 11:23:44 -04005469 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04005470 } else if (wasShowLights) {
5471 updateLightsLocked();
5472 }
Chris Wren82ba59d2015-06-05 11:23:44 -04005473 if (buzz || beep || blink) {
Julia Reynolds28149f62018-07-03 10:43:35 -04005474 // Ignore summary updates because we don't display most of the information.
5475 if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) {
5476 if (DEBUG_INTERRUPTIVENESS) {
5477 Log.v(TAG, "INTERRUPTIVENESS: "
5478 + record.getKey() + " is not interruptive: summary");
5479 }
5480 } else {
5481 if (DEBUG_INTERRUPTIVENESS) {
5482 Log.v(TAG, "INTERRUPTIVENESS: "
5483 + record.getKey() + " is interruptive: alerted");
5484 }
5485 record.setInterruptive(true);
5486 }
Julia Reynolds445cfa82017-05-08 15:41:45 -04005487 MetricsLogger.action(record.getLogMaker()
5488 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
5489 .setType(MetricsEvent.TYPE_OPEN)
5490 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
5491 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04005492 }
Gus Prevasa3226492018-10-23 11:10:09 -04005493 record.setAudiblyAlerted(buzz || beep);
Chris Wrena3446562014-06-03 18:11:47 -04005494 }
5495
Julia Reynolds88860ce2017-06-01 16:55:49 -04005496 @GuardedBy("mNotificationLock")
Julia Reynolds28149f62018-07-03 10:43:35 -04005497 boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
5498 // device lacks light
5499 if (!mHasLight) {
5500 return false;
5501 }
5502 // user turned lights off globally
5503 if (!mNotificationPulseEnabled) {
5504 return false;
5505 }
5506 // the notification/channel has no light
5507 if (record.getLight() == null) {
5508 return false;
5509 }
5510 // unimportant notification
5511 if (!aboveThreshold) {
5512 return false;
5513 }
5514 // suppressed due to DND
5515 if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
5516 return false;
5517 }
5518 // Suppressed because it's a silent update
5519 final Notification notification = record.getNotification();
5520 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
5521 return false;
5522 }
5523 // Suppressed because another notification in its group handles alerting
5524 if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
5525 return false;
5526 }
5527 // not if in call or the screen's on
5528 if (mInCall || mScreenOn) {
5529 return false;
5530 }
5531
5532 return true;
5533 }
5534
5535 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005536 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04005537 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005538 final Notification notification = record.getNotification();
Julia Reynolds28149f62018-07-03 10:43:35 -04005539 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005540 return true;
5541 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005542
Julia Reynolds76c096d2017-06-19 08:16:04 -04005543 // muted by listener
5544 final String disableEffects = disableNotificationEffects(record);
5545 if (disableEffects != null) {
5546 ZenLog.traceDisableEffects(record, disableEffects);
5547 return true;
5548 }
5549
5550 // suppressed due to DND
5551 if (record.isIntercepted()) {
5552 return true;
5553 }
5554
5555 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005556 if (record.sbn.isGroup()) {
Julia Reynolds79dfdd62018-04-17 15:36:33 -04005557 if (notification.suppressAlertingDueToGrouping()) {
5558 return true;
5559 }
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005560 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005561
Julia Reynolds65b85cf2017-07-20 09:19:20 -04005562 // Suppressed for being too recently noisy
5563 final String pkg = record.sbn.getPackageName();
5564 if (mUsageStats.isAlertRateLimited(pkg)) {
5565 Slog.e(TAG, "Muting recently noisy " + record.getKey());
5566 return true;
5567 }
5568
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005569 return false;
5570 }
5571
Julia Reynolds0c299d42016-11-15 14:37:04 -05005572 private boolean playSound(final NotificationRecord record, Uri soundUri) {
5573 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
Jean-Michel Triviec2bb182018-03-23 18:04:00 -07005574 // play notifications if there is no user of exclusive audio focus
5575 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
5576 // VIBRATE ringer mode)
5577 if (!mAudioManager.isAudioFocusExclusive()
5578 && (mAudioManager.getStreamVolume(
5579 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05005580 final long identity = Binder.clearCallingIdentity();
5581 try {
5582 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5583 if (player != null) {
5584 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
5585 + " with attributes " + record.getAudioAttributes());
5586 player.playAsync(soundUri, record.sbn.getUser(), looping,
5587 record.getAudioAttributes());
5588 return true;
5589 }
5590 } catch (RemoteException e) {
5591 } finally {
5592 Binder.restoreCallingIdentity(identity);
5593 }
5594 }
5595 return false;
5596 }
5597
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005598 private boolean playVibration(final NotificationRecord record, long[] vibration,
5599 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005600 // Escalate privileges so we can use the vibrator even if the
5601 // notifying app does not have the VIBRATE permission.
5602 long identity = Binder.clearCallingIdentity();
5603 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005604 final VibrationEffect effect;
5605 try {
5606 final boolean insistent =
5607 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
5608 effect = VibrationEffect.createWaveform(
5609 vibration, insistent ? 0 : -1 /*repeatIndex*/);
5610 } catch (IllegalArgumentException e) {
5611 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
5612 Arrays.toString(vibration));
5613 return false;
5614 }
5615 if (delayVibForSound) {
5616 new Thread(() -> {
5617 // delay the vibration by the same amount as the notification sound
5618 final int waitMs = mAudioManager.getFocusRampTimeMs(
5619 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
5620 record.getAudioAttributes());
5621 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
5622 try {
5623 Thread.sleep(waitMs);
5624 } catch (InterruptedException e) { }
Seungho Leede933882018-10-31 21:49:09 +09005625
5626 // Notifications might be canceled before it actually vibrates due to waitMs,
5627 // so need to check the notification still valide for vibrate.
5628 synchronized (mNotificationLock) {
5629 if (mNotificationsByKey.get(record.getKey()) != null) {
5630 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
5631 effect, "Notification (delayed)", record.getAudioAttributes());
5632 } else {
5633 Slog.e(TAG, "No vibration for canceled notification : " + record.getKey());
5634 }
5635 }
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005636 }).start();
5637 } else {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04005638 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01005639 effect, "Notification", record.getAudioAttributes());
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005640 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005641 return true;
5642 } finally{
5643 Binder.restoreCallingIdentity(identity);
5644 }
5645 }
5646
Julia Reynolds7c96b582017-05-25 12:35:36 -04005647 private boolean isNotificationForCurrentUser(NotificationRecord record) {
5648 final int currentUser;
5649 final long token = Binder.clearCallingIdentity();
5650 try {
5651 currentUser = ActivityManager.getCurrentUser();
5652 } finally {
5653 Binder.restoreCallingIdentity(token);
5654 }
5655 return (record.getUserId() == UserHandle.USER_ALL ||
5656 record.getUserId() == currentUser ||
5657 mUserProfiles.isCurrentProfile(record.getUserId()));
5658 }
5659
Beverly5d463b62017-07-26 14:13:40 -04005660 protected void playInCallNotification() {
Beverly28c3d162018-06-28 11:37:53 -04005661 if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL
5662 && Settings.Secure.getInt(getContext().getContentResolver(),
5663 Settings.Secure.IN_CALL_NOTIFICATION_ENABLED, 1) != 0) {
5664 new Thread() {
5665 @Override
5666 public void run() {
5667 final long identity = Binder.clearCallingIdentity();
5668 try {
5669 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5670 if (player != null) {
5671 if (mCallNotificationToken != null) {
5672 player.stop(mCallNotificationToken);
5673 }
5674 mCallNotificationToken = new Binder();
5675 player.play(mCallNotificationToken, mInCallNotificationUri,
5676 mInCallNotificationAudioAttributes,
5677 mInCallNotificationVolume, false);
luochaojiang50e5273c2018-04-16 16:55:03 +08005678 }
Beverly28c3d162018-06-28 11:37:53 -04005679 } catch (RemoteException e) {
5680 } finally {
5681 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01005682 }
Marta Białka39c992f2011-03-10 10:27:24 +01005683 }
Beverly28c3d162018-06-28 11:37:53 -04005684 }.start();
5685 }
Marta Białka39c992f2011-03-10 10:27:24 +01005686 }
5687
Julia Reynolds88860ce2017-06-01 16:55:49 -04005688 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005689 void showNextToastLocked() {
5690 ToastRecord record = mToastQueue.get(0);
5691 while (record != null) {
5692 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
5693 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005694 record.callback.show(record.token);
Robert Carr997427342018-02-28 18:06:10 -08005695 scheduleDurationReachedLocked(record);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005696 return;
5697 } catch (RemoteException e) {
5698 Slog.w(TAG, "Object died trying to show notification " + record.callback
5699 + " in package " + record.pkg);
5700 // remove it from the list and let the process die
5701 int index = mToastQueue.indexOf(record);
5702 if (index >= 0) {
5703 mToastQueue.remove(index);
5704 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005705 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005706 if (mToastQueue.size() > 0) {
5707 record = mToastQueue.get(0);
5708 } else {
5709 record = null;
5710 }
5711 }
5712 }
5713 }
5714
Julia Reynolds88860ce2017-06-01 16:55:49 -04005715 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005716 void cancelToastLocked(int index) {
5717 ToastRecord record = mToastQueue.get(index);
5718 try {
5719 record.callback.hide();
5720 } catch (RemoteException e) {
5721 Slog.w(TAG, "Object died trying to hide notification " + record.callback
5722 + " in package " + record.pkg);
5723 // don't worry about this, we're about to remove it from
5724 // the list anyway
5725 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005726
5727 ToastRecord lastToast = mToastQueue.remove(index);
Robert Carr997427342018-02-28 18:06:10 -08005728
5729 mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
Jeff Chang48ecef42018-08-09 16:31:59 +08005730 lastToast.displayId);
Robert Carr997427342018-02-28 18:06:10 -08005731 // We passed 'false' for 'removeWindows' so that the client has time to stop
5732 // rendering (as hide above is a one-way message), otherwise we could crash
5733 // a client which was actively using a surface made from the token. However
5734 // we need to schedule a timeout to make sure the token is eventually killed
5735 // one way or another.
Jeff Chang48ecef42018-08-09 16:31:59 +08005736 scheduleKillTokenTimeout(lastToast);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005737
5738 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005739 if (mToastQueue.size() > 0) {
5740 // Show the next one. If the callback fails, this will remove
5741 // it from the list, so don't assume that the list hasn't changed
5742 // after this point.
5743 showNextToastLocked();
5744 }
5745 }
5746
Jeff Chang48ecef42018-08-09 16:31:59 +08005747 void finishTokenLocked(IBinder t, int displayId) {
Robert Carr997427342018-02-28 18:06:10 -08005748 mHandler.removeCallbacksAndMessages(t);
5749 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
5750 // remaining surfaces as either the client has called finishToken indicating
5751 // it has successfully removed the views, or the client has timed out
5752 // at which point anything goes.
Jeff Chang48ecef42018-08-09 16:31:59 +08005753 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */, displayId);
Robert Carr997427342018-02-28 18:06:10 -08005754 }
5755
Julia Reynolds88860ce2017-06-01 16:55:49 -04005756 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08005757 private void scheduleDurationReachedLocked(ToastRecord r)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005758 {
5759 mHandler.removeCallbacksAndMessages(r);
Robert Carr997427342018-02-28 18:06:10 -08005760 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
Rhed Jao406d3a22018-11-30 19:28:58 +08005761 int delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
5762 // Accessibility users may need longer timeout duration. This api compares original delay
5763 // with user's preference and return longer one. It returns original delay if there's no
5764 // preference.
5765 delay = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
5766 AccessibilityManager.FLAG_CONTENT_TEXT);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005767 mHandler.sendMessageDelayed(m, delay);
5768 }
5769
Robert Carr997427342018-02-28 18:06:10 -08005770 private void handleDurationReached(ToastRecord record)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005771 {
5772 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
5773 synchronized (mToastQueue) {
5774 int index = indexOfToastLocked(record.pkg, record.callback);
5775 if (index >= 0) {
5776 cancelToastLocked(index);
5777 }
5778 }
5779 }
5780
Julia Reynolds88860ce2017-06-01 16:55:49 -04005781 @GuardedBy("mToastQueue")
Jeff Chang48ecef42018-08-09 16:31:59 +08005782 private void scheduleKillTokenTimeout(ToastRecord r)
Robert Carr997427342018-02-28 18:06:10 -08005783 {
Jeff Chang48ecef42018-08-09 16:31:59 +08005784 mHandler.removeCallbacksAndMessages(r);
5785 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, r);
Robert Carr3406d462018-03-15 16:19:07 -07005786 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
Robert Carr997427342018-02-28 18:06:10 -08005787 }
5788
Jeff Chang48ecef42018-08-09 16:31:59 +08005789 private void handleKillTokenTimeout(ToastRecord record)
Robert Carr997427342018-02-28 18:06:10 -08005790 {
Jeff Chang48ecef42018-08-09 16:31:59 +08005791 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.token);
Robert Carr997427342018-02-28 18:06:10 -08005792 synchronized (mToastQueue) {
Jeff Chang48ecef42018-08-09 16:31:59 +08005793 finishTokenLocked(record.token, record.displayId);
Robert Carr997427342018-02-28 18:06:10 -08005794 }
5795 }
5796
5797 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005798 int indexOfToastLocked(String pkg, ITransientNotification callback)
5799 {
5800 IBinder cbak = callback.asBinder();
5801 ArrayList<ToastRecord> list = mToastQueue;
5802 int len = list.size();
5803 for (int i=0; i<len; i++) {
5804 ToastRecord r = list.get(i);
Beverly Taia7ed0ab2018-06-11 14:50:36 +00005805 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08005806 return i;
5807 }
5808 }
5809 return -1;
5810 }
5811
Julia Reynolds88860ce2017-06-01 16:55:49 -04005812 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005813 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005814 {
5815 int toastCount = 0; // toasts from this pid
5816 ArrayList<ToastRecord> list = mToastQueue;
5817 int N = list.size();
5818 for (int i=0; i<N; i++) {
5819 ToastRecord r = list.get(i);
5820 if (r.pid == pid) {
5821 toastCount++;
5822 }
5823 }
5824 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07005825 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08005826 } catch (RemoteException e) {
5827 // Shouldn't happen.
5828 }
5829 }
5830
Chris Wrenf9536642014-04-17 10:01:54 -04005831 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005832 if (!(message.obj instanceof RankingReconsideration)) return;
5833 RankingReconsideration recon = (RankingReconsideration) message.obj;
5834 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04005835 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005836 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005837 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
5838 if (record == null) {
5839 return;
Chris Wrenf9536642014-04-17 10:01:54 -04005840 }
Chris Wren333a61c2014-05-28 16:40:57 -04005841 int indexBefore = findNotificationRecordIndexLocked(record);
5842 boolean interceptBefore = record.isIntercepted();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005843 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04005844 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04005845 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04005846 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04005847 int indexAfter = findNotificationRecordIndexLocked(record);
5848 boolean interceptAfter = record.isIntercepted();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005849 int visibilityAfter = record.getPackageVisibilityOverride();
5850 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
5851 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005852 if (interceptBefore && !interceptAfter
Julia Reynoldsd6730072019-01-04 12:52:52 -05005853 && record.isNewEnoughForAlerting(System.currentTimeMillis())) {
Chris Wrena3446562014-06-03 18:11:47 -04005854 buzzBeepBlinkLocked(record);
5855 }
Chris Wrenf9536642014-04-17 10:01:54 -04005856 }
Chris Wren333a61c2014-05-28 16:40:57 -04005857 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005858 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04005859 }
5860 }
5861
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005862 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04005863 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005864 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04005865 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005866 // Any field that can change via one of the extractors needs to be added here.
5867 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005868 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05005869 boolean[] showBadges = new boolean[N];
Julia Reynolds4509ce72019-01-31 13:12:43 -05005870 boolean[] allowBubbles = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005871 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
5872 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
5873 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
5874 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Julia Reynolds503ed942017-10-04 16:04:56 -04005875 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005876 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
Gustav Sennton1463d832018-11-06 16:12:48 +00005877 ArrayList<ArrayList<Notification.Action>> systemSmartActionsBefore = new ArrayList<>(N);
Tony Makc9acf672018-07-20 13:58:24 +02005878 ArrayList<ArrayList<CharSequence>> smartRepliesBefore = new ArrayList<>(N);
Julia Reynolds27c0a962018-12-10 12:37:28 -05005879 int[] importancesBefore = new int[N];
Chris Wren54bbef42014-07-09 18:37:56 -04005880 for (int i = 0; i < N; i++) {
5881 final NotificationRecord r = mNotificationList.get(i);
5882 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005883 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05005884 showBadges[i] = r.canShowBadge();
Julia Reynolds4509ce72019-01-31 13:12:43 -05005885 allowBubbles[i] = r.canBubble();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005886 channelBefore.add(r.getChannel());
5887 groupKeyBefore.add(r.getGroupKey());
5888 overridePeopleBefore.add(r.getPeopleOverride());
5889 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Julia Reynolds503ed942017-10-04 16:04:56 -04005890 userSentimentBefore.add(r.getUserSentiment());
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005891 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
Gustav Sennton1463d832018-11-06 16:12:48 +00005892 systemSmartActionsBefore.add(r.getSystemGeneratedSmartActions());
Tony Makc9acf672018-07-20 13:58:24 +02005893 smartRepliesBefore.add(r.getSmartReplies());
Julia Reynolds27c0a962018-12-10 12:37:28 -05005894 importancesBefore[i] = r.getImportance();
Chris Wren54bbef42014-07-09 18:37:56 -04005895 mRankingHelper.extractSignals(r);
5896 }
Chris Wren19a02b02015-12-22 10:34:22 -05005897 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04005898 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005899 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005900 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05005901 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005902 || showBadges[i] != r.canShowBadge()
Julia Reynolds4509ce72019-01-31 13:12:43 -05005903 || allowBubbles[i] != r.canBubble()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005904 || !Objects.equals(channelBefore.get(i), r.getChannel())
5905 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
5906 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
Julia Reynolds503ed942017-10-04 16:04:56 -04005907 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005908 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
5909 || !Objects.equals(suppressVisuallyBefore.get(i),
Tony Mak628cb932018-06-19 18:30:41 +01005910 r.getSuppressedVisualEffects())
Gustav Sennton1463d832018-11-06 16:12:48 +00005911 || !Objects.equals(systemSmartActionsBefore.get(i),
5912 r.getSystemGeneratedSmartActions())
Julia Reynolds27c0a962018-12-10 12:37:28 -05005913 || !Objects.equals(smartRepliesBefore.get(i), r.getSmartReplies())
5914 || importancesBefore[i] != r.getImportance()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005915 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04005916 return;
5917 }
5918 }
5919 }
5920 }
5921
Julia Reynolds88860ce2017-06-01 16:55:49 -04005922 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005923 private void recordCallerLocked(NotificationRecord record) {
5924 if (mZenModeHelper.isCall(record)) {
5925 mZenModeHelper.recordCaller(record);
5926 }
5927 }
5928
Christoph Studerd5092bc2014-07-03 17:47:58 +02005929 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04005930 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005931 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02005932 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005933 if (record.isIntercepted()) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05005934 record.setSuppressedVisualEffects(
Beverlyff2df9b2018-10-10 16:54:10 -04005935 mZenModeHelper.getConsolidatedNotificationPolicy().suppressedVisualEffects);
Julia Reynolds445cfa82017-05-08 15:41:45 -04005936 } else {
5937 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005938 }
Chris Wren333a61c2014-05-28 16:40:57 -04005939 }
5940
Julia Reynolds88860ce2017-06-01 16:55:49 -04005941 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04005942 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04005943 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04005944 }
5945
Chris Wrenf9536642014-04-17 10:01:54 -04005946 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005947 synchronized (mNotificationLock) {
Beverly5a20a5e2018-03-06 15:02:44 -05005948 mListeners.notifyRankingUpdateLocked(null);
Chris Wrenf9536642014-04-17 10:01:54 -04005949 }
5950 }
5951
John Spurlockd8afe3c2014-08-01 14:04:07 -04005952 private void scheduleListenerHintsChanged(int state) {
5953 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
5954 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04005955 }
5956
Christoph Studer85a384b2014-08-27 20:16:15 +02005957 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
5958 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
5959 mHandler.obtainMessage(
5960 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
5961 listenerInterruptionFilter,
5962 0).sendToTarget();
5963 }
5964
John Spurlockd8afe3c2014-08-01 14:04:07 -04005965 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005966 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005967 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005968 }
5969 }
5970
Christoph Studer85a384b2014-08-27 20:16:15 +02005971 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005972 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02005973 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
5974 }
5975 }
5976
Julia Reynoldsb0405592018-11-26 17:01:13 -05005977 private void handleOnPackageChanged(boolean removingPackage, int changeUserId,
5978 String[] pkgList, int[] uidList) {
5979 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
5980 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
5981 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
5982 mPreferencesHelper.onPackagesChanged(
5983 removingPackage, changeUserId, pkgList, uidList);
5984 handleSavePolicyFile();
5985 }
5986
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005987 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08005988 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005989 public WorkerHandler(Looper looper) {
5990 super(looper);
5991 }
5992
Adam Lesinski182f73f2013-12-05 16:48:06 -08005993 @Override
5994 public void handleMessage(Message msg)
5995 {
5996 switch (msg.what)
5997 {
Robert Carr997427342018-02-28 18:06:10 -08005998 case MESSAGE_DURATION_REACHED:
Julia Reynoldsb0405592018-11-26 17:01:13 -05005999 handleDurationReached((ToastRecord) msg.obj);
Robert Carr997427342018-02-28 18:06:10 -08006000 break;
6001 case MESSAGE_FINISH_TOKEN_TIMEOUT:
Julia Reynoldsb0405592018-11-26 17:01:13 -05006002 handleKillTokenTimeout((ToastRecord) msg.obj);
Adam Lesinski182f73f2013-12-05 16:48:06 -08006003 break;
Chris Wrenf9536642014-04-17 10:01:54 -04006004 case MESSAGE_SEND_RANKING_UPDATE:
6005 handleSendRankingUpdate();
6006 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04006007 case MESSAGE_LISTENER_HINTS_CHANGED:
6008 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04006009 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02006010 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
6011 handleListenerInterruptionFilterChanged(msg.arg1);
6012 break;
Julia Reynoldsb0405592018-11-26 17:01:13 -05006013 case MESSAGE_ON_PACKAGE_CHANGED:
6014 SomeArgs args = (SomeArgs) msg.obj;
6015 handleOnPackageChanged((boolean) args.arg1, args.argi1, (String[]) args.arg2,
6016 (int[]) args.arg3);
6017 args.recycle();
6018 break;
Chris Wrenf9536642014-04-17 10:01:54 -04006019 }
6020 }
6021
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006022 protected void scheduleSendRankingUpdate() {
6023 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
6024 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
6025 sendMessage(m);
6026 }
6027 }
6028
Julia Reynoldsefcdff42018-08-09 09:42:56 -04006029 protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable) {
6030 if (!hasCallbacks(cancelRunnable)) {
6031 sendMessage(Message.obtain(this, cancelRunnable));
6032 }
6033 }
Julia Reynoldsb0405592018-11-26 17:01:13 -05006034
6035 protected void scheduleOnPackageChanged(boolean removingPackage, int changeUserId,
6036 String[] pkgList, int[] uidList) {
6037 SomeArgs args = SomeArgs.obtain();
6038 args.arg1 = removingPackage;
6039 args.argi1 = changeUserId;
6040 args.arg2 = pkgList;
6041 args.arg3 = uidList;
6042 sendMessage(Message.obtain(this, MESSAGE_ON_PACKAGE_CHANGED, args));
6043 }
Chris Wrenf9536642014-04-17 10:01:54 -04006044 }
6045
Chris Wren51017d02015-12-15 15:34:46 -05006046 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04006047 {
Chris Wren51017d02015-12-15 15:34:46 -05006048 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04006049 super(looper);
6050 }
6051
6052 @Override
6053 public void handleMessage(Message msg) {
6054 switch (msg.what) {
6055 case MESSAGE_RECONSIDER_RANKING:
6056 handleRankingReconsideration(msg);
6057 break;
Chris Wren51017d02015-12-15 15:34:46 -05006058 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006059 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04006060 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08006061 }
6062 }
Chris Wren51017d02015-12-15 15:34:46 -05006063
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006064 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05006065 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05006066 Message msg = Message.obtain();
6067 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05006068 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05006069 }
6070
6071 public void requestReconsideration(RankingReconsideration recon) {
6072 Message m = Message.obtain(this,
6073 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
6074 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
6075 sendMessageDelayed(m, delay);
6076 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08006077 }
6078
Adam Lesinski182f73f2013-12-05 16:48:06 -08006079 // Notifications
6080 // ============================================================================
6081 static int clamp(int x, int low, int high) {
6082 return (x < low) ? low : ((x > high) ? high : x);
6083 }
6084
6085 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
Eugene Suslad4128ec2017-12-04 19:48:41 +00006086 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07006087 return;
6088 }
6089
6090 AccessibilityEvent event =
6091 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
6092 event.setPackageName(packageName);
6093 event.setClassName(Notification.class.getName());
6094 event.setParcelableData(notification);
6095 CharSequence tickerText = notification.tickerText;
6096 if (!TextUtils.isEmpty(tickerText)) {
6097 event.getText().add(tickerText);
6098 }
6099
Julia Reynolds94187562017-10-10 13:58:49 -04006100 mAccessibilityManager.sendAccessibilityEvent(event);
svetoslavganov75986cf2009-05-14 22:28:01 -07006101 }
6102
Julia Reynolds0839c022017-06-15 15:24:01 -04006103 /**
6104 * Removes all NotificationsRecords with the same key as the given notification record
6105 * from both lists. Do not call this method while iterating over either list.
6106 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006107 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04006108 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
6109 // Remove from both lists, either list could have a separate Record for what is
6110 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006111 boolean wasPosted = false;
6112 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04006113 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
6114 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006115 mNotificationList.remove(recordInList);
6116 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006117 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006118 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006119 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006120 != null) {
6121 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006122 }
Julia Reynolds0839c022017-06-15 15:24:01 -04006123 return wasPosted;
6124 }
6125
6126 @GuardedBy("mNotificationLock")
6127 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04006128 boolean wasPosted, String listenerName) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08006129 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName);
6130 }
6131
6132 @GuardedBy("mNotificationLock")
6133 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
6134 int rank, int count, boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04006135 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04006136
6137 // Record caller.
6138 recordCallerLocked(r);
6139
Julia Reynolds503ed942017-10-04 16:04:56 -04006140 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
6141 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
6142 }
6143
Joe Onorato46439ce2010-11-19 13:56:21 -08006144 // tell the app
6145 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05006146 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08006147 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05006148 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08006149 } catch (PendingIntent.CanceledException ex) {
6150 // do nothing - there's no relevant way to recover, and
6151 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04006152 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08006153 }
6154 }
6155 }
6156
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006157 // Only cancel these if this notification actually got to be posted.
6158 if (wasPosted) {
6159 // status bar
6160 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05006161 if (reason != REASON_SNOOZED) {
6162 r.isCanceled = true;
6163 }
Beverly5a20a5e2018-03-06 15:02:44 -05006164 mListeners.notifyRemovedLocked(r, reason, r.getStats());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006165 mHandler.post(new Runnable() {
6166 @Override
6167 public void run() {
6168 mGroupHelper.onNotificationRemoved(r.sbn);
6169 }
6170 });
6171 }
6172
6173 // sound
6174 if (canceledKey.equals(mSoundNotificationKey)) {
6175 mSoundNotificationKey = null;
6176 final long identity = Binder.clearCallingIdentity();
6177 try {
6178 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
6179 if (player != null) {
6180 player.stopAsync();
6181 }
6182 } catch (RemoteException e) {
6183 } finally {
6184 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04006185 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006186 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006187
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006188 // vibrate
6189 if (canceledKey.equals(mVibrateNotificationKey)) {
6190 mVibrateNotificationKey = null;
6191 long identity = Binder.clearCallingIdentity();
6192 try {
6193 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07006194 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006195 finally {
6196 Binder.restoreCallingIdentity(identity);
6197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006198 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006199
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006200 // light
6201 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006202 }
6203
Christoph Studer546bec82014-03-14 12:17:12 +01006204 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04006205 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01006206 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04006207 case REASON_CANCEL:
6208 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01006209 case REASON_LISTENER_CANCEL:
6210 case REASON_LISTENER_CANCEL_ALL:
6211 mUsageStats.registerDismissedByUser(r);
6212 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05006213 case REASON_APP_CANCEL:
6214 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01006215 mUsageStats.registerRemovedByApp(r);
6216 break;
Christoph Studer546bec82014-03-14 12:17:12 +01006217 }
6218
Christoph Studer265c1052014-07-23 17:14:33 +02006219 String groupKey = r.getGroupKey();
6220 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006221 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02006222 mSummaryByGroupKey.remove(groupKey);
6223 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04006224 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
6225 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
6226 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04006227 }
Christoph Studercef37cf2014-07-25 14:18:17 +02006228
Daniel Sandler23d7c702013-03-07 16:32:06 -05006229 // Save it for users of getHistoricalNotifications()
6230 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02006231
Chris Wren6650e572015-05-15 17:19:25 -04006232 final long now = System.currentTimeMillis();
Julia Reynolds3dfdde02018-10-08 09:17:56 -04006233 final LogMaker logMaker = r.getItemLogMaker()
Chris Wren9eb5e102017-01-26 13:15:06 -05006234 .setType(MetricsEvent.TYPE_DISMISS)
Dieter Hsud39f0d52018-04-14 02:08:30 +08006235 .setSubtype(reason);
6236 if (rank != -1 && count != -1) {
6237 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
6238 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
6239 }
6240 MetricsLogger.action(logMaker);
Chris Wrene6ddb8a2015-05-27 15:21:00 -04006241 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Dieter Hsud39f0d52018-04-14 02:08:30 +08006242 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
6243 rank, count, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006244 }
6245
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006246 @VisibleForTesting
6247 void updateUriPermissions(@Nullable NotificationRecord newRecord,
6248 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) {
6249 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey();
6250 if (DBG) Slog.d(TAG, key + ": updating permissions");
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006251
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006252 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null;
6253 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null;
6254
6255 // Shortcut when no Uris involved
6256 if (newUris == null && oldUris == null) {
6257 return;
6258 }
6259
6260 // Inherit any existing owner
6261 IBinder permissionOwner = null;
6262 if (newRecord != null && permissionOwner == null) {
6263 permissionOwner = newRecord.permissionOwner;
6264 }
6265 if (oldRecord != null && permissionOwner == null) {
6266 permissionOwner = oldRecord.permissionOwner;
6267 }
6268
6269 // If we have Uris to grant, but no owner yet, go create one
6270 if (newUris != null && permissionOwner == null) {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07006271 if (DBG) Slog.d(TAG, key + ": creating owner");
6272 permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006273 }
6274
6275 // If we have no Uris to grant, but an existing owner, go destroy it
6276 if (newUris == null && permissionOwner != null) {
6277 final long ident = Binder.clearCallingIdentity();
6278 try {
6279 if (DBG) Slog.d(TAG, key + ": destroying owner");
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07006280 mUgmInternal.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006281 UserHandle.getUserId(oldRecord.getUid()));
6282 permissionOwner = null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006283 } finally {
6284 Binder.restoreCallingIdentity(ident);
6285 }
6286 }
6287
6288 // Grant access to new Uris
6289 if (newUris != null && permissionOwner != null) {
6290 for (int i = 0; i < newUris.size(); i++) {
6291 final Uri uri = newUris.valueAt(i);
6292 if (oldUris == null || !oldUris.contains(uri)) {
6293 if (DBG) Slog.d(TAG, key + ": granting " + uri);
6294 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
6295 targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006296 }
6297 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006298 }
6299
6300 // Revoke access to old Uris
6301 if (oldUris != null && permissionOwner != null) {
6302 for (int i = 0; i < oldUris.size(); i++) {
6303 final Uri uri = oldUris.valueAt(i);
6304 if (newUris == null || !newUris.contains(uri)) {
6305 if (DBG) Slog.d(TAG, key + ": revoking " + uri);
6306 revokeUriPermission(permissionOwner, uri, oldRecord.getUid());
6307 }
6308 }
6309 }
6310
6311 if (newRecord != null) {
6312 newRecord.permissionOwner = permissionOwner;
6313 }
6314 }
6315
6316 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg,
6317 int targetUserId) {
6318 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
6319
6320 final long ident = Binder.clearCallingIdentity();
6321 try {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07006322 mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006323 ContentProvider.getUriWithoutUserId(uri),
6324 Intent.FLAG_GRANT_READ_URI_PERMISSION,
6325 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
6326 targetUserId);
6327 } catch (RemoteException ignored) {
6328 // Ignored because we're in same process
6329 } finally {
6330 Binder.restoreCallingIdentity(ident);
6331 }
6332 }
6333
6334 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUid) {
6335 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
6336
6337 final long ident = Binder.clearCallingIdentity();
6338 try {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07006339 mUgmInternal.revokeUriPermissionFromOwner(
6340 owner,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006341 ContentProvider.getUriWithoutUserId(uri),
6342 Intent.FLAG_GRANT_READ_URI_PERMISSION,
6343 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006344 } finally {
6345 Binder.restoreCallingIdentity(ident);
6346 }
6347 }
6348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006349 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07006350 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006351 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006352 */
John Spurlocke6a7d932014-03-13 12:29:00 -04006353 void cancelNotification(final int callingUid, final int callingPid,
6354 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07006355 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04006356 final int userId, final int reason, final ManagedServiceInfo listener) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08006357 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
6358 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
6359 }
6360
6361 /**
6362 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
6363 * and none of the {@code mustNotHaveFlags}.
6364 */
6365 void cancelNotification(final int callingUid, final int callingPid,
6366 final String pkg, final String tag, final int id,
6367 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
Julia Reynoldsefcdff42018-08-09 09:42:56 -04006368 final int userId, final int reason, int rank, int count,
6369 final ManagedServiceInfo listener) {
Svetoslav Ganov835835e2013-08-04 20:17:52 -07006370 // In enqueueNotificationInternal notifications are added by scheduling the
6371 // work on the worker handler. Hence, we also schedule the cancel on this
6372 // handler to avoid a scenario where an add notification call followed by a
6373 // remove notification call ends up in not removing the notification.
Julia Reynoldsefcdff42018-08-09 09:42:56 -04006374 mHandler.scheduleCancelNotification(new CancelNotificationRunnable(callingUid, callingPid,
6375 pkg, tag, id, mustHaveFlags, mustNotHaveFlags, sendDelete, userId, reason, rank,
6376 count, listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006377 }
6378
6379 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07006380 * Determine whether the userId applies to the notification in question, either because
6381 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
6382 */
6383 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
6384 return
6385 // looking for USER_ALL notifications? match everything
6386 userId == UserHandle.USER_ALL
6387 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05006388 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07006389 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05006390 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07006391 }
6392
6393 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006394 * Determine whether the userId applies to the notification in question, either because
6395 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01006396 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006397 */
Kenny Guy2a764942014-04-02 13:29:20 +01006398 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00006399 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04006400 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006401 }
6402
6403 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05006404 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006405 * {@code mustHaveFlags}.
6406 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006407 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04006408 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04006409 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006410 mHandler.post(new Runnable() {
6411 @Override
6412 public void run() {
6413 String listenerName = listener == null ? null : listener.component.toShortString();
6414 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
6415 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
6416 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006417
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006418 // Why does this parameter exist? Do we actually want to execute the above if doit
6419 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08006420 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006421 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08006422 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006423
6424 synchronized (mNotificationLock) {
6425 FlagChecker flagChecker = (int flags) -> {
6426 if ((flags & mustHaveFlags) != mustHaveFlags) {
6427 return false;
6428 }
6429 if ((flags & mustNotHaveFlags) != 0) {
6430 return false;
6431 }
6432 return true;
6433 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006434 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
6435 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
6436 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04006437 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006438 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
6439 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
6440 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04006441 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006442 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02006443 }
6444 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006445 });
6446 }
6447
6448 private interface FlagChecker {
6449 // Returns false if these flags do not pass the defined flag test.
6450 public boolean apply(int flags);
6451 }
6452
Julia Reynolds88860ce2017-06-01 16:55:49 -04006453 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006454 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
6455 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
6456 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04006457 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006458 ArrayList<NotificationRecord> canceledNotifications = null;
6459 for (int i = notificationList.size() - 1; i >= 0; --i) {
6460 NotificationRecord r = notificationList.get(i);
6461 if (includeCurrentProfiles) {
6462 if (!notificationMatchesCurrentProfiles(r, userId)) {
6463 continue;
6464 }
6465 } else if (!notificationMatchesUserId(r, userId)) {
6466 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006467 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006468 // Don't remove notifications to all, if there's no package name specified
6469 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
6470 continue;
6471 }
6472 if (!flagChecker.apply(r.getFlags())) {
6473 continue;
6474 }
6475 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
6476 continue;
6477 }
6478 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
6479 continue;
6480 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006481 if (canceledNotifications == null) {
6482 canceledNotifications = new ArrayList<>();
6483 }
Julia Reynolds0839c022017-06-15 15:24:01 -04006484 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04006485 mNotificationsByKey.remove(r.getKey());
Julia Reynoldsfd4099d2018-08-21 11:06:06 -04006486 r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006487 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04006488 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006489 }
6490 if (canceledNotifications != null) {
6491 final int M = canceledNotifications.size();
6492 for (int i = 0; i < M; i++) {
6493 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04006494 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006495 }
6496 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006497 }
6498 }
6499
Julia Reynolds50989772017-02-23 14:32:16 -05006500 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006501 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05006502 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05006503 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05006504 return;
6505 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05006506
Julia Reynolds79672302017-01-12 08:30:16 -05006507 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05006508 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
6509 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05006510 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006511 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006512 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006513 }
6514
6515 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
6516 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006517 if (DBG) {
6518 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
6519 }
Julia Reynolds79672302017-01-12 08:30:16 -05006520 mSnoozeHelper.repost(key);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05006521 handleSavePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006522 }
6523
Julia Reynolds88860ce2017-06-01 16:55:49 -04006524 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07006525 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04006526 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006527 mHandler.post(new Runnable() {
6528 @Override
6529 public void run() {
6530 synchronized (mNotificationLock) {
6531 String listenerName =
6532 listener == null ? null : listener.component.toShortString();
6533 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
6534 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01006535
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006536 FlagChecker flagChecker = (int flags) -> {
6537 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
6538 != 0) {
6539 return false;
6540 }
6541 return true;
6542 };
6543
6544 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
6545 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
6546 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04006547 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006548 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
6549 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
6550 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04006551 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006552 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00006553 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006554 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006555 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006556 }
6557
Christoph Studere4ef156b2014-07-04 18:41:57 +02006558 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04006559 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02006560 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04006561 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02006562 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02006563 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02006564 return;
6565 }
6566
6567 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02006568
6569 if (pkg == null) {
6570 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
6571 return;
6572 }
6573
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006574 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04006575 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006576 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04006577 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006578 }
6579
Julia Reynolds88860ce2017-06-01 16:55:49 -04006580 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006581 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
6582 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04006583 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006584 final String pkg = parentNotification.sbn.getPackageName();
6585 final int userId = parentNotification.getUserId();
6586 final int reason = REASON_GROUP_SUMMARY_CANCELED;
6587 for (int i = notificationList.size() - 1; i >= 0; i--) {
6588 final NotificationRecord childR = notificationList.get(i);
6589 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04006590 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006591 childR.getGroupKey().equals(parentNotification.getGroupKey())
Julia Reynoldse5c60452018-04-30 14:41:36 -04006592 && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
Beverly40239d92017-07-07 10:20:41 -04006593 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02006594 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
6595 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04006596 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04006597 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04006598 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02006599 }
6600 }
6601 }
6602
Julia Reynolds88860ce2017-06-01 16:55:49 -04006603 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08006604 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006605 {
The Android Open Source Project10592532009-03-18 17:39:46 -07006606 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05006607 NotificationRecord ledNotification = null;
6608 while (ledNotification == null && !mLights.isEmpty()) {
6609 final String owner = mLights.get(mLights.size() - 1);
6610 ledNotification = mNotificationsByKey.get(owner);
6611 if (ledNotification == null) {
6612 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
6613 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006614 }
6615 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006616
Mike Lockwood63b5ad92011-08-30 09:55:30 -04006617 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05006618 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05006619 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07006620 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006621 NotificationRecord.Light light = ledNotification.getLight();
6622 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05006623 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006624 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
6625 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05006626 }
The Android Open Source Project10592532009-03-18 17:39:46 -07006627 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006628 }
6629
Julia Reynolds88860ce2017-06-01 16:55:49 -04006630 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006631 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
6632 String groupKey, int userId) {
6633 List<NotificationRecord> records = new ArrayList<>();
6634 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
6635 records.addAll(
6636 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
6637 return records;
6638 }
6639
6640
Julia Reynolds88860ce2017-06-01 16:55:49 -04006641 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006642 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
6643 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
6644 List<NotificationRecord> records = new ArrayList<>();
6645 final int len = list.size();
6646 for (int i = 0; i < len; i++) {
6647 NotificationRecord r = list.get(i);
6648 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
6649 && r.sbn.getPackageName().equals(pkg)) {
6650 records.add(r);
6651 }
6652 }
6653 return records;
6654 }
6655
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006656 // Searches both enqueued and posted notifications by key.
6657 // TODO: need to combine a bunch of these getters with slightly different behavior.
6658 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04006659 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006660 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006661 NotificationRecord r;
6662 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
6663 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006664 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006665 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
6666 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006667 }
6668 return null;
6669 }
6670
Julia Reynolds88860ce2017-06-01 16:55:49 -04006671 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006672 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006673 NotificationRecord r;
6674 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
6675 return r;
6676 }
6677 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
6678 != null) {
6679 return r;
6680 }
6681 return null;
6682 }
6683
Julia Reynolds88860ce2017-06-01 16:55:49 -04006684 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006685 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006686 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006687 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006688 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006689 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01006690 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
6691 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006692 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006693 }
6694 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006695 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006696 }
6697
Julia Reynolds88860ce2017-06-01 16:55:49 -04006698 @GuardedBy("mNotificationLock")
Julia Reynolds564273f2018-09-13 15:53:11 -04006699 private List<NotificationRecord> findNotificationsByListLocked(
6700 ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) {
6701 List<NotificationRecord> matching = new ArrayList<>();
6702 final int len = list.size();
6703 for (int i = 0; i < len; i++) {
6704 NotificationRecord r = list.get(i);
6705 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
6706 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
6707 matching.add(r);
6708 }
6709 }
6710 return matching;
6711 }
6712
6713 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006714 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04006715 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006716 final int N = list.size();
6717 for (int i = 0; i < N; i++) {
6718 if (key.equals(list.get(i).getKey())) {
6719 return list.get(i);
6720 }
6721 }
6722 return null;
6723 }
6724
Julia Reynolds88860ce2017-06-01 16:55:49 -04006725 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02006726 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02006727 final int N = mNotificationList.size();
6728 for (int i = 0; i < N; i++) {
6729 if (key.equals(mNotificationList.get(i).getKey())) {
6730 return i;
6731 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02006732 }
Christoph Studerc5115552014-06-12 20:22:31 +02006733 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02006734 }
6735
Beverly5a20a5e2018-03-06 15:02:44 -05006736 @VisibleForTesting
6737 protected void hideNotificationsForPackages(String[] pkgs) {
6738 synchronized (mNotificationLock) {
6739 List<String> pkgList = Arrays.asList(pkgs);
6740 List<NotificationRecord> changedNotifications = new ArrayList<>();
6741 int numNotifications = mNotificationList.size();
6742 for (int i = 0; i < numNotifications; i++) {
6743 NotificationRecord rec = mNotificationList.get(i);
6744 if (pkgList.contains(rec.sbn.getPackageName())) {
6745 rec.setHidden(true);
6746 changedNotifications.add(rec);
6747 }
6748 }
6749
6750 mListeners.notifyHiddenLocked(changedNotifications);
6751 }
6752 }
6753
6754 @VisibleForTesting
6755 protected void unhideNotificationsForPackages(String[] pkgs) {
6756 synchronized (mNotificationLock) {
6757 List<String> pkgList = Arrays.asList(pkgs);
6758 List<NotificationRecord> changedNotifications = new ArrayList<>();
6759 int numNotifications = mNotificationList.size();
6760 for (int i = 0; i < numNotifications; i++) {
6761 NotificationRecord rec = mNotificationList.get(i);
6762 if (pkgList.contains(rec.sbn.getPackageName())) {
6763 rec.setHidden(false);
6764 changedNotifications.add(rec);
6765 }
6766 }
6767
6768 mListeners.notifyUnhiddenLocked(changedNotifications);
6769 }
6770 }
6771
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006772 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006773 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006774 updateLightsLocked();
6775 }
6776 }
John Spurlocke677d712014-02-13 12:52:19 -05006777
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006778 protected boolean isCallingUidSystem() {
6779 final int uid = Binder.getCallingUid();
6780 return uid == Process.SYSTEM_UID;
6781 }
6782
6783 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04006784 final int appid = UserHandle.getAppId(uid);
6785 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
6786 }
John Spurlockb408e8e2014-04-23 21:12:45 -04006787
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006788 // TODO: Most calls should probably move to isCallerSystem.
6789 protected boolean isCallerSystemOrPhone() {
6790 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04006791 }
6792
Julia Reynoldsb852e562017-06-06 16:14:18 -04006793 private void checkCallerIsSystemOrShell() {
6794 if (Binder.getCallingUid() == Process.SHELL_UID) {
6795 return;
6796 }
6797 checkCallerIsSystem();
6798 }
6799
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006800 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006801 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006802 return;
6803 }
6804 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
6805 }
6806
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006807 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006808 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006809 return;
6810 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04006811 checkCallerIsSameApp(pkg);
6812 }
6813
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006814 private boolean isCallerAndroid(String callingPkg, int uid) {
6815 return isUidSystemOrPhone(uid) && callingPkg != null
6816 && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg);
6817 }
6818
Brad Stenning8c991ea2018-07-31 13:33:01 -07006819 /**
6820 * Check if the notification is of a category type that is restricted to system use only,
6821 * if so throw SecurityException
6822 */
6823 private void checkRestrictedCategories(final Notification notification) {
6824 try {
6825 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) {
6826 return;
6827 }
6828 } catch (RemoteException re) {
6829 if (DBG) Log.e(TAG, "Unable to confirm if it's safe to skip category "
6830 + "restrictions check thus the check will be done anyway");
6831 }
6832 if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category)
6833 || Notification.CATEGORY_CAR_WARNING.equals(notification.category)
6834 || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) {
6835 checkCallerIsSystem();
6836 }
6837 }
6838
Julia Reynoldsb6634872018-09-25 13:19:53 -04006839 @VisibleForTesting
Julia Reynolds268647a2018-10-25 16:54:27 -04006840 boolean isCallerInstantApp(int callingUid, int userId) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08006841 // System is always allowed to act for ephemeral apps.
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006842 if (isUidSystemOrPhone(callingUid)) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08006843 return false;
6844 }
6845
Chad Brubaker6b68f102017-01-27 13:39:00 -08006846 try {
Julia Reynolds268647a2018-10-25 16:54:27 -04006847 final String[] pkgs = mPackageManager.getPackagesForUid(callingUid);
6848 if (pkgs == null) {
6849 throw new SecurityException("Unknown uid " + callingUid);
6850 }
6851 final String pkg = pkgs[0];
6852 mAppOps.checkPackage(callingUid, pkg);
6853
Julia Reynoldsb6634872018-09-25 13:19:53 -04006854 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId);
Chad Brubaker6b68f102017-01-27 13:39:00 -08006855 if (ai == null) {
6856 throw new SecurityException("Unknown package " + pkg);
6857 }
6858 return ai.isInstantApp();
6859 } catch (RemoteException re) {
Julia Reynolds268647a2018-10-25 16:54:27 -04006860 throw new SecurityException("Unknown uid " + callingUid, re);
Chad Brubaker6b68f102017-01-27 13:39:00 -08006861 }
Chad Brubaker6b68f102017-01-27 13:39:00 -08006862 }
6863
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006864 private void checkCallerIsSameApp(String pkg) {
Julia Reynoldsb6634872018-09-25 13:19:53 -04006865 checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId());
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006866 }
6867
Julia Reynoldsb6634872018-09-25 13:19:53 -04006868 private void checkCallerIsSameApp(String pkg, int uid, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04006869 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006870 ApplicationInfo ai = mPackageManager.getApplicationInfo(
Julia Reynoldsb6634872018-09-25 13:19:53 -04006871 pkg, 0, userId);
Dan Sandler09afc2e2014-07-18 14:29:20 -04006872 if (ai == null) {
6873 throw new SecurityException("Unknown package " + pkg);
6874 }
John Spurlock7340fc82014-04-24 18:50:12 -04006875 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006876 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04006877 + pkg + " which is owned by uid " + ai.uid);
6878 }
6879 } catch (RemoteException re) {
6880 throw new SecurityException("Unknown package " + pkg + "\n" + re);
6881 }
6882 }
6883
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006884 private boolean isCallerSameApp(String pkg) {
6885 try {
6886 checkCallerIsSameApp(pkg);
6887 return true;
6888 } catch (SecurityException e) {
6889 return false;
6890 }
6891 }
6892
Julia Reynoldsb6634872018-09-25 13:19:53 -04006893 private boolean isCallerSameApp(String pkg, int uid, int userId) {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006894 try {
Julia Reynoldsb6634872018-09-25 13:19:53 -04006895 checkCallerIsSameApp(pkg, uid, userId);
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006896 return true;
6897 } catch (SecurityException e) {
6898 return false;
6899 }
6900 }
6901
John Spurlock32fe4c62014-10-02 12:16:02 -04006902 private static String callStateToString(int state) {
6903 switch (state) {
6904 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
6905 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
6906 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
6907 default: return "CALL_STATE_UNKNOWN_" + state;
6908 }
6909 }
6910
6911 private void listenForCallState() {
6912 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
6913 @Override
6914 public void onCallStateChanged(int state, String incomingNumber) {
6915 if (mCallState == state) return;
6916 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
6917 mCallState = state;
6918 }
6919 }, PhoneStateListener.LISTEN_CALL_STATE);
6920 }
6921
Christoph Studer05ad4822014-05-16 14:16:03 +02006922 /**
6923 * Generates a NotificationRankingUpdate from 'sbns', considering only
6924 * notifications visible to the given listener.
6925 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006926 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04006927 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04006928 final int N = mNotificationList.size();
6929 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02006930 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05006931 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04006932 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006933 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006934 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05006935 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006936 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05006937 Bundle overridePeople = new Bundle();
6938 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006939 Bundle showBadge = new Bundle();
Julia Reynolds503ed942017-10-04 16:04:56 -04006940 Bundle userSentiment = new Bundle();
Beverly5a20a5e2018-03-06 15:02:44 -05006941 Bundle hidden = new Bundle();
Gustav Sennton1463d832018-11-06 16:12:48 +00006942 Bundle systemGeneratedSmartActions = new Bundle();
Tony Makc9acf672018-07-20 13:58:24 +02006943 Bundle smartReplies = new Bundle();
Gus Prevas7306b902018-12-11 10:57:06 -05006944 Bundle lastAudiblyAlerted = new Bundle();
Gus Prevas9abc5062018-10-31 16:11:04 -04006945 Bundle noisy = new Bundle();
Julia Reynolds4509ce72019-01-31 13:12:43 -05006946 ArrayList<Boolean> canBubble = new ArrayList<>(N);
Chris Wren333a61c2014-05-28 16:40:57 -04006947 for (int i = 0; i < N; i++) {
6948 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02006949 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006950 continue;
6951 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006952 final String key = record.sbn.getKey();
6953 keys.add(key);
6954 importance.add(record.getImportance());
6955 if (record.getImportanceExplanation() != null) {
6956 explanation.putCharSequence(key, record.getImportanceExplanation());
6957 }
Chris Wren333a61c2014-05-28 16:40:57 -04006958 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006959 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006960
Christoph Studer05ad4822014-05-16 14:16:03 +02006961 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006962 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006963 if (record.getPackageVisibilityOverride()
6964 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006965 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006966 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04006967 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05006968 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05006969 overridePeople.putStringArrayList(key, record.getPeopleOverride());
6970 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05006971 showBadge.putBoolean(key, record.canShowBadge());
Julia Reynolds503ed942017-10-04 16:04:56 -04006972 userSentiment.putInt(key, record.getUserSentiment());
Beverly5a20a5e2018-03-06 15:02:44 -05006973 hidden.putBoolean(key, record.isHidden());
Gustav Sennton1463d832018-11-06 16:12:48 +00006974 systemGeneratedSmartActions.putParcelableArrayList(key,
6975 record.getSystemGeneratedSmartActions());
Tony Makc9acf672018-07-20 13:58:24 +02006976 smartReplies.putCharSequenceArrayList(key, record.getSmartReplies());
Gus Prevas7306b902018-12-11 10:57:06 -05006977 lastAudiblyAlerted.putLong(key, record.getLastAudiblyAlertedMs());
Gus Prevas9abc5062018-10-31 16:11:04 -04006978 noisy.putBoolean(key, record.getSound() != null || record.getVibration() != null);
Julia Reynolds4509ce72019-01-31 13:12:43 -05006979 canBubble.add(record.canBubble());
Christoph Studer05ad4822014-05-16 14:16:03 +02006980 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006981 final int M = keys.size();
6982 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02006983 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05006984 int[] importanceAr = new int[M];
Julia Reynolds4509ce72019-01-31 13:12:43 -05006985 boolean[] canBubbleAr = new boolean[M];
Chris Wrenbdf33762015-12-04 15:50:51 -05006986 for (int i = 0; i < M; i++) {
6987 importanceAr[i] = importance.get(i);
Julia Reynolds4509ce72019-01-31 13:12:43 -05006988 canBubbleAr[i] = canBubble.get(i);
Chris Wrenbdf33762015-12-04 15:50:51 -05006989 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006990 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05006991 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Tony Mak628cb932018-06-19 18:30:41 +01006992 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden,
Julia Reynolds4509ce72019-01-31 13:12:43 -05006993 systemGeneratedSmartActions, smartReplies, lastAudiblyAlerted, noisy,
6994 canBubbleAr);
Christoph Studer05ad4822014-05-16 14:16:03 +02006995 }
6996
Julia Reynoldsda781472017-04-12 09:41:16 -04006997 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006998 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04006999 mCompanionManager = getCompanionManager();
7000 }
7001 // Companion mgr doesn't exist on all device types
7002 if (mCompanionManager == null) {
7003 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007004 }
Julia Reynoldsda781472017-04-12 09:41:16 -04007005 long identity = Binder.clearCallingIdentity();
7006 try {
7007 List<String> associations = mCompanionManager.getAssociations(
7008 info.component.getPackageName(), info.userid);
7009 if (!ArrayUtils.isEmpty(associations)) {
7010 return true;
7011 }
7012 } catch (SecurityException se) {
7013 // Not a privileged listener
7014 } catch (RemoteException re) {
7015 Slog.e(TAG, "Cannot reach companion device service", re);
7016 } catch (Exception e) {
7017 Slog.e(TAG, "Cannot verify listener " + info, e);
7018 } finally {
7019 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007020 }
Julia Reynoldsda781472017-04-12 09:41:16 -04007021 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007022 }
7023
Julia Reynolds727a7282017-04-13 10:54:01 -04007024 protected ICompanionDeviceManager getCompanionManager() {
7025 return ICompanionDeviceManager.Stub.asInterface(
7026 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
7027 }
7028
Christoph Studercef37cf2014-07-25 14:18:17 +02007029 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
7030 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
7031 return false;
7032 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07007033 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02007034 return true;
7035 }
7036
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00007037 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Beverly2be7a052018-03-27 11:37:58 -04007038 final long identity = Binder.clearCallingIdentity();
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007039 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007040 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05007041 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007042 } catch (RemoteException re) {
7043 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00007044 } catch (IllegalArgumentException ex) {
7045 // Package not found.
7046 return false;
Beverly2be7a052018-03-27 11:37:58 -04007047 } finally {
7048 Binder.restoreCallingIdentity(identity);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007049 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007050 }
7051
Kristian Monsen30f59b22018-04-09 10:27:16 +02007052 @VisibleForTesting
7053 boolean canUseManagedServices(String pkg) {
7054 boolean canUseManagedServices = !mActivityManager.isLowRamDevice()
Julia Reynoldse1816412017-10-24 10:39:11 -04007055 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
Kristian Monsen30f59b22018-04-09 10:27:16 +02007056
7057 for (String whitelisted : getContext().getResources().getStringArray(
7058 R.array.config_allowedManagedServicesOnLowRamDevices)) {
7059 if (whitelisted.equals(pkg)) {
7060 canUseManagedServices = true;
7061 }
7062 }
7063
7064 return canUseManagedServices;
Julia Reynoldse1816412017-10-24 10:39:11 -04007065 }
7066
Chris Wren47633422016-01-22 09:56:59 -05007067 private class TrimCache {
7068 StatusBarNotification heavy;
7069 StatusBarNotification sbnClone;
7070 StatusBarNotification sbnCloneLight;
7071
7072 TrimCache(StatusBarNotification sbn) {
7073 heavy = sbn;
7074 }
7075
7076 StatusBarNotification ForListener(ManagedServiceInfo info) {
7077 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
7078 if (sbnCloneLight == null) {
7079 sbnCloneLight = heavy.cloneLight();
7080 }
7081 return sbnCloneLight;
7082 } else {
7083 if (sbnClone == null) {
7084 sbnClone = heavy.clone();
7085 }
7086 return sbnClone;
7087 }
7088 }
7089 }
7090
Julia Reynolds77b2cc92016-11-08 14:41:09 -05007091 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04007092 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05007093
Julia Reynolds7380d872018-01-12 10:28:26 -05007094 public NotificationAssistants(Context context, Object lock, UserProfiles up,
7095 IPackageManager pm) {
7096 super(context, lock, up, pm);
Chris Wren51017d02015-12-15 15:34:46 -05007097 }
7098
7099 @Override
7100 protected Config getConfig() {
7101 Config c = new Config();
Julia Reynolds503ed942017-10-04 16:04:56 -04007102 c.caption = "notification assistant";
Julia Reynolds77b2cc92016-11-08 14:41:09 -05007103 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04007104 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05007105 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
7106 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05007107 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05007108 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05007109 return c;
7110 }
7111
7112 @Override
7113 protected IInterface asInterface(IBinder binder) {
7114 return INotificationListener.Stub.asInterface(binder);
7115 }
7116
7117 @Override
7118 protected boolean checkType(IInterface service) {
7119 return service instanceof INotificationListener;
7120 }
7121
7122 @Override
7123 protected void onServiceAdded(ManagedServiceInfo info) {
7124 mListeners.registerGuestService(info);
7125 }
7126
7127 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04007128 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05007129 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
7130 mListeners.unregisterService(removed.service, removed.userid);
7131 }
Chris Wren47633422016-01-22 09:56:59 -05007132
Julia Reynoldsef934fd2018-02-01 14:39:17 -05007133 @Override
7134 public void onUserUnlocked(int user) {
7135 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04007136 // force rebind the assistant, as it might be keeping its own state in user locked
7137 // storage
7138 rebindServices(true, user);
Julia Reynoldsef934fd2018-02-01 14:39:17 -05007139 }
7140
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04007141 protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
7142 // There should be only one, but it's a list, so while we enforce
7143 // singularity elsewhere, we keep it general here, to avoid surprises.
7144 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7145 ArrayList<String> keys = new ArrayList<>(records.size());
7146 for (NotificationRecord r : records) {
7147 boolean sbnVisible = isVisibleToListener(r.sbn, info)
7148 && info.isSameUser(r.getUserId());
7149 if (sbnVisible) {
7150 keys.add(r.getKey());
7151 }
7152 }
7153
7154 if (!keys.isEmpty()) {
7155 mHandler.post(() -> notifySeen(info, keys));
7156 }
7157 }
7158 }
7159
7160 private void notifySeen(final ManagedServiceInfo info,
7161 final ArrayList<String> keys) {
7162 final INotificationListener assistant = (INotificationListener) info.service;
7163 try {
7164 assistant.onNotificationsSeen(keys);
7165 } catch (RemoteException ex) {
7166 Log.e(TAG, "unable to notify assistant (seen): " + assistant, ex);
7167 }
7168 }
7169
Tony Makeda84a72018-11-19 17:01:32 +00007170 @GuardedBy("mNotificationLock")
7171 private void onNotificationEnqueuedLocked(final NotificationRecord r) {
Chris Wren47633422016-01-22 09:56:59 -05007172 final StatusBarNotification sbn = r.sbn;
Tony Makeda84a72018-11-19 17:01:32 +00007173 notifyAssistantLocked(
7174 sbn,
7175 true /* sameUserOnly */,
7176 (assistant, sbnHolder) -> {
7177 try {
7178 assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel());
7179 } catch (RemoteException ex) {
7180 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
7181 }
7182 });
Chris Wren47633422016-01-22 09:56:59 -05007183 }
7184
Tony Makeda84a72018-11-19 17:01:32 +00007185 @GuardedBy("mNotificationLock")
7186 void notifyAssistantExpansionChangedLocked(
7187 final StatusBarNotification sbn,
7188 final boolean isUserAction,
7189 final boolean isExpanded) {
7190 final String key = sbn.getKey();
7191 notifyAssistantLocked(
7192 sbn,
7193 false /* sameUserOnly */,
7194 (assistant, sbnHolder) -> {
7195 try {
7196 assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded);
7197 } catch (RemoteException ex) {
7198 Log.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
7199 }
7200 });
Chris Wren47633422016-01-22 09:56:59 -05007201 }
7202
Tony Makeda84a72018-11-19 17:01:32 +00007203 @GuardedBy("mNotificationLock")
7204 void notifyAssistantNotificationDirectReplyLocked(
7205 final StatusBarNotification sbn) {
7206 final String key = sbn.getKey();
7207 notifyAssistantLocked(
7208 sbn,
7209 false /* sameUserOnly */,
7210 (assistant, sbnHolder) -> {
7211 try {
7212 assistant.onNotificationDirectReply(key);
7213 } catch (RemoteException ex) {
7214 Log.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
7215 }
7216 });
7217 }
7218
Tony Mak29996702018-11-26 16:23:34 +00007219 @GuardedBy("mNotificationLock")
7220 void notifyAssistantSuggestedReplySent(
7221 final StatusBarNotification sbn, CharSequence reply, boolean generatedByAssistant) {
7222 final String key = sbn.getKey();
7223 notifyAssistantLocked(
7224 sbn,
7225 false /* sameUserOnly */,
7226 (assistant, sbnHolder) -> {
7227 try {
7228 assistant.onSuggestedReplySent(
7229 key,
7230 reply,
7231 generatedByAssistant
7232 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
7233 : NotificationAssistantService.SOURCE_FROM_APP);
7234 } catch (RemoteException ex) {
7235 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
7236 }
7237 });
7238 }
7239
Tony Mak7d4b3a52018-11-27 17:29:36 +00007240 @GuardedBy("mNotificationLock")
7241 void notifyAssistantActionClicked(
7242 final StatusBarNotification sbn, int actionIndex, Notification.Action action,
7243 boolean generatedByAssistant) {
7244 final String key = sbn.getKey();
7245 notifyAssistantLocked(
7246 sbn,
7247 false /* sameUserOnly */,
7248 (assistant, sbnHolder) -> {
7249 try {
7250 assistant.onActionClicked(
7251 key,
7252 action,
7253 generatedByAssistant
7254 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
7255 : NotificationAssistantService.SOURCE_FROM_APP);
7256 } catch (RemoteException ex) {
7257 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
7258 }
7259 });
7260 }
Tony Makeda84a72018-11-19 17:01:32 +00007261
Julia Reynolds79672302017-01-12 08:30:16 -05007262 /**
7263 * asynchronously notify the assistant that a notification has been snoozed until a
7264 * context
7265 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007266 @GuardedBy("mNotificationLock")
Tony Makeda84a72018-11-19 17:01:32 +00007267 private void notifyAssistantSnoozedLocked(
7268 final StatusBarNotification sbn, final String snoozeCriterionId) {
7269 notifyAssistantLocked(
7270 sbn,
7271 false /* sameUserOnly */,
7272 (assistant, sbnHolder) -> {
Julia Reynolds79672302017-01-12 08:30:16 -05007273 try {
7274 assistant.onNotificationSnoozedUntilContext(
7275 sbnHolder, snoozeCriterionId);
7276 } catch (RemoteException ex) {
7277 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
7278 }
Tony Makeda84a72018-11-19 17:01:32 +00007279 });
7280 }
7281
7282 /**
7283 * Notifies the assistant something about the specified notification, only assistant
7284 * that is visible to the notification will be notified.
7285 *
7286 * @param sbn the notification object that the update is about.
7287 * @param sameUserOnly should the update be sent to the assistant in the same user only.
7288 * @param callback the callback that provides the assistant to be notified, executed
7289 * in WorkerHandler.
7290 */
7291 @GuardedBy("mNotificationLock")
7292 private void notifyAssistantLocked(
7293 final StatusBarNotification sbn,
7294 boolean sameUserOnly,
7295 BiConsumer<INotificationListener, StatusBarNotificationHolder> callback) {
7296 TrimCache trimCache = new TrimCache(sbn);
7297 // There should be only one, but it's a list, so while we enforce
7298 // singularity elsewhere, we keep it general here, to avoid surprises.
7299 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7300 boolean sbnVisible = isVisibleToListener(sbn, info)
7301 && (!sameUserOnly || info.isSameUser(sbn.getUserId()));
7302 if (!sbnVisible) {
7303 continue;
7304 }
7305 final INotificationListener assistant = (INotificationListener) info.service;
7306 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
7307 final StatusBarNotificationHolder sbnHolder =
7308 new StatusBarNotificationHolder(sbnToPost);
7309 mHandler.post(() -> callback.accept(assistant, sbnHolder));
Julia Reynolds79672302017-01-12 08:30:16 -05007310 }
7311 }
7312
Chris Wren47633422016-01-22 09:56:59 -05007313 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04007314 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05007315 }
Julia Reynolds7380d872018-01-12 10:28:26 -05007316
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04007317 protected void ensureAssistant() {
7318 final List<UserInfo> activeUsers = mUm.getUsers(true);
7319 for (UserInfo userInfo : activeUsers) {
7320 int userId = userInfo.getUserHandle().getIdentifier();
7321 if (getAllowedPackages(userId).isEmpty()) {
7322 Slog.d(TAG, "Approving default notification assistant for user " + userId);
7323 readDefaultAssistant(userId);
7324 }
Julia Reynolds7380d872018-01-12 10:28:26 -05007325 }
7326 }
Fabian Kozynskid9425662019-01-29 13:08:30 -05007327
7328 @Override
7329 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
7330 boolean isPrimary, boolean enabled) {
7331 // Ensures that only one component is enabled at a time
7332 if (enabled) {
7333 List<ComponentName> allowedComponents = getAllowedComponents(userId);
7334 if (!allowedComponents.isEmpty()) {
7335 ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents);
7336 if (currentComponent.flattenToString().equals(pkgOrComponent)) return;
7337 try {
7338 getBinderService().setNotificationAssistantAccessGrantedForUser(
7339 currentComponent, userId, false);
7340 } catch (RemoteException e) {
7341 e.rethrowFromSystemServer();
7342 }
7343 }
7344 }
7345 super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled);
7346 }
Chris Wren51017d02015-12-15 15:34:46 -05007347 }
7348
John Spurlock7340fc82014-04-24 18:50:12 -04007349 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04007350 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04007351
Christoph Studerb82bc782014-08-20 14:29:43 +02007352 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
7353
Julia Reynoldsb852e562017-06-06 16:14:18 -04007354 public NotificationListeners(IPackageManager pm) {
7355 super(getContext(), mNotificationLock, mUserProfiles, pm);
7356
John Spurlock7340fc82014-04-24 18:50:12 -04007357 }
7358
7359 @Override
Amith Yamasanie5bfeee2018-09-05 18:52:35 -07007360 protected int getBindFlags() {
7361 // Most of the same flags as the base, but also add BIND_ADJUST_BELOW_PERCEPTIBLE
7362 // because too many 3P apps could be kept in memory as notification listeners and
7363 // cause extreme memory pressure.
7364 // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation.
7365 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
7366 | BIND_ADJUST_BELOW_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
7367 }
7368
7369 @Override
John Spurlock7340fc82014-04-24 18:50:12 -04007370 protected Config getConfig() {
7371 Config c = new Config();
7372 c.caption = "notification listener";
7373 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04007374 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04007375 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
7376 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
7377 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
7378 c.clientLabel = R.string.notification_listener_binding_label;
7379 return c;
7380 }
7381
7382 @Override
7383 protected IInterface asInterface(IBinder binder) {
7384 return INotificationListener.Stub.asInterface(binder);
7385 }
7386
7387 @Override
Chris Wren51017d02015-12-15 15:34:46 -05007388 protected boolean checkType(IInterface service) {
7389 return service instanceof INotificationListener;
7390 }
7391
7392 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04007393 public void onServiceAdded(ManagedServiceInfo info) {
7394 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04007395 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007396 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04007397 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02007398 }
John Spurlock7340fc82014-04-24 18:50:12 -04007399 try {
Chris Wren333a61c2014-05-28 16:40:57 -04007400 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04007401 } catch (RemoteException e) {
7402 // we tried
7403 }
7404 }
7405
John Spurlock1fa865f2014-07-21 14:56:39 -04007406 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04007407 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04007408 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07007409 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04007410 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01007411 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04007412 }
Christoph Studerb82bc782014-08-20 14:29:43 +02007413 mLightTrimListeners.remove(removed);
7414 }
7415
Julia Reynolds88860ce2017-06-01 16:55:49 -04007416 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02007417 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
7418 if (trim == TRIM_LIGHT) {
7419 mLightTrimListeners.add(info);
7420 } else {
7421 mLightTrimListeners.remove(info);
7422 }
7423 }
7424
7425 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
7426 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04007427 }
7428
Julia Reynolds12ad7ca2019-01-28 09:29:16 -05007429 public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
7430 for (final ManagedServiceInfo info : getServices()) {
7431 mHandler.post(() -> {
7432 final INotificationListener listener = (INotificationListener) info.service;
7433 try {
7434 listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
7435 } catch (RemoteException ex) {
7436 Log.e(TAG, "unable to notify listener "
7437 + "(hideSilentStatusIcons): " + listener, ex);
7438 }
7439 });
7440 }
7441 }
7442
John Spurlock7340fc82014-04-24 18:50:12 -04007443 /**
7444 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02007445 *
7446 * <p>
7447 * Also takes care of removing a notification that has been visible to a listener before,
7448 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04007449 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007450 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007451 public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
7452 notifyPostedLocked(r, old, true);
Beverly5a20a5e2018-03-06 15:02:44 -05007453 }
7454
7455 /**
7456 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
7457 * targetting <= O_MR1
7458 */
7459 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007460 private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
Beverly5a20a5e2018-03-06 15:02:44 -05007461 boolean notifyAllListeners) {
Christoph Studerb82bc782014-08-20 14:29:43 +02007462 // Lazily initialized snapshots of the notification.
Julia Reynoldse0d711f2017-09-01 08:50:47 -04007463 StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007464 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Chris Wren47633422016-01-22 09:56:59 -05007465 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02007466
Julia Reynolds00314d92017-04-14 10:01:24 -04007467 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02007468 boolean sbnVisible = isVisibleToListener(sbn, info);
7469 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
7470 // This notification hasn't been and still isn't visible -> ignore.
7471 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02007472 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04007473 }
Beverly5a20a5e2018-03-06 15:02:44 -05007474 // If the notification is hidden, don't notifyPosted listeners targeting < P.
7475 // Instead, those listeners will receive notifyPosted when the notification is
7476 // unhidden.
7477 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
7478 continue;
7479 }
7480
7481 // If we shouldn't notify all listeners, this means the hidden state of
7482 // a notification was changed. Don't notifyPosted listeners targeting >= P.
7483 // Instead, those listeners will receive notifyRankingUpdate.
7484 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
7485 continue;
7486 }
7487
Chris Wren333a61c2014-05-28 16:40:57 -04007488 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02007489
7490 // This notification became invisible -> remove the old one.
7491 if (oldSbnVisible && !sbnVisible) {
7492 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
7493 mHandler.post(new Runnable() {
7494 @Override
7495 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04007496 notifyRemoved(
7497 info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02007498 }
7499 });
Christoph Studer05ad4822014-05-16 14:16:03 +02007500 continue;
7501 }
Christoph Studercef37cf2014-07-25 14:18:17 +02007502
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007503 // Grant access before listener is notified
7504 final int targetUserId = (info.userid == UserHandle.USER_ALL)
7505 ? UserHandle.USER_SYSTEM : info.userid;
7506 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04007507
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007508 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02007509 mHandler.post(new Runnable() {
7510 @Override
7511 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02007512 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02007513 }
7514 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00007515 }
7516 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00007517
John Spurlock7340fc82014-04-24 18:50:12 -04007518 /**
7519 * asynchronously notify all listeners about a removed notification
7520 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007521 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05007522 public void notifyRemovedLocked(NotificationRecord r, int reason,
Julia Reynolds503ed942017-10-04 16:04:56 -04007523 NotificationStats notificationStats) {
Beverly5a20a5e2018-03-06 15:02:44 -05007524 final StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007525
John Spurlock7340fc82014-04-24 18:50:12 -04007526 // make a copy in case changes are made to the underlying Notification object
7527 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
7528 // notification
7529 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04007530 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02007531 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02007532 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04007533 }
Beverly5a20a5e2018-03-06 15:02:44 -05007534
7535 // don't notifyRemoved for listeners targeting < P
7536 // if not for reason package suspended
7537 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
7538 && info.targetSdkVersion < Build.VERSION_CODES.P) {
7539 continue;
7540 }
7541
7542 // don't notifyRemoved for listeners targeting >= P
7543 // if the reason is package suspended
7544 if (reason == REASON_PACKAGE_SUSPENDED
7545 && info.targetSdkVersion >= Build.VERSION_CODES.P) {
7546 continue;
7547 }
7548
Julia Reynolds503ed942017-10-04 16:04:56 -04007549 // Only assistants can get stats
7550 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
7551 ? notificationStats : null;
Chris Wren333a61c2014-05-28 16:40:57 -04007552 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02007553 mHandler.post(new Runnable() {
7554 @Override
7555 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04007556 notifyRemoved(info, sbnLight, update, stats, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02007557 }
7558 });
Chris Wrenf9536642014-04-17 10:01:54 -04007559 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007560
7561 // Revoke access after all listeners have been updated
7562 mHandler.post(() -> {
7563 updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM);
7564 });
Chris Wrenf9536642014-04-17 10:01:54 -04007565 }
7566
7567 /**
Beverly5a20a5e2018-03-06 15:02:44 -05007568 * Asynchronously notify all listeners about a reordering of notifications
7569 * unless changedHiddenNotifications is populated.
7570 * If changedHiddenNotifications is populated, there was a change in the hidden state
7571 * of the notifications. In this case, we only send updates to listeners that
7572 * target >= P.
Chris Wrenf9536642014-04-17 10:01:54 -04007573 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007574 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05007575 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
7576 boolean isHiddenRankingUpdate = changedHiddenNotifications != null
7577 && changedHiddenNotifications.size() > 0;
7578
Julia Reynolds00314d92017-04-14 10:01:24 -04007579 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02007580 if (!serviceInfo.isEnabledForCurrentProfiles()) {
7581 continue;
7582 }
Beverly5a20a5e2018-03-06 15:02:44 -05007583
7584 boolean notifyThisListener = false;
7585 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
7586 Build.VERSION_CODES.P) {
7587 for (NotificationRecord rec : changedHiddenNotifications) {
7588 if (isVisibleToListener(rec.sbn, serviceInfo)) {
7589 notifyThisListener = true;
7590 break;
7591 }
John Spurlock7340fc82014-04-24 18:50:12 -04007592 }
Beverly5a20a5e2018-03-06 15:02:44 -05007593 }
7594
7595 if (notifyThisListener || !isHiddenRankingUpdate) {
7596 final NotificationRankingUpdate update = makeRankingUpdateLocked(
7597 serviceInfo);
7598
7599 mHandler.post(new Runnable() {
7600 @Override
7601 public void run() {
7602 notifyRankingUpdate(serviceInfo, update);
7603 }
7604 });
7605 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007606 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007607 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007608
Julia Reynolds88860ce2017-06-01 16:55:49 -04007609 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04007610 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04007611 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04007612 if (!serviceInfo.isEnabledForCurrentProfiles()) {
7613 continue;
7614 }
7615 mHandler.post(new Runnable() {
7616 @Override
7617 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04007618 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04007619 }
7620 });
7621 }
7622 }
7623
Beverly5a20a5e2018-03-06 15:02:44 -05007624 /**
7625 * asynchronously notify relevant listeners their notification is hidden
7626 * NotificationListenerServices that target P+:
7627 * NotificationListenerService#notifyRankingUpdateLocked()
7628 * NotificationListenerServices that target <= P:
7629 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
7630 */
7631 @GuardedBy("mNotificationLock")
7632 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
7633 if (changedNotifications == null || changedNotifications.size() == 0) {
7634 return;
7635 }
7636
7637 notifyRankingUpdateLocked(changedNotifications);
7638
7639 // for listeners that target < P, notifyRemoveLocked
7640 int numChangedNotifications = changedNotifications.size();
7641 for (int i = 0; i < numChangedNotifications; i++) {
7642 NotificationRecord rec = changedNotifications.get(i);
7643 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
7644 }
7645 }
7646
7647 /**
7648 * asynchronously notify relevant listeners their notification is unhidden
7649 * NotificationListenerServices that target P+:
7650 * NotificationListenerService#notifyRankingUpdateLocked()
7651 * NotificationListenerServices that target <= P:
7652 * NotificationListeners#notifyPostedLocked()
7653 */
7654 @GuardedBy("mNotificationLock")
7655 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
7656 if (changedNotifications == null || changedNotifications.size() == 0) {
7657 return;
7658 }
7659
7660 notifyRankingUpdateLocked(changedNotifications);
7661
7662 // for listeners that target < P, notifyPostedLocked
7663 int numChangedNotifications = changedNotifications.size();
7664 for (int i = 0; i < numChangedNotifications; i++) {
7665 NotificationRecord rec = changedNotifications.get(i);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007666 mListeners.notifyPostedLocked(rec, rec, false);
Beverly5a20a5e2018-03-06 15:02:44 -05007667 }
7668 }
7669
Christoph Studer85a384b2014-08-27 20:16:15 +02007670 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04007671 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02007672 if (!serviceInfo.isEnabledForCurrentProfiles()) {
7673 continue;
7674 }
7675 mHandler.post(new Runnable() {
7676 @Override
7677 public void run() {
7678 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
7679 }
7680 });
7681 }
7682 }
7683
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007684 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007685 final NotificationChannel channel, final int modificationType) {
7686 if (channel == null) {
7687 return;
7688 }
7689 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04007690 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007691 continue;
7692 }
Julia Reynolds018aa622017-04-20 11:31:30 -04007693
Eugene Suslaa25d17f2017-08-24 11:28:08 -07007694 BackgroundThread.getHandler().post(() -> {
7695 if (hasCompanionDevice(serviceInfo)) {
7696 notifyNotificationChannelChanged(
7697 serviceInfo, pkg, user, channel, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04007698 }
7699 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007700 }
7701 }
7702
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007703 protected void notifyNotificationChannelGroupChanged(
7704 final String pkg, final UserHandle user, final NotificationChannelGroup group,
7705 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007706 if (group == null) {
7707 return;
7708 }
7709 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04007710 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007711 continue;
7712 }
Julia Reynolds018aa622017-04-20 11:31:30 -04007713
Eugene Suslaa25d17f2017-08-24 11:28:08 -07007714 BackgroundThread.getHandler().post(() -> {
7715 if (hasCompanionDevice(serviceInfo)) {
7716 notifyNotificationChannelGroupChanged(
7717 serviceInfo, pkg, user, group, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04007718 }
7719 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007720 }
7721 }
7722
Christoph Studercef37cf2014-07-25 14:18:17 +02007723 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02007724 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04007725 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007726 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04007727 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07007728 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04007729 } catch (RemoteException ex) {
7730 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
7731 }
7732 }
7733
Christoph Studercef37cf2014-07-25 14:18:17 +02007734 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds503ed942017-10-04 16:04:56 -04007735 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04007736 if (!info.enabledAndUserMatches(sbn.getUserId())) {
7737 return;
7738 }
Christoph Studer05ad4822014-05-16 14:16:03 +02007739 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007740 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04007741 try {
Julia Reynolds503ed942017-10-04 16:04:56 -04007742 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04007743 } catch (RemoteException ex) {
7744 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04007745 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007746 }
Chris Wrenf9536642014-04-17 10:01:54 -04007747
Christoph Studer05ad4822014-05-16 14:16:03 +02007748 private void notifyRankingUpdate(ManagedServiceInfo info,
7749 NotificationRankingUpdate rankingUpdate) {
7750 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04007751 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02007752 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04007753 } catch (RemoteException ex) {
7754 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
7755 }
7756 }
John Spurlock1fa865f2014-07-21 14:56:39 -04007757
John Spurlockd8afe3c2014-08-01 14:04:07 -04007758 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04007759 final INotificationListener listener = (INotificationListener) info.service;
7760 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04007761 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04007762 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04007763 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04007764 }
7765 }
Justin Koh38156c52014-06-04 13:57:49 -07007766
Christoph Studer85a384b2014-08-27 20:16:15 +02007767 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
7768 int interruptionFilter) {
7769 final INotificationListener listener = (INotificationListener) info.service;
7770 try {
7771 listener.onInterruptionFilterChanged(interruptionFilter);
7772 } catch (RemoteException ex) {
7773 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
7774 }
7775 }
7776
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007777 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007778 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007779 final int modificationType) {
7780 final INotificationListener listener = (INotificationListener) info.service;
7781 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007782 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007783 } catch (RemoteException ex) {
7784 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
7785 }
7786 }
7787
7788 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007789 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007790 final int modificationType) {
7791 final INotificationListener listener = (INotificationListener) info.service;
7792 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007793 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007794 } catch (RemoteException ex) {
7795 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
7796 }
7797 }
7798
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007799 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07007800 if (packageName == null) {
7801 return false;
7802 }
7803 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007804 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04007805 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07007806 if (packageName.equals(serviceInfo.component.getPackageName())) {
7807 return true;
7808 }
7809 }
7810 }
7811 return false;
7812 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007813 }
John Spurlock25e2d242014-06-27 13:58:23 -04007814
7815 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04007816 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04007817 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04007818 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04007819 public long since;
7820 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04007821 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05007822 public boolean proto = false;
Vishnu Naire3e4d252018-03-01 11:26:57 -08007823 public boolean criticalPriority = false;
7824 public boolean normalPriority = false;
John Spurlock25e2d242014-06-27 13:58:23 -04007825
Kweku Adams887f09c2017-11-13 17:12:20 -08007826 @NonNull
John Spurlock25e2d242014-06-27 13:58:23 -04007827 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04007828 final DumpFilter filter = new DumpFilter();
7829 for (int ai = 0; ai < args.length; ai++) {
7830 final String a = args[ai];
Kweku Adams62b42242017-09-25 12:54:02 -07007831 if ("--proto".equals(a)) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05007832 filter.proto = true;
Kweku Adams62b42242017-09-25 12:54:02 -07007833 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
Dan Sandlera1770312015-07-10 13:59:29 -04007834 filter.redact = false;
7835 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
7836 if (ai < args.length-1) {
7837 ai++;
7838 filter.pkgFilter = args[ai].trim().toLowerCase();
7839 if (filter.pkgFilter.isEmpty()) {
7840 filter.pkgFilter = null;
7841 } else {
7842 filter.filtered = true;
7843 }
7844 }
7845 } else if ("--zen".equals(a) || "zen".equals(a)) {
7846 filter.filtered = true;
7847 filter.zen = true;
7848 } else if ("--stats".equals(a)) {
7849 filter.stats = true;
7850 if (ai < args.length-1) {
7851 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01007852 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04007853 } else {
7854 filter.since = 0;
7855 }
Vishnu Naire3e4d252018-03-01 11:26:57 -08007856 } else if (PRIORITY_ARG.equals(a)) {
7857 // Bugreport will call the service twice with priority arguments, first to dump
7858 // critical sections and then non critical ones. Set approriate filters
7859 // to generate the desired data.
7860 if (ai < args.length - 1) {
7861 ai++;
7862 switch (args[ai]) {
7863 case PRIORITY_ARG_CRITICAL:
7864 filter.criticalPriority = true;
7865 break;
7866 case PRIORITY_ARG_NORMAL:
7867 filter.normalPriority = true;
7868 break;
7869 }
7870 }
Dan Sandlera1770312015-07-10 13:59:29 -04007871 }
John Spurlock25e2d242014-06-27 13:58:23 -04007872 }
Dan Sandlera1770312015-07-10 13:59:29 -04007873 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04007874 }
7875
7876 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04007877 if (!filtered) return true;
7878 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04007879 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04007880 }
7881
7882 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04007883 if (!filtered) return true;
7884 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04007885 }
7886
7887 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04007888 if (!filtered) return true;
7889 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04007890 }
7891
7892 @Override
7893 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04007894 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04007895 }
7896 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07007897
Beverly5a20a5e2018-03-06 15:02:44 -05007898 @VisibleForTesting
7899 protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
7900 // only use for testing: mimic receive broadcast that package is (un)suspended
7901 // but does not actually (un)suspend the package
7902 final Bundle extras = new Bundle();
7903 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
7904 new String[]{pkg});
7905
7906 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
Beverly3c707b42018-09-14 09:49:07 -04007907 : Intent.ACTION_PACKAGES_UNSUSPENDED;
Beverly5a20a5e2018-03-06 15:02:44 -05007908 final Intent intent = new Intent(action);
7909 intent.putExtras(extras);
7910
7911 mPackageIntentReceiver.onReceive(getContext(), intent);
7912 }
7913
Julia Reynolds0e5a3432019-01-17 09:40:46 -05007914 @VisibleForTesting
7915 protected void simulatePackageDistractionBroadcast(int flag, String[] pkgs) {
7916 // only use for testing: mimic receive broadcast that package is (un)distracting
7917 // but does not actually register that info with packagemanager
7918 final Bundle extras = new Bundle();
7919 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs);
7920 extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag);
7921
7922 final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
7923 intent.putExtras(extras);
7924
7925 mPackageIntentReceiver.onReceive(getContext(), intent);
7926 }
7927
Griff Hazen84a00ea2014-09-02 17:10:47 -07007928 /**
7929 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
7930 * binder without sending large amounts of data over a oneway transaction.
7931 */
7932 private static final class StatusBarNotificationHolder
7933 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07007934 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007935
7936 public StatusBarNotificationHolder(StatusBarNotification value) {
7937 mValue = value;
7938 }
7939
Griff Hazene9aac5f2014-09-05 20:04:09 -07007940 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07007941 @Override
7942 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07007943 StatusBarNotification value = mValue;
7944 mValue = null;
7945 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007946 }
7947 }
John Spurlock7c74f782015-06-04 13:01:42 -04007948
Zimuzob3b9c262018-10-31 11:54:20 +00007949 private void writeSecureNotificationsPolicy(XmlSerializer out) throws IOException {
7950 out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
7951 out.attribute(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
7952 Boolean.toString(mLockScreenAllowSecureNotifications));
7953 out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
7954 }
7955
7956 private static boolean safeBoolean(String val, boolean defValue) {
7957 if (TextUtils.isEmpty(val)) return defValue;
7958 return Boolean.parseBoolean(val);
7959 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007960}