blob: f487200e40c13b8d11350745eba1c91aa5fa3b58 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Adam Lesinski182f73f2013-12-05 16:48:06 -080017package com.android.server.notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Julia Reynoldse5c60452018-04-30 14:41:36 -040019import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
Julia Reynoldsfc9767b2018-01-22 17:45:16 -050020import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050021import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
22import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
Julia Reynolds8617e4e2017-09-18 16:52:37 -040023import static android.app.NotificationManager.IMPORTANCE_LOW;
Julia Reynolds7c96b582017-05-25 12:35:36 -040024import static android.app.NotificationManager.IMPORTANCE_MIN;
Julia Reynolds85769912016-10-25 09:08:57 -040025import static android.app.NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -050026import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
27import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
28import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
29import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
30import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
31import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
32import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
33import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
34import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
35import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -050036import static android.content.pm.PackageManager.FEATURE_LEANBACK;
37import static android.content.pm.PackageManager.FEATURE_TELEVISION;
Julia Reynolds4db59552017-06-30 13:34:01 -040038import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Vishnu Naire3e4d252018-03-01 11:26:57 -080039import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
40import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
Julia Reynolds88a879f2017-07-26 17:06:46 -040041import static android.os.UserHandle.USER_NULL;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040042import static android.os.UserHandle.USER_SYSTEM;
Julia Reynolds73ed76b2017-04-04 17:04:38 -040043import static android.service.notification.NotificationListenerService
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050044 .HINT_HOST_DISABLE_CALL_EFFECTS;
45import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
46import static android.service.notification.NotificationListenerService
47 .HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
48import static android.service.notification.NotificationListenerService
Julia Reynolds73ed76b2017-04-04 17:04:38 -040049 .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
50import static android.service.notification.NotificationListenerService
51 .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
52import static android.service.notification.NotificationListenerService
53 .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050054import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
55import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040056import static android.service.notification.NotificationListenerService.REASON_CANCEL;
57import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050058import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040059import static android.service.notification.NotificationListenerService.REASON_CLICK;
60import static android.service.notification.NotificationListenerService.REASON_ERROR;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050061import static android.service.notification.NotificationListenerService
62 .REASON_GROUP_SUMMARY_CANCELED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050063import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
64import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
65import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
66import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
67import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
68import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
69import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
Julia Reynolds2a128742016-11-28 14:29:25 -050070import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050071import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
72import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
Christoph Studerb82bc782014-08-20 14:29:43 +020073import static android.service.notification.NotificationListenerService.TRIM_FULL;
74import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
Wale Ogunwaleac2561e2016-11-01 15:43:46 -070075import static android.view.Display.DEFAULT_DISPLAY;
76import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
svetoslavganov75986cf2009-05-14 22:28:01 -070077
Vishnu Naire3e4d252018-03-01 11:26:57 -080078import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
79import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
80import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
81
Chris Wren51017d02015-12-15 15:34:46 -050082import android.Manifest;
Julia Reynoldsa78cdff2017-04-26 10:19:25 -040083import android.annotation.NonNull;
Wei Liu97e56662016-03-04 10:52:33 -080084import android.annotation.Nullable;
Dianne Hackborn41203752012-08-31 14:05:51 -070085import android.app.ActivityManager;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070086import android.app.ActivityManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -050087import android.app.AlarmManager;
John Spurlock7340fc82014-04-24 18:50:12 -040088import android.app.AppGlobals;
Daniel Sandler4a900ac2013-01-30 14:04:10 -050089import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040090import android.app.AutomaticZenRule;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.app.IActivityManager;
92import android.app.INotificationManager;
93import android.app.ITransientNotification;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070094import android.app.IUriGrantsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.app.Notification;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040096import android.app.NotificationChannel;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050097import android.app.NotificationChannelGroup;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -050098import android.app.NotificationManager;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050099import android.app.NotificationManager.Policy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100import android.app.PendingIntent;
101import android.app.StatusBarManager;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700102import android.app.UriGrantsManager;
Jason Parks50322ff2018-03-27 10:23:33 -0500103import android.app.admin.DeviceAdminInfo;
104import android.app.admin.DevicePolicyManagerInternal;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500105import android.app.backup.BackupManager;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700106import android.app.usage.UsageEvents;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700107import android.app.usage.UsageStatsManagerInternal;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400108import android.companion.ICompanionDeviceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import android.content.BroadcastReceiver;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700110import android.content.ComponentName;
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400111import android.content.ContentProvider;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700112import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113import android.content.Context;
114import android.content.Intent;
115import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -0400116import android.content.pm.ApplicationInfo;
Kenny Guy70058402014-10-28 20:45:06 +0000117import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118import android.content.pm.PackageManager;
119import android.content.pm.PackageManager.NameNotFoundException;
Christoph Studercee44ba2014-05-20 18:36:43 +0200120import android.content.pm.ParceledListSlice;
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400121import android.content.pm.UserInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700123import android.database.ContentObserver;
Beverly5d463b62017-07-26 14:13:40 -0400124import android.media.AudioAttributes;
svetoslavganov75986cf2009-05-14 22:28:01 -0700125import android.media.AudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500126import android.media.AudioManagerInternal;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700127import android.media.IRingtonePlayer;
Kenny Guy23991102018-04-05 21:18:38 +0100128import android.metrics.LogMaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130import android.os.Binder;
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -0400131import android.os.Build;
John Spurlock2b122f42014-08-27 16:29:47 -0400132import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -0400133import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134import android.os.Handler;
Chris Wrenf9536642014-04-17 10:01:54 -0400135import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136import android.os.IBinder;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800137import android.os.IDeviceIdleController;
John Spurlock7340fc82014-04-24 18:50:12 -0400138import android.os.IInterface;
Chris Wrenf9536642014-04-17 10:01:54 -0400139import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700141import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -0700142import android.os.RemoteException;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400143import android.os.ResultReceiver;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400144import android.os.ServiceManager;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400145import android.os.ShellCallback;
146import android.os.ShellCommand;
Chris Wrenc8673a82016-05-17 17:11:29 -0400147import android.os.SystemClock;
Selim Cinekb5605e52015-02-20 18:21:41 +0100148import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700149import android.os.UserHandle;
Michael Wright71216972017-01-31 18:33:54 +0000150import android.os.VibrationEffect;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500151import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152import android.provider.Settings;
Julia Reynoldse46bb372016-03-17 11:05:58 -0400153import android.service.notification.Adjustment;
Chris Wren333a61c2014-05-28 16:40:57 -0400154import android.service.notification.Condition;
John Spurlock7340fc82014-04-24 18:50:12 -0400155import android.service.notification.IConditionProvider;
Chris Wren333a61c2014-05-28 16:40:57 -0400156import android.service.notification.INotificationListener;
Griff Hazen84a00ea2014-09-02 17:10:47 -0700157import android.service.notification.IStatusBarNotificationHolder;
Kweku Adams93304b62017-09-20 17:03:00 -0700158import android.service.notification.ListenersDisablingEffectsProto;
Julia Reynolds77b2cc92016-11-08 14:41:09 -0500159import android.service.notification.NotificationAssistantService;
John Spurlock7340fc82014-04-24 18:50:12 -0400160import android.service.notification.NotificationListenerService;
Christoph Studer05ad4822014-05-16 14:16:03 +0200161import android.service.notification.NotificationRankingUpdate;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500162import android.service.notification.NotificationRecordProto;
163import android.service.notification.NotificationServiceDumpProto;
Julia Reynolds503ed942017-10-04 16:04:56 -0400164import android.service.notification.NotificationStats;
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500165import android.service.notification.NotifyingApp;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500166import android.service.notification.SnoozeCriterion;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700167import android.service.notification.StatusBarNotification;
John Spurlock056c5192014-04-20 21:52:01 -0400168import android.service.notification.ZenModeConfig;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500169import android.service.notification.ZenModeProto;
John Spurlock32fe4c62014-10-02 12:16:02 -0400170import android.telephony.PhoneStateListener;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500171import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -0700172import android.text.TextUtils;
John Spurlocka4294292014-03-24 18:02:32 -0400173import android.util.ArrayMap;
John Spurlock1fa865f2014-07-21 14:56:39 -0400174import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700175import android.util.AtomicFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -0800177import android.util.Slog;
Bryce Lee7219ada2016-04-08 10:54:23 -0700178import android.util.SparseArray;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400179import android.util.Xml;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500180import android.util.proto.ProtoOutputStream;
svetoslavganov75986cf2009-05-14 22:28:01 -0700181import android.view.accessibility.AccessibilityEvent;
182import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183import android.widget.Toast;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000184
Scott Greenwald9a05b312013-06-28 00:37:54 -0400185import com.android.internal.R;
Julia Reynolds88860ce2017-06-01 16:55:49 -0400186import com.android.internal.annotations.GuardedBy;
Chris Wren93bb8b82016-03-29 14:35:05 -0400187import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -0500188import com.android.internal.logging.MetricsLogger;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500189import com.android.internal.logging.nano.MetricsProto;
Chris Wren9eb5e102017-01-26 13:15:06 -0500190import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Beverly70dcd002018-03-29 17:09:16 -0400191import com.android.internal.notification.SystemNotificationChannels;
Eugene Suslaa25d17f2017-08-24 11:28:08 -0700192import com.android.internal.os.BackgroundThread;
Chris Wrend1dbc922015-06-19 17:51:16 -0400193import com.android.internal.statusbar.NotificationVisibility;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400194import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600195import com.android.internal.util.DumpUtils;
John Spurlock056c5192014-04-20 21:52:01 -0400196import com.android.internal.util.FastXmlSerializer;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400197import com.android.internal.util.Preconditions;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400198import com.android.internal.util.XmlUtils;
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700199import com.android.server.DeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800200import com.android.server.EventLogTags;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700201import com.android.server.LocalServices;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800202import com.android.server.SystemService;
203import com.android.server.lights.Light;
204import com.android.server.lights.LightsManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400205import com.android.server.notification.ManagedServices.ManagedServiceInfo;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500206import com.android.server.notification.ManagedServices.UserProfiles;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700207import com.android.server.policy.PhoneWindowManager;
John Spurlockb408e8e2014-04-23 21:12:45 -0400208import com.android.server.statusbar.StatusBarManagerInternal;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700209import com.android.server.uri.UriGrantsManagerInternal;
Adrian Roose99bc052017-11-20 17:55:31 +0100210import com.android.server.wm.WindowManagerInternal;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800211
John Spurlockb408e8e2014-04-23 21:12:45 -0400212import libcore.io.IoUtils;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000213
Chris Wrene4b38802015-07-07 15:54:19 -0400214import org.json.JSONException;
215import org.json.JSONObject;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700216import org.xmlpull.v1.XmlPullParser;
217import org.xmlpull.v1.XmlPullParserException;
John Spurlock056c5192014-04-20 21:52:01 -0400218import org.xmlpull.v1.XmlSerializer;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700219
John Spurlock35ef0a62015-05-28 11:24:10 -0400220import java.io.ByteArrayInputStream;
221import java.io.ByteArrayOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400222import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400224import java.io.FileNotFoundException;
John Spurlock056c5192014-04-20 21:52:01 -0400225import java.io.FileOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400226import java.io.IOException;
John Spurlock35ef0a62015-05-28 11:24:10 -0400227import java.io.InputStream;
228import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100230import java.nio.charset.StandardCharsets;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500231import java.util.ArrayDeque;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232import java.util.ArrayList;
Michael Wrightbc4d0d92017-03-23 18:57:57 +0000233import java.util.Arrays;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500234import java.util.Iterator;
John Spurlock7c74f782015-06-04 13:01:42 -0400235import java.util.List;
Christoph Studer265c1052014-07-23 17:14:33 +0200236import java.util.Map.Entry;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500237import java.util.Objects;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400238import java.util.Set;
Chris Wren51017d02015-12-15 15:34:46 -0500239import java.util.concurrent.TimeUnit;
Kristian Monsen30f59b22018-04-09 10:27:16 +0200240import java.util.function.Predicate;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400241
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400242/** {@hide} */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800243public class NotificationManagerService extends SystemService {
244 static final String TAG = "NotificationService";
Christoph Studer1f32c652014-11-26 15:32:20 +0100245 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Selim Cinek40412492015-12-08 18:03:22 -0800246 public static final boolean ENABLE_CHILD_NOTIFICATIONS
247 = SystemProperties.getBoolean("debug.child_notifs", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248
Dan Sandler7d67bd42018-05-15 14:06:38 -0400249 static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
250 "debug.notification.interruptiveness", false);
251
Adam Lesinski182f73f2013-12-05 16:48:06 -0800252 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
Julia Reynolds6ad0aec2017-07-05 08:47:03 -0400253 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
Joe Onoratobd73d012010-06-04 11:44:54 -0700254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 // message codes
Robert Carr997427342018-02-28 18:06:10 -0800256 static final int MESSAGE_DURATION_REACHED = 2;
John Spurlock056c5192014-04-20 21:52:01 -0400257 static final int MESSAGE_SAVE_POLICY_FILE = 3;
Chris Wren51017d02015-12-15 15:34:46 -0500258 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
259 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
260 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
Robert Carr997427342018-02-28 18:06:10 -0800261 static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
Chris Wren51017d02015-12-15 15:34:46 -0500262
263 // ranking thread messages
264 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
265 private static final int MESSAGE_RANKING_SORT = 1001;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700267 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800268 static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800269
Robert Carr3406d462018-03-15 16:19:07 -0700270 // 1 second past the ANR timeout.
271 static final int FINISH_TOKEN_TIMEOUT = 11 * 1000;
272
Adam Lesinski182f73f2013-12-05 16:48:06 -0800273 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
Christoph Studer265c1052014-07-23 17:14:33 +0200274
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500275 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
276
Adam Lesinski182f73f2013-12-05 16:48:06 -0800277 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278
Adam Lesinski182f73f2013-12-05 16:48:06 -0800279 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler526fa0e2012-12-04 14:51:50 -0500280
Adam Lesinski182f73f2013-12-05 16:48:06 -0800281 static final boolean ENABLE_BLOCKED_TOASTS = true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400282
Christoph Studer12aeda82014-09-23 19:08:56 +0200283 // When #matchesCallFilter is called from the ringer, wait at most
284 // 3s to resolve the contacts. This timeout is required since
285 // ContactsProvider might take a long time to start up.
286 //
287 // Return STARRED_CONTACT when the timeout is hit in order to avoid
288 // missed calls in ZEN mode "Important".
289 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
290 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
291 ValidateNotificationPeople.STARRED_CONTACT;
292
Christoph Studer265c1052014-07-23 17:14:33 +0200293 /** notification_enqueue status value for a newly enqueued notification. */
294 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
295
296 /** notification_enqueue status value for an existing notification. */
297 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
298
299 /** notification_enqueue status value for an ignored notification. */
300 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
Chris Wrenc8673a82016-05-17 17:11:29 -0400301 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
Christoph Studer265c1052014-07-23 17:14:33 +0200302
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500303 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
304
Julia Reynolds2a128742016-11-28 14:29:25 -0500305 private static final String ACTION_NOTIFICATION_TIMEOUT =
306 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
307 private static final int REQUEST_CODE_TIMEOUT = 1;
308 private static final String SCHEME_TIMEOUT = "timeout";
309 private static final String EXTRA_KEY = "key";
310
Adam Lesinski182f73f2013-12-05 16:48:06 -0800311 private IActivityManager mAm;
Julia Reynolds68263d12017-06-21 14:21:19 -0400312 private ActivityManager mActivityManager;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500313 private IPackageManager mPackageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500314 private PackageManager mPackageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800315 AudioManager mAudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500316 AudioManagerInternal mAudioManagerInternal;
Wei Liu97e56662016-03-04 10:52:33 -0800317 @Nullable StatusBarManagerInternal mStatusBar;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800318 Vibrator mVibrator;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700319 private WindowManagerInternal mWindowManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -0500320 private AlarmManager mAlarmManager;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400321 private ICompanionDeviceManager mCompanionManager;
Julia Reynolds94187562017-10-10 13:58:49 -0400322 private AccessibilityManager mAccessibilityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800323 private IDeviceIdleController mDeviceIdleController;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700324 private IUriGrantsManager mUgm;
325 private UriGrantsManagerInternal mUgmInternal;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 final IBinder mForegroundToken = new Binder();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400328 private WorkerHandler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400329 private final HandlerThread mRankingThread = new HandlerThread("ranker",
330 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331
Adam Lesinski182f73f2013-12-05 16:48:06 -0800332 private Light mNotificationLight;
333 Light mAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800334
Daniel Sandleredbb3802012-11-13 20:49:47 -0800335 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400336 private boolean mUseAttentionLight;
Julia Reynolds28149f62018-07-03 10:43:35 -0400337 boolean mHasLight = true;
338 boolean mLightEnabled;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800339 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800340
John Spurlockd8afe3c2014-08-01 14:04:07 -0400341 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400342 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500343 private String mSoundNotificationKey;
344 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345
Bryce Lee7219ada2016-04-08 10:54:23 -0700346 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400347 new SparseArray<>();
348 private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400349 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500350 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400351
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500352 // for enabling and disabling notification pulse behavior
Julia Reynolds28149f62018-07-03 10:43:35 -0400353 boolean mScreenOn = true;
Beverly5d463b62017-07-26 14:13:40 -0400354 protected boolean mInCall = false;
Julia Reynolds28149f62018-07-03 10:43:35 -0400355 boolean mNotificationPulseEnabled;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500356
Beverly5d463b62017-07-26 14:13:40 -0400357 private Uri mInCallNotificationUri;
358 private AudioAttributes mInCallNotificationAudioAttributes;
359 private float mInCallNotificationVolume;
luochaojiang50e5273c2018-04-16 16:55:03 +0800360 private Binder mCallNotificationToken = null;
Marta Białka39c992f2011-03-10 10:27:24 +0100361
Daniel Sandler09a247e2013-02-14 10:24:17 -0500362 // used as a mutex for access to all active notifications & listeners
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500363 final Object mNotificationLock = new Object();
Julia Reynolds0839c022017-06-15 15:24:01 -0400364 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400365 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400366 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400367 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400368 @GuardedBy("mNotificationLock")
Chris Wren6676dab2016-12-21 18:26:27 -0500369 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400370 @GuardedBy("mNotificationLock")
Julia Reynoldseae43fb2016-05-09 12:42:58 -0400371 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400372 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
Christoph Studer265c1052014-07-23 17:14:33 +0200373 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500374 final ArrayMap<Integer, ArrayList<NotifyingApp>> mRecentApps = new ArrayMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375
Chris Wren6054e612014-11-25 17:16:46 -0500376 // The last key in this list owns the hardware.
377 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700378
Adam Lesinski182f73f2013-12-05 16:48:06 -0800379 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700380 private UsageStatsManagerInternal mAppUsageStats;
Jason Parks50322ff2018-03-27 10:23:33 -0500381 private DevicePolicyManagerInternal mDpm;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500382
Griff Hazen9f637d12014-06-10 11:13:51 -0700383 private Archive mArchive;
384
John Spurlock21258a32015-05-27 18:22:55 -0400385 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400386 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400387
Daniel Sandler0da673f2012-04-11 12:33:16 -0400388 private static final int DB_VERSION = 1;
389
John Spurlock21258a32015-05-27 18:22:55 -0400390 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400391 private static final String ATTR_VERSION = "version";
392
Chris Wren54bbef42014-07-09 18:37:56 -0400393 private RankingHelper mRankingHelper;
Aaron Heuckrothe5bec152018-07-09 16:26:09 -0400394 private PreferencesHelper mPreferencesHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400395
John Spurlockb408e8e2014-04-23 21:12:45 -0400396 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400397 private NotificationListeners mListeners;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400398 private NotificationAssistants mAssistants;
John Spurlock7340fc82014-04-24 18:50:12 -0400399 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200400 private NotificationUsageStats mUsageStats;
Christoph Studer546bec82014-03-14 12:17:12 +0100401
John Spurlocke6a7d932014-03-13 12:29:00 -0400402 private static final int MY_UID = Process.myUid();
403 private static final int MY_PID = Process.myPid();
Dianne Hackborn98305522017-05-05 17:53:53 -0700404 private static final IBinder WHITELIST_TOKEN = new Binder();
Chris Wren51017d02015-12-15 15:34:46 -0500405 private RankingHandler mRankingHandler;
Chris Wrenc8673a82016-05-17 17:11:29 -0400406 private long mLastOverRateLogTime;
Chris Wren763a9bb2016-05-31 17:14:12 -0400407 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
John Spurlocke6a7d932014-03-13 12:29:00 -0400408
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400409 private SnoozeHelper mSnoozeHelper;
Julia Reynolds8f488d32016-10-14 10:59:01 -0400410 private GroupHelper mGroupHelper;
Adora Zhang48dd614a82018-06-25 19:18:41 -0700411 private int mAutoGroupAtCount;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -0500412 private boolean mIsTelevision;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400413
Kenny Guy23991102018-04-05 21:18:38 +0100414 private MetricsLogger mMetricsLogger;
Kristian Monsen30f59b22018-04-09 10:27:16 +0200415 private Predicate<String> mAllowedManagedServicePackages;
Kenny Guy23991102018-04-05 21:18:38 +0100416
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500417 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700418 final int mBufferSize;
419 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500420
Griff Hazen9f637d12014-06-10 11:13:51 -0700421 public Archive(int size) {
422 mBufferSize = size;
423 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500424 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700425
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400426 public String toString() {
427 final StringBuilder sb = new StringBuilder();
428 final int N = mBuffer.size();
429 sb.append("Archive (");
430 sb.append(N);
431 sb.append(" notification");
432 sb.append((N==1)?")":"s)");
433 return sb.toString();
434 }
435
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500436 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700437 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500438 mBuffer.removeFirst();
439 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400440
441 // We don't want to store the heavy bits of the notification in the archive,
442 // but other clients in the system process might be using the object, so we
443 // store a (lightened) copy.
444 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500445 }
446
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500447 public Iterator<StatusBarNotification> descendingIterator() {
448 return mBuffer.descendingIterator();
449 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500450
451 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700452 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500453 final StatusBarNotification[] a
454 = new StatusBarNotification[Math.min(count, mBuffer.size())];
455 Iterator<StatusBarNotification> iter = descendingIterator();
456 int i=0;
457 while (iter.hasNext() && i < count) {
458 a[i++] = iter.next();
459 }
460 return a;
461 }
462
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500463 }
464
Julia Reynolds88a879f2017-07-26 17:06:46 -0400465 protected void readDefaultApprovedServices(int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400466 String defaultListenerAccess = getContext().getResources().getString(
467 com.android.internal.R.string.config_defaultListenerAccessPackages);
468 if (defaultListenerAccess != null) {
469 for (String whitelisted :
470 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
471 // Gather all notification listener components for candidate pkgs.
472 Set<ComponentName> approvedListeners =
473 mListeners.queryPackageForServices(whitelisted,
474 PackageManager.MATCH_DIRECT_BOOT_AWARE
475 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
476 for (ComponentName cn : approvedListeners) {
477 try {
478 getBinderService().setNotificationListenerAccessGrantedForUser(cn,
479 userId, true);
480 } catch (RemoteException e) {
481 e.printStackTrace();
482 }
483 }
484 }
485 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500486
Julia Reynoldsb852e562017-06-06 16:14:18 -0400487 String defaultDndAccess = getContext().getResources().getString(
488 com.android.internal.R.string.config_defaultDndAccessPackages);
Edward Savage-Jones36a89422018-07-19 12:23:58 +0200489 if (defaultDndAccess != null) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400490 for (String whitelisted :
491 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
492 try {
493 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
494 } catch (RemoteException e) {
495 e.printStackTrace();
496 }
497 }
498 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500499
500 readDefaultAssistant(userId);
501 }
502
503 protected void readDefaultAssistant(int userId) {
504 String defaultAssistantAccess = getContext().getResources().getString(
505 com.android.internal.R.string.config_defaultAssistantAccessPackage);
506 if (defaultAssistantAccess != null) {
507 // Gather all notification assistant components for candidate pkg. There should
508 // only be one
509 Set<ComponentName> approvedAssistants =
510 mAssistants.queryPackageForServices(defaultAssistantAccess,
511 PackageManager.MATCH_DIRECT_BOOT_AWARE
512 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
513 for (ComponentName cn : approvedAssistants) {
514 try {
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400515 getBinderService().setNotificationAssistantAccessGrantedForUser(
516 cn, userId, true);
Julia Reynolds7380d872018-01-12 10:28:26 -0500517 } catch (RemoteException e) {
518 e.printStackTrace();
519 }
520 }
521 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400522 }
523
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400524 void readPolicyXml(InputStream stream, boolean forRestore)
John Spurlock35ef0a62015-05-28 11:24:10 -0400525 throws XmlPullParserException, NumberFormatException, IOException {
526 final XmlPullParser parser = Xml.newPullParser();
527 parser.setInput(stream, StandardCharsets.UTF_8.name());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400528 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
529 boolean migratedManagedServices = false;
530 int outerDepth = parser.getDepth();
531 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
532 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
533 mZenModeHelper.readXml(parser, forRestore);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -0400534 } else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){
535 mPreferencesHelper.readXml(parser, forRestore);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400536 }
Kristian Monsen30f59b22018-04-09 10:27:16 +0200537 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
538 mListeners.readXml(parser, mAllowedManagedServicePackages);
539 migratedManagedServices = true;
540 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
541 mAssistants.readXml(parser, mAllowedManagedServicePackages);
542 migratedManagedServices = true;
543 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
544 mConditionProviders.readXml(parser, mAllowedManagedServicePackages);
545 migratedManagedServices = true;
Julia Reynolds68263d12017-06-21 14:21:19 -0400546 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400547 }
548
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400549 if (!migratedManagedServices) {
550 mListeners.migrateToXml();
551 mAssistants.migrateToXml();
552 mConditionProviders.migrateToXml();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400553 savePolicyFile();
John Spurlock35ef0a62015-05-28 11:24:10 -0400554 }
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400555
556 mAssistants.ensureAssistant();
John Spurlock35ef0a62015-05-28 11:24:10 -0400557 }
558
John Spurlock056c5192014-04-20 21:52:01 -0400559 private void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400560 if (DBG) Slog.d(TAG, "loadPolicyFile");
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500561 synchronized (mPolicyFile) {
Daniel Sandler0da673f2012-04-11 12:33:16 -0400562
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400563 InputStream infile = null;
John Spurlock056c5192014-04-20 21:52:01 -0400564 try {
565 infile = mPolicyFile.openRead();
John Spurlock35ef0a62015-05-28 11:24:10 -0400566 readPolicyXml(infile, false /*forRestore*/);
John Spurlock056c5192014-04-20 21:52:01 -0400567 } catch (FileNotFoundException e) {
568 // No data yet
Julia Reynoldsb852e562017-06-06 16:14:18 -0400569 // Load default managed services approvals
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400570 readDefaultApprovedServices(USER_SYSTEM);
John Spurlock056c5192014-04-20 21:52:01 -0400571 } catch (IOException e) {
572 Log.wtf(TAG, "Unable to read notification policy", e);
573 } catch (NumberFormatException e) {
574 Log.wtf(TAG, "Unable to parse notification policy", e);
575 } catch (XmlPullParserException e) {
576 Log.wtf(TAG, "Unable to parse notification policy", e);
577 } finally {
578 IoUtils.closeQuietly(infile);
579 }
580 }
581 }
582
583 public void savePolicyFile() {
584 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
585 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
586 }
587
588 private void handleSavePolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400589 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400590 synchronized (mPolicyFile) {
591 final FileOutputStream stream;
592 try {
593 stream = mPolicyFile.startWrite();
594 } catch (IOException e) {
595 Slog.w(TAG, "Failed to save policy file", e);
596 return;
597 }
598
599 try {
John Spurlock35ef0a62015-05-28 11:24:10 -0400600 writePolicyXml(stream, false /*forBackup*/);
John Spurlock056c5192014-04-20 21:52:01 -0400601 mPolicyFile.finishWrite(stream);
602 } catch (IOException e) {
603 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
604 mPolicyFile.failWrite(stream);
Daniel Sandler0da673f2012-04-11 12:33:16 -0400605 }
606 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400607 BackupManager.dataChanged(getContext().getPackageName());
608 }
609
610 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
611 final XmlSerializer out = new FastXmlSerializer();
612 out.setOutput(stream, StandardCharsets.UTF_8.name());
613 out.startDocument(null, true);
614 out.startTag(null, TAG_NOTIFICATION_POLICY);
615 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
Beverly4e2f76c2018-03-16 15:43:49 -0400616 mZenModeHelper.writeXml(out, forBackup, null);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -0400617 mPreferencesHelper.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400618 mListeners.writeXml(out, forBackup);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400619 mAssistants.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400620 mConditionProviders.writeXml(out, forBackup);
John Spurlock35ef0a62015-05-28 11:24:10 -0400621 out.endTag(null, TAG_NOTIFICATION_POLICY);
622 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400623 }
624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 private static final class ToastRecord
626 {
627 final int pid;
628 final String pkg;
Beverly Taia7ed0ab2018-06-11 14:50:36 +0000629 final ITransientNotification callback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 int duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700631 Binder token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700633 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
634 Binder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 this.pid = pid;
636 this.pkg = pkg;
637 this.callback = callback;
638 this.duration = duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700639 this.token = token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 }
641
642 void update(int duration) {
643 this.duration = duration;
644 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800645
John Spurlock25e2d242014-06-27 13:58:23 -0400646 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
647 if (filter != null && !filter.matches(pkg)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 pw.println(prefix + this);
649 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800650
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 @Override
652 public final String toString()
653 {
654 return "ToastRecord{"
655 + Integer.toHexString(System.identityHashCode(this))
656 + " pkg=" + pkg
657 + " callback=" + callback
658 + " duration=" + duration;
659 }
660 }
661
Beverly40239d92017-07-07 10:20:41 -0400662 @VisibleForTesting
663 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664
Adam Lesinski182f73f2013-12-05 16:48:06 -0800665 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 public void onSetDisabled(int status) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500667 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400668 mDisableNotificationEffects =
669 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
John Spurlock32fe4c62014-10-02 12:16:02 -0400670 if (disableNotificationEffects(null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 // cancel whatever's going on
672 long identity = Binder.clearCallingIdentity();
673 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800674 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700675 if (player != null) {
676 player.stopAsync();
677 }
678 } catch (RemoteException e) {
679 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 Binder.restoreCallingIdentity(identity);
681 }
682
683 identity = Binder.clearCallingIdentity();
684 try {
685 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700686 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 Binder.restoreCallingIdentity(identity);
688 }
689 }
690 }
691 }
692
Adam Lesinski182f73f2013-12-05 16:48:06 -0800693 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400694 public void onClearAll(int callingUid, int callingPid, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500695 synchronized (mNotificationLock) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400696 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
Kenny Guya263e4e2014-03-03 18:24:03 +0000697 /*includeCurrentProfiles*/ true);
Adam Lesinskie8240262014-03-26 16:01:00 -0700698 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 }
700
Adam Lesinski182f73f2013-12-05 16:48:06 -0800701 @Override
Dieter Hsud39f0d52018-04-14 02:08:30 +0800702 public void onNotificationClick(int callingUid, int callingPid, String key, NotificationVisibility nv) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800703 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500704 synchronized (mNotificationLock) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200705 NotificationRecord r = mNotificationsByKey.get(key);
706 if (r == null) {
707 Log.w(TAG, "No notification with key: " + key);
708 return;
709 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400710 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500711 MetricsLogger.action(r.getLogMaker(now)
712 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
Dieter Hsud39f0d52018-04-14 02:08:30 +0800713 .setType(MetricsEvent.TYPE_ACTION)
714 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
715 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400716 EventLogTags.writeNotificationClicked(key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800717 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
718 nv.rank, nv.count);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400719
Christoph Studer03b87a22014-04-30 17:33:27 +0200720 StatusBarNotification sbn = r.sbn;
721 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
722 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400723 FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
Dieter Hsud39f0d52018-04-14 02:08:30 +0800724 REASON_CLICK, nv.rank, nv.count, null);
725 nv.recycle();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800726 reportUserInteraction(r);
Christoph Studer03b87a22014-04-30 17:33:27 +0200727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 }
729
Adam Lesinski182f73f2013-12-05 16:48:06 -0800730 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200731 public void onNotificationActionClick(int callingUid, int callingPid, String key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800732 int actionIndex, NotificationVisibility nv) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800733 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500734 synchronized (mNotificationLock) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200735 NotificationRecord r = mNotificationsByKey.get(key);
736 if (r == null) {
737 Log.w(TAG, "No notification with key: " + key);
738 return;
739 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400740 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500741 MetricsLogger.action(r.getLogMaker(now)
742 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
743 .setType(MetricsEvent.TYPE_ACTION)
Dieter Hsud39f0d52018-04-14 02:08:30 +0800744 .setSubtype(actionIndex)
745 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
746 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400747 EventLogTags.writeNotificationActionClicked(key, actionIndex,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800748 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
749 nv.rank, nv.count);
750 nv.recycle();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800751 reportUserInteraction(r);
Christoph Studer4da84cd2014-10-21 17:24:20 +0200752 }
753 }
754
755 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400756 public void onNotificationClear(int callingUid, int callingPid,
Julia Reynolds503ed942017-10-04 16:04:56 -0400757 String pkg, String tag, int id, int userId, String key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800758 @NotificationStats.DismissalSurface int dismissalSurface,
759 NotificationVisibility nv) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400760 synchronized (mNotificationLock) {
761 NotificationRecord r = mNotificationsByKey.get(key);
762 if (r != null) {
763 r.recordDismissalSurface(dismissalSurface);
764 }
765 }
John Spurlocke6a7d932014-03-13 12:29:00 -0400766 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400767 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800768 true, userId, REASON_CANCEL, nv.rank, nv.count,null);
769 nv.recycle();
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400770 }
771
Adam Lesinski182f73f2013-12-05 16:48:06 -0800772 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400773 public void onPanelRevealed(boolean clearEffects, int items) {
Chris Wren9eb5e102017-01-26 13:15:06 -0500774 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Chris Wren621933f2017-06-14 15:59:03 -0400775 MetricsLogger.histogram(getContext(), "note_load", items);
Chris Wrenb659c4f2015-06-25 17:12:27 -0400776 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100777 if (clearEffects) {
778 clearEffects();
779 }
780 }
781
782 @Override
783 public void onPanelHidden() {
Chris Wren9eb5e102017-01-26 13:15:06 -0500784 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Christoph Studer1f32c652014-11-26 15:32:20 +0100785 EventLogTags.writeNotificationPanelHidden();
786 }
787
788 @Override
789 public void clearEffects() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500790 synchronized (mNotificationLock) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100791 if (DBG) Slog.d(TAG, "clearEffects");
Chris Wren93bb8b82016-03-29 14:35:05 -0400792 clearSoundLocked();
793 clearVibrateLocked();
794 clearLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 }
796 }
Joe Onorato005847b2010-06-04 16:08:02 -0400797
Adam Lesinski182f73f2013-12-05 16:48:06 -0800798 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400799 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000800 int uid, int initialPid, String message, int userId) {
John Spurlocke6a7d932014-03-13 12:29:00 -0400801 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400802 REASON_ERROR, null);
Joe Onorato005847b2010-06-04 16:08:02 -0400803 }
John Spurlocke677d712014-02-13 12:52:19 -0500804
805 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400806 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
807 NotificationVisibility[] noLongerVisibleKeys) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500808 synchronized (mNotificationLock) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400809 for (NotificationVisibility nv : newlyVisibleKeys) {
810 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200811 if (r == null) continue;
Amith Yamasani803eab692017-11-09 17:47:04 -0800812 if (!r.isSeen()) {
813 // Report to usage stats that notification was made visible
814 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
815 reportSeen(r);
Kenny Guy23991102018-04-05 21:18:38 +0100816
817 // If the newly visible notification has smart replies
818 // then log that the user has seen them.
819 if (r.getNumSmartRepliesAdded() > 0
820 && !r.hasSeenSmartReplies()) {
821 r.setSeenSmartReplies(true);
822 LogMaker logMaker = r.getLogMaker()
823 .setCategory(MetricsEvent.SMART_REPLY_VISIBLE)
824 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT,
825 r.getNumSmartRepliesAdded());
826 mMetricsLogger.write(logMaker);
827 }
Amith Yamasani803eab692017-11-09 17:47:04 -0800828 }
Dieter Hsud39f0d52018-04-14 02:08:30 +0800829 r.setVisibility(true, nv.rank, nv.count);
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400830 maybeRecordInterruptionLocked(r);
Chris Wrend1dbc922015-06-19 17:51:16 -0400831 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200832 }
833 // Note that we might receive this event after notifications
834 // have already left the system, e.g. after dismissing from the
835 // shade. Hence not finding notifications in
836 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400837 for (NotificationVisibility nv : noLongerVisibleKeys) {
838 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200839 if (r == null) continue;
Dieter Hsud39f0d52018-04-14 02:08:30 +0800840 r.setVisibility(false, nv.rank, nv.count);
Chris Wrend1dbc922015-06-19 17:51:16 -0400841 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200842 }
843 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200844 }
Chris Wren78403d72014-07-28 10:23:24 +0100845
846 @Override
847 public void onNotificationExpansionChanged(String key,
848 boolean userAction, boolean expanded) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500849 synchronized (mNotificationLock) {
Chris Wren78403d72014-07-28 10:23:24 +0100850 NotificationRecord r = mNotificationsByKey.get(key);
851 if (r != null) {
852 r.stats.onExpansionChanged(userAction, expanded);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400853 final long now = System.currentTimeMillis();
Chris Wrenf7342712017-09-14 10:55:55 -0400854 if (userAction) {
Chris Wren377ac6d2017-09-12 14:15:23 -0400855 MetricsLogger.action(r.getLogMaker(now)
856 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
Chris Wrenf7342712017-09-14 10:55:55 -0400857 .setType(expanded ? MetricsEvent.TYPE_DETAIL
858 : MetricsEvent.TYPE_COLLAPSE));
Chris Wren377ac6d2017-09-12 14:15:23 -0400859 }
Julia Reynolds84dc96b2017-11-14 09:51:01 -0500860 if (expanded && userAction) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400861 r.recordExpanded();
862 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400863 EventLogTags.writeNotificationExpansion(key,
864 userAction ? 1 : 0, expanded ? 1 : 0,
865 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Chris Wren78403d72014-07-28 10:23:24 +0100866 }
867 }
868 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400869
870 @Override
871 public void onNotificationDirectReplied(String key) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800872 exitIdle();
Julia Reynolds503ed942017-10-04 16:04:56 -0400873 synchronized (mNotificationLock) {
874 NotificationRecord r = mNotificationsByKey.get(key);
875 if (r != null) {
876 r.recordDirectReplied();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800877 reportUserInteraction(r);
Julia Reynolds503ed942017-10-04 16:04:56 -0400878 }
879 }
880 }
881
882 @Override
Kenny Guy23991102018-04-05 21:18:38 +0100883 public void onNotificationSmartRepliesAdded(String key, int replyCount) {
884 synchronized (mNotificationLock) {
885 NotificationRecord r = mNotificationsByKey.get(key);
886 if (r != null) {
887 r.setNumSmartRepliesAdded(replyCount);
888 }
889 }
890 }
891
892 @Override
893 public void onNotificationSmartReplySent(String key, int replyIndex) {
894 synchronized (mNotificationLock) {
895 NotificationRecord r = mNotificationsByKey.get(key);
896 if (r != null) {
897 LogMaker logMaker = r.getLogMaker()
898 .setCategory(MetricsEvent.SMART_REPLY_ACTION)
899 .setSubtype(replyIndex);
900 mMetricsLogger.write(logMaker);
901 // Treat clicking on a smart reply as a user interaction.
902 reportUserInteraction(r);
903 }
904 }
905 }
906
907 @Override
Julia Reynolds503ed942017-10-04 16:04:56 -0400908 public void onNotificationSettingsViewed(String key) {
909 synchronized (mNotificationLock) {
910 NotificationRecord r = mNotificationsByKey.get(key);
911 if (r != null) {
912 r.recordViewedSettings();
913 }
914 }
915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 };
917
Julia Reynolds88860ce2017-06-01 16:55:49 -0400918 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400919 private void clearSoundLocked() {
920 mSoundNotificationKey = null;
921 long identity = Binder.clearCallingIdentity();
922 try {
923 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
924 if (player != null) {
925 player.stopAsync();
926 }
927 } catch (RemoteException e) {
928 } finally {
929 Binder.restoreCallingIdentity(identity);
930 }
931 }
932
Julia Reynolds88860ce2017-06-01 16:55:49 -0400933 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400934 private void clearVibrateLocked() {
935 mVibrateNotificationKey = null;
936 long identity = Binder.clearCallingIdentity();
937 try {
938 mVibrator.cancel();
939 } finally {
940 Binder.restoreCallingIdentity(identity);
941 }
942 }
943
Julia Reynolds88860ce2017-06-01 16:55:49 -0400944 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400945 private void clearLightsLocked() {
946 // light
947 mLights.clear();
948 updateLightsLocked();
949 }
950
Beverlyd4f96492017-08-02 13:36:11 -0400951 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
952 @Override
953 public void onReceive(Context context, Intent intent) {
954 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
Beverly70dcd002018-03-29 17:09:16 -0400955 // update system notification channels
956 SystemNotificationChannels.createAll(context);
Beverlyd4f96492017-08-02 13:36:11 -0400957 mZenModeHelper.updateDefaultZenRules();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -0400958 mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
Beverlyd4f96492017-08-02 13:36:11 -0400959 }
960 }
961 };
962
Julia Reynoldsb852e562017-06-06 16:14:18 -0400963 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
964 @Override
965 public void onReceive(Context context, Intent intent) {
966 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
967 try {
968 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
969 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
Michal Karpinski6135a262017-08-11 10:45:58 +0100970 int restoredFromSdkInt = intent.getIntExtra(
971 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400972 mListeners.onSettingRestored(
973 element, newValue, restoredFromSdkInt, getSendingUserId());
974 mConditionProviders.onSettingRestored(
975 element, newValue, restoredFromSdkInt, getSendingUserId());
Julia Reynoldsb852e562017-06-06 16:14:18 -0400976 } catch (Exception e) {
977 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
978 }
979 }
980 }
981 };
982
Julia Reynolds2a128742016-11-28 14:29:25 -0500983 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
984 @Override
985 public void onReceive(Context context, Intent intent) {
986 String action = intent.getAction();
987 if (action == null) {
988 return;
989 }
990 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
991 final NotificationRecord record;
992 synchronized (mNotificationLock) {
993 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
994 }
995 if (record != null) {
996 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
997 record.sbn.getPackageName(), record.sbn.getTag(),
998 record.sbn.getId(), 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400999 FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
Julia Reynolds2a128742016-11-28 14:29:25 -05001000 REASON_TIMEOUT, null);
1001 }
1002 }
1003 }
1004 };
1005
Kenny Guy70058402014-10-28 20:45:06 +00001006 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 @Override
1008 public void onReceive(Context context, Intent intent) {
1009 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -08001010 if (action == null) {
1011 return;
1012 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001014 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -04001015 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -04001016 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -04001017 boolean cancelNotifications = true;
Beverly5a20a5e2018-03-06 15:02:44 -05001018 boolean hideNotifications = false;
1019 boolean unhideNotifications = false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001020 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -04001021
Chris Wren3da73022013-05-10 14:41:21 -04001022 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -04001023 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001024 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -04001025 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001026 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001027 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
Beverly5a20a5e2018-03-06 15:02:44 -05001028 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
1029 || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
Kenny Guy70058402014-10-28 20:45:06 +00001030 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1031 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001032 String pkgList[] = null;
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001033 int uidList[] = null;
Julia Reynolds6434eb22016-08-08 17:19:26 -04001034 boolean removingPackage = queryRemove &&
1035 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
1036 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001037 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001038 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001039 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001040 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
1041 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Beverly5a20a5e2018-03-06 15:02:44 -05001042 cancelNotifications = false;
1043 hideNotifications = true;
1044 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
1045 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1046 cancelNotifications = false;
1047 unhideNotifications = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001048 } else if (queryRestart) {
1049 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001050 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001051 } else {
1052 Uri uri = intent.getData();
1053 if (uri == null) {
1054 return;
1055 }
1056 String pkgName = uri.getSchemeSpecificPart();
1057 if (pkgName == null) {
1058 return;
1059 }
Daniel Sandler26ece572012-06-01 15:38:46 -04001060 if (packageChanged) {
1061 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -07001062 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001063 final int enabled = mPackageManager.getApplicationEnabledSetting(
1064 pkgName,
Kenny Guy70058402014-10-28 20:45:06 +00001065 changeUserId != UserHandle.USER_ALL ? changeUserId :
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001066 USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -07001067 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1068 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
1069 cancelNotifications = false;
1070 }
1071 } catch (IllegalArgumentException e) {
1072 // Package doesn't exist; probably racing with uninstall.
1073 // cancelNotifications is already true, so nothing to do here.
1074 if (DBG) {
1075 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
1076 }
Kenny Guy70058402014-10-28 20:45:06 +00001077 } catch (RemoteException e) {
1078 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -04001079 }
1080 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001081 pkgList = new String[]{pkgName};
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001082 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001084 if (pkgList != null && (pkgList.length > 0)) {
1085 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -04001086 if (cancelNotifications) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001087 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
1088 !queryRestart, changeUserId, reason, null);
Beverly5a20a5e2018-03-06 15:02:44 -05001089 } else if (hideNotifications) {
1090 hideNotificationsForPackages(pkgList);
1091 } else if (unhideNotifications) {
1092 unhideNotificationsForPackages(pkgList);
John Spurlock79f78922013-05-16 09:10:05 -04001093 }
Beverly5a20a5e2018-03-06 15:02:44 -05001094
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001095 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 }
Beverly5a20a5e2018-03-06 15:02:44 -05001097
Julia Reynoldsb852e562017-06-06 16:14:18 -04001098 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001099 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsb852e562017-06-06 16:14:18 -04001100 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001101 mPreferencesHelper.onPackagesChanged(
1102 removingPackage, changeUserId, pkgList, uidList);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001103 savePolicyFile();
Kenny Guy70058402014-10-28 20:45:06 +00001104 }
1105 }
1106 };
1107
1108 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1109 @Override
1110 public void onReceive(Context context, Intent intent) {
1111 String action = intent.getAction();
1112
1113 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001114 // Keep track of screen on/off state, but do not turn off the notification light
1115 // until user passes through the lock screen or views the notification.
1116 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +01001117 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001118 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1119 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +01001120 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001121 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -05001122 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
1123 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001124 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001125 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
1126 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1127 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001128 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001129 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001130 }
Rubin Xue95057a2016-04-01 16:49:25 +01001131 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001132 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +01001133 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001134 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001135 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001136 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001137 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1138 // turn off LED when user passes through lock screen
1139 mNotificationLight.turnOff();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001140 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001141 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001142 // reload per-user settings
1143 mSettingsObserver.update(null);
John Spurlockb408e8e2014-04-23 21:12:45 -04001144 mUserProfiles.updateCache(context);
Christoph Studerb53dfd42014-09-12 14:45:59 +02001145 // Refresh managed services
John Spurlock1b8b22b2015-05-20 09:47:13 -04001146 mConditionProviders.onUserSwitched(user);
1147 mListeners.onUserSwitched(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001148 mAssistants.onUserSwitched(user);
John Spurlock21258a32015-05-27 18:22:55 -04001149 mZenModeHelper.onUserSwitched(user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001150 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001151 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1152 if (userId != USER_NULL) {
1153 mUserProfiles.updateCache(context);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001154 if (!mUserProfiles.isManagedProfile(userId)) {
1155 readDefaultApprovedServices(userId);
1156 }
Julia Reynolds88a879f2017-07-26 17:06:46 -04001157 }
John Spurlock21258a32015-05-27 18:22:55 -04001158 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001159 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001160 mUserProfiles.updateCache(context);
John Spurlock21258a32015-05-27 18:22:55 -04001161 mZenModeHelper.onUserRemoved(user);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001162 mPreferencesHelper.onUserRemoved(user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001163 mListeners.onUserRemoved(user);
1164 mConditionProviders.onUserRemoved(user);
1165 mAssistants.onUserRemoved(user);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -04001166 savePolicyFile();
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001167 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001168 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001169 mConditionProviders.onUserUnlocked(user);
1170 mListeners.onUserUnlocked(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001171 mAssistants.onUserUnlocked(user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001172 mZenModeHelper.onUserUnlocked(user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 }
1174 }
1175 };
1176
John Spurlock7c74f782015-06-04 13:01:42 -04001177 private final class SettingsObserver extends ContentObserver {
Chris Wren89aa2262017-05-05 18:05:56 -04001178 private final Uri NOTIFICATION_BADGING_URI
1179 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001180 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1181 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wren763a9bb2016-05-31 17:14:12 -04001182 private final Uri NOTIFICATION_RATE_LIMIT_URI
1183 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001184
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001185 SettingsObserver(Handler handler) {
1186 super(handler);
1187 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001188
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001189 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001190 ContentResolver resolver = getContext().getContentResolver();
Chris Wren89aa2262017-05-05 18:05:56 -04001191 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1192 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001193 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -07001194 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -04001195 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1196 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001197 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001198 }
1199
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001200 @Override public void onChange(boolean selfChange, Uri uri) {
1201 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001202 }
1203
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001204 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001205 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001206 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
zhoulei7e376972017-05-17 18:41:25 +08001207 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
Julia Reynolds28149f62018-07-03 10:43:35 -04001208 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT)
1209 != 0;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001210 if (mNotificationPulseEnabled != pulseEnabled) {
1211 mNotificationPulseEnabled = pulseEnabled;
1212 updateNotificationPulse();
1213 }
1214 }
Chris Wren763a9bb2016-05-31 17:14:12 -04001215 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1216 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1217 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1218 }
Chris Wren89aa2262017-05-05 18:05:56 -04001219 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001220 mPreferencesHelper.updateBadgingEnabled();
Chris Wren89aa2262017-05-05 18:05:56 -04001221 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001222 }
1223 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001224
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001225 private SettingsObserver mSettingsObserver;
Beverlyd4f96492017-08-02 13:36:11 -04001226 protected ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001227
Daniel Sandleredbb3802012-11-13 20:49:47 -08001228 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1229 int[] ar = r.getIntArray(resid);
1230 if (ar == null) {
1231 return def;
1232 }
1233 final int len = ar.length > maxlen ? maxlen : ar.length;
1234 long[] out = new long[len];
1235 for (int i=0; i<len; i++) {
1236 out[i] = ar[i];
1237 }
1238 return out;
1239 }
1240
Jeff Brownb880d882014-02-10 19:47:07 -08001241 public NotificationManagerService(Context context) {
1242 super(context);
Dianne Hackborn98305522017-05-05 17:53:53 -07001243 Notification.processWhitelistToken = WHITELIST_TOKEN;
Jeff Brownb880d882014-02-10 19:47:07 -08001244 }
1245
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001246 // TODO - replace these methods with a single VisibleForTesting constructor
Chris Wren93bb8b82016-03-29 14:35:05 -04001247 @VisibleForTesting
1248 void setAudioManager(AudioManager audioMananger) {
1249 mAudioManager = audioMananger;
1250 }
1251
1252 @VisibleForTesting
1253 void setVibrator(Vibrator vibrator) {
1254 mVibrator = vibrator;
1255 }
1256
1257 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001258 void setLights(Light light) {
1259 mNotificationLight = light;
1260 mAttentionLight = light;
Julia Reynolds033a4122017-01-31 16:50:38 -05001261 mNotificationPulseEnabled = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001262 }
1263
1264 @VisibleForTesting
1265 void setScreenOn(boolean on) {
1266 mScreenOn = on;
1267 }
1268
1269 @VisibleForTesting
Julia Reynolds080361e2017-07-13 11:23:12 -04001270 int getNotificationRecordCount() {
1271 synchronized (mNotificationLock) {
1272 int count = mNotificationList.size() + mNotificationsByKey.size()
1273 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1274 // subtract duplicates
1275 for (NotificationRecord posted : mNotificationList) {
1276 if (mNotificationsByKey.containsKey(posted.getKey())) {
1277 count--;
1278 }
1279 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001280 count--;
Julia Reynolds080361e2017-07-13 11:23:12 -04001281 }
1282 }
1283
1284 return count;
1285 }
1286 }
1287
Julia Reynolds7380d872018-01-12 10:28:26 -05001288 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001289 void clearNotifications() {
1290 mEnqueuedNotifications.clear();
1291 mNotificationList.clear();
1292 mNotificationsByKey.clear();
1293 mSummaryByGroupKey.clear();
1294 }
1295
Julia Reynolds080361e2017-07-13 11:23:12 -04001296 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001297 void addNotification(NotificationRecord r) {
1298 mNotificationList.add(r);
1299 mNotificationsByKey.put(r.sbn.getKey(), r);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001300 if (r.sbn.isGroup()) {
1301 mSummaryByGroupKey.put(r.getGroupKey(), r);
1302 }
1303 }
1304
1305 @VisibleForTesting
1306 void addEnqueuedNotification(NotificationRecord r) {
1307 mEnqueuedNotifications.add(r);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001308 }
1309
1310 @VisibleForTesting
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001311 NotificationRecord getNotificationRecord(String key) {
1312 return mNotificationsByKey.get(key);
1313 }
1314
1315
1316 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001317 void setSystemReady(boolean systemReady) {
1318 mSystemReady = systemReady;
1319 }
1320
1321 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001322 void setHandler(WorkerHandler handler) {
Chris Wren93bb8b82016-03-29 14:35:05 -04001323 mHandler = handler;
1324 }
1325
Chris Wrend4054312016-06-24 17:07:40 -04001326 @VisibleForTesting
Julia Reynolds0c299d42016-11-15 14:37:04 -05001327 void setFallbackVibrationPattern(long[] vibrationPattern) {
1328 mFallbackVibrationPattern = vibrationPattern;
Chris Wrend4054312016-06-24 17:07:40 -04001329 }
1330
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001331 @VisibleForTesting
1332 void setPackageManager(IPackageManager packageManager) {
1333 mPackageManager = packageManager;
1334 }
1335
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001336 @VisibleForTesting
1337 void setRankingHelper(RankingHelper rankingHelper) {
1338 mRankingHelper = rankingHelper;
1339 }
1340
1341 @VisibleForTesting
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001342 void setPreferencesHelper(PreferencesHelper prefHelper) { mPreferencesHelper = prefHelper; }
1343
1344 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001345 void setRankingHandler(RankingHandler rankingHandler) {
1346 mRankingHandler = rankingHandler;
1347 }
1348
1349 @VisibleForTesting
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001350 void setIsTelevision(boolean isTelevision) {
1351 mIsTelevision = isTelevision;
1352 }
1353
Julia Reynolds76c096d2017-06-19 08:16:04 -04001354 @VisibleForTesting
1355 void setUsageStats(NotificationUsageStats us) {
1356 mUsageStats = us;
1357 }
1358
Julia Reynolds94187562017-10-10 13:58:49 -04001359 @VisibleForTesting
1360 void setAccessibilityManager(AccessibilityManager am) {
1361 mAccessibilityManager = am;
1362 }
1363
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001364 // TODO: All tests should use this init instead of the one-off setters above.
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001365 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001366 void init(Looper looper, IPackageManager packageManager,
1367 PackageManager packageManagerClient,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001368 LightsManager lightsManager, NotificationListeners notificationListeners,
Julia Reynoldsb852e562017-06-06 16:14:18 -04001369 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001370 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
Julia Reynolds68263d12017-06-21 14:21:19 -04001371 NotificationUsageStats usageStats, AtomicFile policyFile,
Julia Reynolds7217dc92018-03-07 12:12:09 -05001372 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001373 UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
1374 IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal) {
Chris Wren54bbef42014-07-09 18:37:56 -04001375 Resources resources = getContext().getResources();
Chris Wren763a9bb2016-05-31 17:14:12 -04001376 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1377 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1378 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1379
Julia Reynolds94187562017-10-10 13:58:49 -04001380 mAccessibilityManager =
1381 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001382 mAm = am;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001383 mUgm = ugm;
1384 mUgmInternal = ugmInternal;
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001385 mPackageManager = packageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001386 mPackageManagerClient = packageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001387 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1388 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Julia Reynolds7217dc92018-03-07 12:12:09 -05001389 mAppUsageStats = appUsageStats;
Julia Reynolds2a128742016-11-28 14:29:25 -05001390 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001391 mCompanionManager = companionManager;
Julia Reynolds68263d12017-06-21 14:21:19 -04001392 mActivityManager = activityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -08001393 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1394 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
Jason Parks50322ff2018-03-27 10:23:33 -05001395 mDpm = dpm;
1396
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001397 mHandler = new WorkerHandler(looper);
Chris Wrenf9536642014-04-17 10:01:54 -04001398 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -04001399 String[] extractorNames;
1400 try {
1401 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1402 } catch (Resources.NotFoundException e) {
1403 extractorNames = new String[0];
1404 }
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001405 mUsageStats = usageStats;
Kenny Guy23991102018-04-05 21:18:38 +01001406 mMetricsLogger = new MetricsLogger();
Chris Wren51017d02015-12-15 15:34:46 -05001407 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Julia Reynoldsb852e562017-06-06 16:14:18 -04001408 mConditionProviders = conditionProviders;
John Spurlockb2278d62015-04-07 12:47:12 -04001409 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -04001410 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -04001411 @Override
1412 public void onConfigChanged() {
1413 savePolicyFile();
1414 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001415
1416 @Override
1417 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001418 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -05001419 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -05001420 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1421 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -05001422 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001423 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02001424 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001425 }
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001426 mRankingHandler.requestSort();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001427 }
John Spurlock1fc476d2015-04-14 16:05:20 -04001428
1429 @Override
1430 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001431 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001432 mRankingHandler.requestSort();
John Spurlock80774932015-05-07 17:38:50 -04001433 }
John Spurlock056c5192014-04-20 21:52:01 -04001434 });
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001435 mPreferencesHelper = new PreferencesHelper(getContext(),
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001436 mPackageManagerClient,
1437 mRankingHandler,
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001438 mZenModeHelper);
1439 mRankingHelper = new RankingHelper(getContext(),
1440 mRankingHandler,
1441 mPreferencesHelper,
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001442 mZenModeHelper,
1443 mUsageStats,
1444 extractorNames);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001445 mSnoozeHelper = snoozeHelper;
Julia Reynolds8aebf352017-06-26 11:35:33 -04001446 mGroupHelper = groupHelper;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04001447
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001448 // This is a ManagedServices object that keeps track of the listeners.
1449 mListeners = notificationListeners;
Chris Wren0efdb882016-03-01 17:17:47 -05001450
Julia Reynolds77b2cc92016-11-08 14:41:09 -05001451 // This is a MangedServices object that keeps track of the assistant.
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001452 mAssistants = notificationAssistants;
Julia Reynoldsb852e562017-06-06 16:14:18 -04001453
Kristian Monsen30f59b22018-04-09 10:27:16 +02001454 // Needs to be set before loadPolicyFile
1455 mAllowedManagedServicePackages = this::canUseManagedServices;
1456
Julia Reynoldsb852e562017-06-06 16:14:18 -04001457 mPolicyFile = policyFile;
1458 loadPolicyFile();
Chris Wren0efdb882016-03-01 17:17:47 -05001459
Adam Lesinski182f73f2013-12-05 16:48:06 -08001460 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -08001461 if (mStatusBar != null) {
1462 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1463 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001465 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1466 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001467
Daniel Sandleredbb3802012-11-13 20:49:47 -08001468 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001469 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001470 VIBRATE_PATTERN_MAXLEN,
1471 DEFAULT_VIBRATE_PATTERN);
Beverly5d463b62017-07-26 14:13:40 -04001472 mInCallNotificationUri = Uri.parse("file://" +
1473 resources.getString(R.string.config_inCallNotificationSound));
1474 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1475 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1476 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
Beverly5d463b62017-07-26 14:13:40 -04001477 .build();
1478 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1479
Chris Wren5116a822014-06-04 15:59:50 -04001480 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
Julia Reynolds28149f62018-07-03 10:43:35 -04001481 mHasLight =
1482 resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
Chris Wren5116a822014-06-04 15:59:50 -04001483
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001484 // Don't start allowing notifications until the setup wizard has run once.
1485 // After that, including subsequent boots, init with notifications turned on.
1486 // This works on the first boot because the setup wizard will toggle this
1487 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001488 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001489 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001490 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001491 }
John Spurlockb2278d62015-04-07 12:47:12 -04001492 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001493 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001494
John Spurlockb408e8e2014-04-23 21:12:45 -04001495 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001496 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001497
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001498 mSettingsObserver = new SettingsObserver(mHandler);
1499
1500 mArchive = new Archive(resources.getInteger(
1501 R.integer.config_notificationServiceArchiveSize));
1502
1503 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1504 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1505 }
1506
1507 @Override
1508 public void onStart() {
1509 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1510 @Override
1511 public void repost(int userId, NotificationRecord r) {
1512 try {
1513 if (DBG) {
1514 Slog.d(TAG, "Reposting " + r.getKey());
1515 }
1516 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1517 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1518 r.sbn.getNotification(), userId);
1519 } catch (Exception e) {
1520 Slog.e(TAG, "Cannot un-snooze notification", e);
1521 }
1522 }
1523 }, mUserProfiles);
1524
1525 final File systemDir = new File(Environment.getDataDirectory(), "system");
1526
1527 init(Looper.myLooper(),
1528 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1529 getLocalService(LightsManager.class),
1530 new NotificationListeners(AppGlobals.getPackageManager()),
Julia Reynolds7380d872018-01-12 10:28:26 -05001531 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
1532 AppGlobals.getPackageManager()),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001533 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1534 null, snoozeHelper, new NotificationUsageStats(getContext()),
Dianne Hackborne17b4452018-01-10 13:15:40 -08001535 new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001536 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
Julia Reynolds7217dc92018-03-07 12:12:09 -05001537 getGroupHelper(), ActivityManager.getService(),
Jason Parks50322ff2018-03-27 10:23:33 -05001538 LocalServices.getService(UsageStatsManagerInternal.class),
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001539 LocalServices.getService(DevicePolicyManagerInternal.class),
1540 UriGrantsManager.getService(),
1541 LocalServices.getService(UriGrantsManagerInternal.class));
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001542
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001543 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001545 filter.addAction(Intent.ACTION_SCREEN_ON);
1546 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001547 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001548 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001549 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001550 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001551 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001552 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001553 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001554 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001555 getContext().registerReceiver(mIntentReceiver, filter);
Kenny Guy70058402014-10-28 20:45:06 +00001556
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001557 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001558 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001559 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001560 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001561 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1562 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1563 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001564 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1565 null);
1566
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001567 IntentFilter suspendedPkgFilter = new IntentFilter();
1568 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
Beverly5a20a5e2018-03-06 15:02:44 -05001569 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001570 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1571 suspendedPkgFilter, null, null);
1572
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001573 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001574 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1575 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001576
Julia Reynolds2a128742016-11-28 14:29:25 -05001577 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1578 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1579 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1580
Julia Reynoldsb852e562017-06-06 16:14:18 -04001581 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1582 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1583
Beverlyd4f96492017-08-02 13:36:11 -04001584 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1585 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1586
Vishnu Naire3e4d252018-03-01 11:26:57 -08001587 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
1588 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001589 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590 }
1591
Julia Reynolds8aebf352017-06-26 11:35:33 -04001592 private GroupHelper getGroupHelper() {
Adora Zhang48dd614a82018-06-25 19:18:41 -07001593 mAutoGroupAtCount =
1594 getContext().getResources().getInteger(R.integer.config_autoGroupAtCount);
1595 return new GroupHelper(mAutoGroupAtCount, new GroupHelper.Callback() {
Julia Reynolds8aebf352017-06-26 11:35:33 -04001596 @Override
1597 public void addAutoGroup(String key) {
1598 synchronized (mNotificationLock) {
1599 addAutogroupKeyLocked(key);
1600 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001601 }
1602
1603 @Override
1604 public void removeAutoGroup(String key) {
1605 synchronized (mNotificationLock) {
1606 removeAutogroupKeyLocked(key);
1607 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001608 }
1609
1610 @Override
1611 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1612 createAutoGroupSummary(userId, pkg, triggeringKey);
1613 }
1614
1615 @Override
1616 public void removeAutoGroupSummary(int userId, String pkg) {
1617 synchronized (mNotificationLock) {
1618 clearAutogroupSummaryLocked(userId, pkg);
1619 }
1620 }
1621 });
1622 }
1623
John Spurlocke7a835b2015-05-13 10:47:05 -04001624 private void sendRegisteredOnlyBroadcast(String action) {
1625 getContext().sendBroadcastAsUser(new Intent(action)
1626 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1627 }
1628
Adam Lesinski182f73f2013-12-05 16:48:06 -08001629 @Override
1630 public void onBootPhase(int phase) {
1631 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1632 // no beeping until we're basically done booting
1633 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001634
Adam Lesinski182f73f2013-12-05 16:48:06 -08001635 // Grab our optional AudioService
1636 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001637 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001638 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001639 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001640 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1641 // This observer will force an update when observe is called, causing us to
1642 // bind to listener services.
1643 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001644 mListeners.onBootPhaseAppsCanStart();
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001645 mAssistants.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001646 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 }
1648 }
1649
Julia Reynolds88860ce2017-06-01 16:55:49 -04001650 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04001651 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001652 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001653 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001654 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001655 mListenerHints = hints;
1656 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001657 }
1658
Julia Reynolds88860ce2017-06-01 16:55:49 -04001659 @GuardedBy("mNotificationLock")
John Spurlockb4782522014-08-22 14:54:46 -04001660 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001661 final long updatedSuppressedEffects = calculateSuppressedEffects();
1662 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1663 final List<ComponentName> suppressors = getSuppressors();
1664 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1665 mEffectsSuppressors = suppressors;
1666 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001667 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001668 }
1669
Amith Yamasani396a10c2018-01-19 10:58:07 -08001670 private void exitIdle() {
1671 try {
1672 if (mDeviceIdleController != null) {
1673 mDeviceIdleController.exitIdle("notification interaction");
1674 }
1675 } catch (RemoteException e) {
1676 }
1677 }
1678
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001679 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1680 boolean fromListener) {
Julia Reynolds924eed12017-01-19 09:52:07 -05001681 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1682 // cancel
1683 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001684 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
Julia Reynolds924eed12017-01-19 09:52:07 -05001685 null);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001686 if (isUidSystemOrPhone(uid)) {
1687 int[] profileIds = mUserProfiles.getCurrentProfileIds();
1688 int N = profileIds.length;
1689 for (int i = 0; i < N; i++) {
1690 int profileId = profileIds[i];
1691 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1692 profileId, REASON_CHANNEL_BANNED,
1693 null);
1694 }
1695 }
Julia Reynolds924eed12017-01-19 09:52:07 -05001696 }
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001697 final NotificationChannel preUpdate =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001698 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001699
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001700 mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001701 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
Julia Reynolds924eed12017-01-19 09:52:07 -05001702
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001703 if (!fromListener) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001704 final NotificationChannel modifiedChannel =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001705 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001706 mListeners.notifyNotificationChannelChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001707 pkg, UserHandle.getUserHandleForUid(uid),
1708 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001709 }
1710
Julia Reynolds924eed12017-01-19 09:52:07 -05001711 savePolicyFile();
1712 }
1713
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001714 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1715 NotificationChannel update) {
1716 try {
1717 if ((preUpdate.getImportance() == IMPORTANCE_NONE
1718 && update.getImportance() != IMPORTANCE_NONE)
1719 || (preUpdate.getImportance() != IMPORTANCE_NONE
1720 && update.getImportance() == IMPORTANCE_NONE)) {
1721 getContext().sendBroadcastAsUser(
1722 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001723 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001724 update.getId())
1725 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1726 update.getImportance() == IMPORTANCE_NONE)
1727 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1728 .setPackage(pkg),
1729 UserHandle.of(UserHandle.getUserId(uid)), null);
1730 }
1731 } catch (SecurityException e) {
1732 Slog.w(TAG, "Can't notify app about channel change", e);
1733 }
1734 }
1735
Julia Reynolds005c8b92017-08-24 10:35:53 -04001736 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
1737 boolean fromApp, boolean fromListener) {
1738 Preconditions.checkNotNull(group);
1739 Preconditions.checkNotNull(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001740
1741 final NotificationChannelGroup preUpdate =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001742 mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
1743 mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group,
Julia Reynolds005c8b92017-08-24 10:35:53 -04001744 fromApp);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001745 if (!fromApp) {
1746 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
1747 }
Julia Reynolds005c8b92017-08-24 10:35:53 -04001748 if (!fromListener) {
1749 mListeners.notifyNotificationChannelGroupChanged(pkg,
1750 UserHandle.of(UserHandle.getCallingUserId()), group,
1751 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1752 }
1753 }
1754
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001755 private void maybeNotifyChannelGroupOwner(String pkg, int uid,
1756 NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
1757 try {
1758 if (preUpdate.isBlocked() != update.isBlocked()) {
1759 getContext().sendBroadcastAsUser(
1760 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001761 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001762 update.getId())
1763 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1764 update.isBlocked())
1765 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1766 .setPackage(pkg),
1767 UserHandle.of(UserHandle.getUserId(uid)), null);
1768 }
1769 } catch (SecurityException e) {
1770 Slog.w(TAG, "Can't notify app about group change", e);
1771 }
1772 }
1773
Bryce Lee7219ada2016-04-08 10:54:23 -07001774 private ArrayList<ComponentName> getSuppressors() {
1775 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1776 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1777 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1778
1779 for (ManagedServiceInfo info : serviceInfoList) {
1780 names.add(info.component);
1781 }
1782 }
1783
1784 return names;
1785 }
1786
1787 private boolean removeDisabledHints(ManagedServiceInfo info) {
1788 return removeDisabledHints(info, 0);
1789 }
1790
1791 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1792 boolean removed = false;
1793
1794 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1795 final int hint = mListenersDisablingEffects.keyAt(i);
1796 final ArraySet<ManagedServiceInfo> listeners =
1797 mListenersDisablingEffects.valueAt(i);
1798
1799 if (hints == 0 || (hint & hints) == hint) {
1800 removed = removed || listeners.remove(info);
1801 }
1802 }
1803
1804 return removed;
1805 }
1806
1807 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1808 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1809 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1810 }
1811
1812 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1813 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1814 }
1815
1816 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1817 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1818 }
1819 }
1820
1821 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1822 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1823 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1824 }
1825
1826 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1827 hintListeners.add(info);
1828 }
1829
1830 private int calculateHints() {
1831 int hints = 0;
1832 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1833 int hint = mListenersDisablingEffects.keyAt(i);
1834 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1835
1836 if (!serviceInfoList.isEmpty()) {
1837 hints |= hint;
1838 }
1839 }
1840
1841 return hints;
1842 }
1843
1844 private long calculateSuppressedEffects() {
1845 int hints = calculateHints();
1846 long suppressedEffects = 0;
1847
1848 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1849 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1850 }
1851
1852 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1853 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1854 }
1855
1856 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1857 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1858 }
1859
1860 return suppressedEffects;
1861 }
1862
Julia Reynolds88860ce2017-06-01 16:55:49 -04001863 @GuardedBy("mNotificationLock")
Christoph Studer85a384b2014-08-27 20:16:15 +02001864 private void updateInterruptionFilterLocked() {
1865 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1866 if (interruptionFilter == mInterruptionFilter) return;
1867 mInterruptionFilter = interruptionFilter;
1868 scheduleInterruptionFilterChanged(interruptionFilter);
1869 }
1870
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001871 @VisibleForTesting
1872 INotificationManager getBinderService() {
1873 return INotificationManager.Stub.asInterface(mService);
1874 }
1875
Amith Yamasani7ec89412018-02-07 08:48:49 -08001876 /**
1877 * Report to usage stats that the notification was seen.
1878 * @param r notification record
1879 */
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001880 @GuardedBy("mNotificationLock")
Amith Yamasani803eab692017-11-09 17:47:04 -08001881 protected void reportSeen(NotificationRecord r) {
Amith Yamasani803eab692017-11-09 17:47:04 -08001882 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001883 getRealUserId(r.sbn.getUserId()),
Amith Yamasani803eab692017-11-09 17:47:04 -08001884 UsageEvents.Event.NOTIFICATION_SEEN);
1885 }
1886
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001887 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
1888 int targetSdkVersion) {
1889 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
1890 return incomingPolicy.suppressedVisualEffects;
1891 }
1892 final int[] effectsIntroducedInP = {
1893 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
1894 SUPPRESSED_EFFECT_LIGHTS,
1895 SUPPRESSED_EFFECT_PEEK,
1896 SUPPRESSED_EFFECT_STATUS_BAR,
1897 SUPPRESSED_EFFECT_BADGE,
1898 SUPPRESSED_EFFECT_AMBIENT,
1899 SUPPRESSED_EFFECT_NOTIFICATION_LIST
1900 };
1901
1902 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06001903 if (targetSdkVersion < Build.VERSION_CODES.P) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001904 // unset higher order bits introduced in P, maintain the user's higher order bits
1905 for (int i = 0; i < effectsIntroducedInP.length ; i++) {
1906 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
1907 newSuppressedVisualEffects |=
1908 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
1909 }
1910 // set higher order bits according to lower order bits
1911 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1912 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1913 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001914 }
1915 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1916 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1917 }
1918 } else {
1919 boolean hasNewEffects = (newSuppressedVisualEffects
1920 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
1921 // if any of the new effects introduced in P are set
1922 if (hasNewEffects) {
1923 // clear out the deprecated effects
1924 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
1925 | SUPPRESSED_EFFECT_SCREEN_OFF);
1926
1927 // set the deprecated effects according to the new more specific effects
1928 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
1929 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
1930 }
1931 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
1932 && (newSuppressedVisualEffects
1933 & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
1934 && (newSuppressedVisualEffects
1935 & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
1936 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
1937 }
1938 } else {
1939 // set higher order bits according to lower order bits
1940 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1941 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1942 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
1943 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
1944 }
1945 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1946 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1947 }
1948 }
1949 }
1950
1951 return newSuppressedVisualEffects;
1952 }
1953
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001954 @GuardedBy("mNotificationLock")
1955 protected void maybeRecordInterruptionLocked(NotificationRecord r) {
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04001956 if (r.isInterruptive() && !r.hasRecordedInterruption()) {
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001957 mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
1958 r.getChannel().getId(),
1959 getRealUserId(r.sbn.getUserId()));
Julia Reynoldsad7d7132018-03-21 16:05:00 -04001960 logRecentLocked(r);
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04001961 r.setRecordedInterruption(true);
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001962 }
1963 }
1964
Amith Yamasani7ec89412018-02-07 08:48:49 -08001965 /**
1966 * Report to usage stats that the notification was clicked.
1967 * @param r notification record
1968 */
1969 protected void reportUserInteraction(NotificationRecord r) {
Amith Yamasani7ec89412018-02-07 08:48:49 -08001970 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001971 getRealUserId(r.sbn.getUserId()),
Amith Yamasani7ec89412018-02-07 08:48:49 -08001972 UsageEvents.Event.USER_INTERACTION);
1973 }
1974
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001975 private int getRealUserId(int userId) {
1976 return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
1977 }
1978
Geoffrey Pitsch415e4542017-04-10 13:12:58 -04001979 @VisibleForTesting
1980 NotificationManagerInternal getInternalService() {
1981 return mInternalService;
1982 }
1983
Adam Lesinski182f73f2013-12-05 16:48:06 -08001984 private final IBinder mService = new INotificationManager.Stub() {
1985 // Toasts
1986 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001988 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001989 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001991 if (DBG) {
1992 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1993 + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001995
1996 if (pkg == null || callback == null) {
1997 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1998 return ;
1999 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002000 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00002001 final boolean isPackageSuspended =
2002 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
Adam Lesinski182f73f2013-12-05 16:48:06 -08002003
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04002004 if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002005 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
2006 || isPackageSuspended)) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04002007 Slog.e(TAG, "Suppressing toast from package " + pkg
2008 + (isPackageSuspended
2009 ? " due to package suspended by administrator."
2010 : " by user request."));
2011 return;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002012 }
2013
2014 synchronized (mToastQueue) {
2015 int callingPid = Binder.getCallingPid();
2016 long callingId = Binder.clearCallingIdentity();
2017 try {
2018 ToastRecord record;
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002019 int index = indexOfToastLocked(pkg, callback);
2020 // If it's already in the queue, we update it in place, we don't
2021 // move it to the end of the queue.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002022 if (index >= 0) {
2023 record = mToastQueue.get(index);
2024 record.update(duration);
2025 } else {
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002026 // Limit the number of toasts that any given package except the android
2027 // package can enqueue. Prevents DOS attacks and deals with leaks.
2028 if (!isSystemToast) {
2029 int count = 0;
2030 final int N = mToastQueue.size();
2031 for (int i=0; i<N; i++) {
2032 final ToastRecord r = mToastQueue.get(i);
2033 if (r.pkg.equals(pkg)) {
2034 count++;
2035 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2036 Slog.e(TAG, "Package has already posted " + count
2037 + " toasts. Not showing more. Package=" + pkg);
2038 return;
2039 }
2040 }
2041 }
2042 }
2043
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002044 Binder token = new Binder();
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002045 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002046 record = new ToastRecord(callingPid, pkg, callback, duration, token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002047 mToastQueue.add(record);
2048 index = mToastQueue.size() - 1;
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002049 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002050 }
2051 // If it's at index 0, it's the current toast. It doesn't matter if it's
2052 // new or just been updated. Call back and tell it to show itself.
2053 // If the callback fails, this will remove it from the list, so don't
2054 // assume that it's valid after this.
2055 if (index == 0) {
2056 showNextToastLocked();
2057 }
2058 } finally {
2059 Binder.restoreCallingIdentity(callingId);
2060 }
2061 }
2062 }
2063
2064 @Override
2065 public void cancelToast(String pkg, ITransientNotification callback) {
2066 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
2067
2068 if (pkg == null || callback == null) {
2069 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
2070 return ;
2071 }
2072
2073 synchronized (mToastQueue) {
2074 long callingId = Binder.clearCallingIdentity();
2075 try {
2076 int index = indexOfToastLocked(pkg, callback);
2077 if (index >= 0) {
2078 cancelToastLocked(index);
2079 } else {
2080 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
2081 + " callback=" + callback);
2082 }
2083 } finally {
2084 Binder.restoreCallingIdentity(callingId);
2085 }
2086 }
2087 }
2088
2089 @Override
Robert Carr997427342018-02-28 18:06:10 -08002090 public void finishToken(String pkg, ITransientNotification callback) {
2091 synchronized (mToastQueue) {
2092 long callingId = Binder.clearCallingIdentity();
2093 try {
2094 int index = indexOfToastLocked(pkg, callback);
2095 if (index >= 0) {
2096 ToastRecord record = mToastQueue.get(index);
2097 finishTokenLocked(record.token);
2098 } else {
2099 Slog.w(TAG, "Toast already killed. pkg=" + pkg
2100 + " callback=" + callback);
2101 }
2102 } finally {
2103 Binder.restoreCallingIdentity(callingId);
2104 }
2105 }
2106 }
2107
2108 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002109 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002110 Notification notification, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002111 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002112 Binder.getCallingPid(), tag, id, notification, userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002113 }
2114
2115 @Override
2116 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002117 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002118 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2119 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002120 // Don't allow client applications to cancel foreground service notis or autobundled
2121 // summaries.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002122 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
Julia Reynoldse5c60452018-04-30 14:41:36 -04002123 (FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
John Spurlocke6a7d932014-03-13 12:29:00 -04002124 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002125 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002126 }
2127
2128 @Override
2129 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002130 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002131
2132 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2133 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
2134
2135 // Calling from user space, don't allow the canceling of actively
2136 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04002137 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
Julia Reynoldse5c60452018-04-30 14:41:36 -04002138 pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05002139 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002140 }
2141
2142 @Override
2143 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
Rohan Shahca0447e2018-03-30 15:18:27 -07002144 enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002145
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002146 mPreferencesHelper.setEnabled(pkg, uid, enabled);
Howard Ro8b56f752018-08-07 15:44:25 -07002147 mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
2148 .setType(MetricsEvent.TYPE_ACTION)
2149 .setPackageName(pkg)
2150 .setSubtype(enabled ? 1 : 0));
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002151 // Now, cancel any outstanding notifications that are part of a just-disabled app
Julia Reynolds4da79702017-06-01 11:06:10 -04002152 if (!enabled) {
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002153 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
2154 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
2155 }
Julia Reynoldsfc9767b2018-01-22 17:45:16 -05002156
2157 try {
2158 getContext().sendBroadcastAsUser(
2159 new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
2160 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
2161 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2162 .setPackage(pkg),
2163 UserHandle.of(UserHandle.getUserId(uid)), null);
2164 } catch (SecurityException e) {
2165 Slog.w(TAG, "Can't notify app about app block change", e);
2166 }
2167
Chris Wrenacf424a2016-03-15 12:48:55 -04002168 savePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002169 }
2170
2171 /**
Rohan Shah590e1b22018-04-10 23:48:47 -04002172 * Updates the enabled state for notifications for the given package (and uid).
2173 * Additionally, this method marks the app importance as locked by the user, which means
2174 * that notifications from the app will <b>not</b> be considered for showing a
2175 * blocking helper.
2176 *
2177 * @param pkg package that owns the notifications to update
2178 * @param uid uid of the app providing notifications
2179 * @param enabled whether notifications should be enabled for the app
2180 *
2181 * @see #setNotificationsEnabledForPackage(String, int, boolean)
2182 */
2183 @Override
2184 public void setNotificationsEnabledWithImportanceLockForPackage(
2185 String pkg, int uid, boolean enabled) {
2186 setNotificationsEnabledForPackage(pkg, uid, enabled);
2187
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002188 mPreferencesHelper.setAppImportanceLocked(pkg, uid);
Rohan Shah590e1b22018-04-10 23:48:47 -04002189 }
2190
2191 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002192 * Use this when you just want to know if notifications are OK for this package.
2193 */
2194 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002195 public boolean areNotificationsEnabled(String pkg) {
2196 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
2197 }
2198
2199 /**
2200 * Use this when you just want to know if notifications are OK for this package.
2201 */
2202 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002203 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002204 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002205
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002206 return mPreferencesHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002207 }
2208
Chris Wren54bbef42014-07-09 18:37:56 -04002209 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05002210 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002211 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002212 return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002213 }
2214
2215 @Override
Julia Reynolds924eed12017-01-19 09:52:07 -05002216 public boolean canShowBadge(String pkg, int uid) {
2217 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002218 return mPreferencesHelper.canShowBadge(pkg, uid);
Julia Reynolds924eed12017-01-19 09:52:07 -05002219 }
2220
2221 @Override
2222 public void setShowBadge(String pkg, int uid, boolean showBadge) {
2223 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002224 mPreferencesHelper.setShowBadge(pkg, uid, showBadge);
Julia Reynolds924eed12017-01-19 09:52:07 -05002225 savePolicyFile();
2226 }
2227
2228 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002229 public void updateNotificationChannelGroupForPackage(String pkg, int uid,
2230 NotificationChannelGroup group) throws RemoteException {
2231 enforceSystemOrSystemUI("Caller not system or systemui");
2232 createNotificationChannelGroup(pkg, uid, group, false, false);
2233 savePolicyFile();
2234 }
2235
2236 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002237 public void createNotificationChannelGroups(String pkg,
2238 ParceledListSlice channelGroupList) throws RemoteException {
2239 checkCallerIsSystemOrSameApp(pkg);
2240 List<NotificationChannelGroup> groups = channelGroupList.getList();
2241 final int groupSize = groups.size();
2242 for (int i = 0; i < groupSize; i++) {
2243 final NotificationChannelGroup group = groups.get(i);
Julia Reynolds005c8b92017-08-24 10:35:53 -04002244 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002245 }
2246 savePolicyFile();
2247 }
2248
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002249 private void createNotificationChannelsImpl(String pkg, int uid,
2250 ParceledListSlice channelsList) {
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002251 List<NotificationChannel> channels = channelsList.getList();
2252 final int channelsSize = channels.size();
2253 for (int i = 0; i < channelsSize; i++) {
2254 final NotificationChannel channel = channels.get(i);
2255 Preconditions.checkNotNull(channel, "channel in list is null");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002256 mPreferencesHelper.createNotificationChannel(pkg, uid, channel,
Julia Reynolds1fe10942018-03-28 12:46:51 -04002257 true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed(
2258 pkg, UserHandle.getUserId(uid)));
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002259 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002260 UserHandle.getUserHandleForUid(uid),
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002261 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002262 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002263 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002264 savePolicyFile();
2265 }
2266
2267 @Override
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002268 public void createNotificationChannels(String pkg,
2269 ParceledListSlice channelsList) throws RemoteException {
2270 checkCallerIsSystemOrSameApp(pkg);
2271 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
2272 }
2273
2274 @Override
2275 public void createNotificationChannelsForPackage(String pkg, int uid,
2276 ParceledListSlice channelsList) throws RemoteException {
2277 checkCallerIsSystem();
2278 createNotificationChannelsImpl(pkg, uid, channelsList);
2279 }
2280
2281 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002282 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002283 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002284 return mPreferencesHelper.getNotificationChannel(
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002285 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002286 }
2287
2288 @Override
2289 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002290 String channelId, boolean includeDeleted) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002291 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002292 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002293 }
2294
2295 @Override
2296 public void deleteNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002297 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002298 final int callingUid = Binder.getCallingUid();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002299 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
2300 throw new IllegalArgumentException("Cannot delete default channel");
2301 }
2302 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002303 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002304 mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002305 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002306 UserHandle.getUserHandleForUid(callingUid),
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002307 mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002308 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002309 savePolicyFile();
2310 }
2311
2312 @Override
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002313 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
2314 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002315 return mPreferencesHelper.getNotificationChannelGroupWithChannels(
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002316 pkg, Binder.getCallingUid(), groupId, false);
2317 }
2318
2319 @Override
Julia Reynolds9bfba592017-03-15 14:03:55 -04002320 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
2321 String pkg) {
2322 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002323 return mPreferencesHelper.getNotificationChannelGroups(
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002324 pkg, Binder.getCallingUid(), false, false);
Julia Reynolds9bfba592017-03-15 14:03:55 -04002325 }
2326
2327 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002328 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04002329 checkCallerIsSystemOrSameApp(pkg);
2330
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002331 final int callingUid = Binder.getCallingUid();
2332 NotificationChannelGroup groupToDelete =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002333 mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002334 if (groupToDelete != null) {
2335 List<NotificationChannel> deletedChannels =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002336 mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002337 for (int i = 0; i < deletedChannels.size(); i++) {
2338 final NotificationChannel deletedChannel = deletedChannels.get(i);
2339 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2340 true,
2341 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2342 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002343 mListeners.notifyNotificationChannelChanged(pkg,
2344 UserHandle.getUserHandleForUid(callingUid),
2345 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002346 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2347 }
2348 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002349 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2350 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002351 savePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002352 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04002353 }
2354
2355 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002356 public void updateNotificationChannelForPackage(String pkg, int uid,
2357 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002358 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05002359 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002360 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002361 }
2362
2363 @Override
2364 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002365 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002366 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002367 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002368 }
2369
2370 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002371 public int getNumNotificationChannelsForPackage(String pkg, int uid,
2372 boolean includeDeleted) {
2373 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002374 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted)
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002375 .getList().size();
2376 }
2377
2378 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04002379 public boolean onlyHasDefaultChannel(String pkg, int uid) {
2380 enforceSystemOrSystemUI("onlyHasDefaultChannel");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002381 return mPreferencesHelper.onlyHasDefaultChannel(pkg, uid);
Julia Reynolds17717f52017-05-09 11:46:06 -04002382 }
2383
2384 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04002385 public int getDeletedChannelCount(String pkg, int uid) {
2386 enforceSystemOrSystemUI("getDeletedChannelCount");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002387 return mPreferencesHelper.getDeletedChannelCount(pkg, uid);
Julia Reynolds41103f42017-03-15 11:36:35 -04002388 }
2389
2390 @Override
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002391 public int getBlockedChannelCount(String pkg, int uid) {
2392 enforceSystemOrSystemUI("getBlockedChannelCount");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002393 return mPreferencesHelper.getBlockedChannelCount(pkg, uid);
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002394 }
2395
2396 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002397 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2398 String pkg, int uid, boolean includeDeleted) {
2399 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002400 return mPreferencesHelper.getNotificationChannelGroups(pkg, uid, includeDeleted, true);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002401 }
2402
2403 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002404 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2405 String pkg, int uid, String groupId, boolean includeDeleted) {
2406 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002407 return mPreferencesHelper.getNotificationChannelGroupWithChannels(
Julia Reynolds005c8b92017-08-24 10:35:53 -04002408 pkg, uid, groupId, includeDeleted);
2409 }
2410
2411 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002412 public NotificationChannelGroup getNotificationChannelGroupForPackage(
2413 String groupId, String pkg, int uid) {
2414 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002415 return mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, uid);
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002416 }
2417
2418 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002419 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
2420 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002421 return mPreferencesHelper.getNotificationChannels(
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002422 pkg, Binder.getCallingUid(), false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002423 }
2424
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002425 @Override
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05002426 public ParceledListSlice<NotifyingApp> getRecentNotifyingAppsForUser(int userId) {
2427 checkCallerIsSystem();
2428 synchronized (mNotificationLock) {
2429 List<NotifyingApp> apps = new ArrayList<>(
2430 mRecentApps.getOrDefault(userId, new ArrayList<>()));
2431 return new ParceledListSlice<>(apps);
2432 }
2433 }
2434
2435 @Override
Julia Reynoldse273f082018-04-12 13:48:49 -04002436 public int getBlockedAppCount(int userId) {
2437 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002438 return mPreferencesHelper.getBlockedAppCount(userId);
Julia Reynoldse273f082018-04-12 13:48:49 -04002439 }
2440
2441 @Override
Beverly86d076f2018-04-17 14:44:52 -04002442 public boolean areChannelsBypassingDnd() {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002443 return mPreferencesHelper.areChannelsBypassingDnd();
Beverly86d076f2018-04-17 14:44:52 -04002444 }
2445
2446 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05002447 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002448 checkCallerIsSystem();
2449
2450 // Cancel posted notifications
2451 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2452 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2453
Julia Reynoldsb852e562017-06-06 16:14:18 -04002454 final String[] packages = new String[] {packageName};
2455 final int[] uids = new int[] {uid};
2456
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002457 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04002458 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002459 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002460
2461 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04002462 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002463
2464 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05002465 if (!fromApp) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002466 mPreferencesHelper.onPackagesChanged(
Julia Reynoldsb852e562017-06-06 16:14:18 -04002467 true, UserHandle.getCallingUserId(), packages, uids);
Julia Reynolds5355e852017-02-07 14:54:13 -05002468 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002469
2470 savePolicyFile();
2471 }
2472
2473
Adam Lesinski182f73f2013-12-05 16:48:06 -08002474 /**
2475 * System-only API for getting a list of current (i.e. not cleared) notifications.
2476 *
2477 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04002478 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002479 */
2480 @Override
2481 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2482 // enforce() will ensure the calling uid has the correct permission
2483 getContext().enforceCallingOrSelfPermission(
2484 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2485 "NotificationManagerService.getActiveNotifications");
2486
2487 StatusBarNotification[] tmp = null;
2488 int uid = Binder.getCallingUid();
2489
2490 // noteOp will check to make sure the callingPkg matches the uid
2491 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2492 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002493 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002494 tmp = new StatusBarNotification[mNotificationList.size()];
2495 final int N = mNotificationList.size();
2496 for (int i=0; i<N; i++) {
2497 tmp[i] = mNotificationList.get(i).sbn;
2498 }
2499 }
2500 }
2501 return tmp;
2502 }
2503
2504 /**
Dan Sandler994349c2015-04-15 11:02:54 -04002505 * Public API for getting a list of current notifications for the calling package/uid.
2506 *
Julia Reynolds573c6532017-01-24 17:44:38 -05002507 * Note that since notification posting is done asynchronously, this will not return
2508 * notifications that are in the process of being posted.
2509 *
Dan Sandler994349c2015-04-15 11:02:54 -04002510 * @returns A list of all the package's notifications, in natural order.
2511 */
2512 @Override
2513 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2514 int incomingUserId) {
2515 checkCallerIsSystemOrSameApp(pkg);
2516 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2517 Binder.getCallingUid(), incomingUserId, true, false,
2518 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002519 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002520 final ArrayMap<String, StatusBarNotification> map
2521 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002522 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002523 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002524 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2525 mNotificationList.get(i).sbn);
2526 if (sbn != null) {
2527 map.put(sbn.getKey(), sbn);
2528 }
2529 }
2530 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2531 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2532 if (sbn != null) {
2533 map.put(sbn.getKey(), sbn);
2534 }
2535 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002536 final int M = mEnqueuedNotifications.size();
2537 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002538 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2539 mEnqueuedNotifications.get(i).sbn);
2540 if (sbn != null) {
2541 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04002542 }
2543 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002544 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2545 list.addAll(map.values());
2546 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04002547 }
Dan Sandler994349c2015-04-15 11:02:54 -04002548 }
2549
Chris Wren6676dab2016-12-21 18:26:27 -05002550 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2551 StatusBarNotification sbn) {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04002552 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
Chris Wren6676dab2016-12-21 18:26:27 -05002553 // We could pass back a cloneLight() but clients might get confused and
2554 // try to send this thing back to notify() again, which would not work
2555 // very well.
2556 return new StatusBarNotification(
2557 sbn.getPackageName(),
2558 sbn.getOpPkg(),
Chris Wren6676dab2016-12-21 18:26:27 -05002559 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2560 sbn.getNotification().clone(),
2561 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2562 }
2563 return null;
2564 }
2565
Dan Sandler994349c2015-04-15 11:02:54 -04002566 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002567 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2568 *
2569 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2570 */
2571 @Override
2572 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2573 // enforce() will ensure the calling uid has the correct permission
2574 getContext().enforceCallingOrSelfPermission(
2575 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2576 "NotificationManagerService.getHistoricalNotifications");
2577
2578 StatusBarNotification[] tmp = null;
2579 int uid = Binder.getCallingUid();
2580
2581 // noteOp will check to make sure the callingPkg matches the uid
2582 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2583 == AppOpsManager.MODE_ALLOWED) {
2584 synchronized (mArchive) {
2585 tmp = mArchive.getArray(count);
2586 }
2587 }
2588 return tmp;
2589 }
2590
2591 /**
2592 * Register a listener binder directly with the notification manager.
2593 *
2594 * Only works with system callers. Apps should extend
2595 * {@link android.service.notification.NotificationListenerService}.
2596 */
2597 @Override
2598 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05002599 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02002600 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05002601 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002602 }
2603
2604 /**
2605 * Remove a listener binder directly
2606 */
2607 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002608 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05002609 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002610 }
2611
2612 /**
2613 * Allow an INotificationListener to simulate a "clear all" operation.
2614 *
2615 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2616 *
2617 * @param token The binder for the listener, to check that the caller is allowed
2618 */
2619 @Override
John Spurlocka4294292014-03-24 18:02:32 -04002620 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002621 final int callingUid = Binder.getCallingUid();
2622 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002623 long identity = Binder.clearCallingIdentity();
2624 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002625 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002626 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Beverly5a20a5e2018-03-06 15:02:44 -05002627
John Spurlocka4294292014-03-24 18:02:32 -04002628 if (keys != null) {
2629 final int N = keys.length;
2630 for (int i = 0; i < N; i++) {
2631 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07002632 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00002633 final int userId = r.sbn.getUserId();
2634 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04002635 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00002636 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04002637 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00002638 }
Griff Hazen335e1f02014-09-11 14:49:31 -07002639 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2640 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2641 userId);
John Spurlocka4294292014-03-24 18:02:32 -04002642 }
2643 } else {
2644 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00002645 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04002646 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002647 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002648 } finally {
2649 Binder.restoreCallingIdentity(identity);
2650 }
2651 }
2652
Chris Wrenab41eec2016-01-04 18:01:27 -05002653 /**
2654 * Handle request from an approved listener to re-enable itself.
2655 *
2656 * @param component The componenet to be re-enabled, caller must match package.
2657 */
2658 @Override
2659 public void requestBindListener(ComponentName component) {
2660 checkCallerIsSystemOrSameApp(component.getPackageName());
2661 long identity = Binder.clearCallingIdentity();
2662 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002663 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002664 mAssistants.isComponentEnabledForCurrentProfiles(component)
2665 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05002666 : mListeners;
2667 manager.setComponentState(component, true);
2668 } finally {
2669 Binder.restoreCallingIdentity(identity);
2670 }
2671 }
2672
2673 @Override
2674 public void requestUnbindListener(INotificationListener token) {
2675 long identity = Binder.clearCallingIdentity();
2676 try {
2677 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002678 synchronized (mNotificationLock) {
2679 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2680 info.getOwner().setComponentState(info.component, false);
2681 }
Chris Wrenab41eec2016-01-04 18:01:27 -05002682 } finally {
2683 Binder.restoreCallingIdentity(identity);
2684 }
2685 }
2686
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002687 @Override
2688 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002689 long identity = Binder.clearCallingIdentity();
2690 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002691 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002692 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2693 if (keys != null) {
2694 final int N = keys.length;
2695 for (int i = 0; i < N; i++) {
2696 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2697 if (r == null) continue;
2698 final int userId = r.sbn.getUserId();
2699 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2700 !mUserProfiles.isCurrentProfile(userId)) {
2701 throw new SecurityException("Disallowed call from listener: "
2702 + info.service);
2703 }
2704 if (!r.isSeen()) {
2705 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
Amith Yamasani803eab692017-11-09 17:47:04 -08002706 reportSeen(r);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002707 r.setSeen();
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04002708 maybeRecordInterruptionLocked(r);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002709 }
2710 }
2711 }
2712 }
2713 } finally {
2714 Binder.restoreCallingIdentity(identity);
2715 }
2716 }
2717
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002718 /**
2719 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2720 *
2721 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2722 *
Julia Reynolds79672302017-01-12 08:30:16 -05002723 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002724 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04002725 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04002726 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00002727 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04002728 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -04002729 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
John Spurlocka4294292014-03-24 18:02:32 -04002730 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00002731 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04002732 }
2733
Adam Lesinski182f73f2013-12-05 16:48:06 -08002734 /**
Julia Reynolds79672302017-01-12 08:30:16 -05002735 * Allow an INotificationListener to snooze a single notification until a context.
2736 *
2737 * @param token The binder for the listener, to check that the caller is allowed
2738 */
2739 @Override
2740 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2741 String key, String snoozeCriterionId) {
2742 long identity = Binder.clearCallingIdentity();
2743 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002744 synchronized (mNotificationLock) {
2745 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2746 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2747 }
Julia Reynolds79672302017-01-12 08:30:16 -05002748 } finally {
2749 Binder.restoreCallingIdentity(identity);
2750 }
2751 }
2752
2753 /**
2754 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002755 *
2756 * @param token The binder for the listener, to check that the caller is allowed
2757 */
2758 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002759 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05002760 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002761 long identity = Binder.clearCallingIdentity();
2762 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002763 synchronized (mNotificationLock) {
2764 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2765 snoozeNotificationInt(key, duration, null, info);
2766 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002767 } finally {
2768 Binder.restoreCallingIdentity(identity);
2769 }
2770 }
2771
2772 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002773 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002774 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002775 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002776 */
2777 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002778 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002779 long identity = Binder.clearCallingIdentity();
2780 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002781 synchronized (mNotificationLock) {
2782 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002783 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002784 unsnoozeNotificationInt(key, info);
2785 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002786 } finally {
2787 Binder.restoreCallingIdentity(identity);
2788 }
2789 }
2790
2791 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002792 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2793 *
2794 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2795 *
2796 * @param token The binder for the listener, to check that the caller is allowed
2797 */
2798 @Override
2799 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2800 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002801 final int callingUid = Binder.getCallingUid();
2802 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002803 long identity = Binder.clearCallingIdentity();
2804 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002805 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002806 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00002807 if (info.supportsProfiles()) {
2808 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2809 + "from " + info.component
2810 + " use cancelNotification(key) instead.");
2811 } else {
2812 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2813 pkg, tag, id, info.userid);
2814 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002815 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002816 } finally {
2817 Binder.restoreCallingIdentity(identity);
2818 }
2819 }
2820
2821 /**
2822 * Allow an INotificationListener to request the list of outstanding notifications seen by
2823 * the current user. Useful when starting up, after which point the listener callbacks
2824 * should be used.
2825 *
2826 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002827 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04002828 * @returns The return value will contain the notifications specified in keys, in that
2829 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002830 */
2831 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02002832 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02002833 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002834 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002835 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002836 final boolean getKeys = keys != null;
2837 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02002838 final ArrayList<StatusBarNotification> list
2839 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02002840 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002841 final NotificationRecord r = getKeys
2842 ? mNotificationsByKey.get(keys[i])
2843 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02002844 if (r == null) continue;
2845 StatusBarNotification sbn = r.sbn;
2846 if (!isVisibleToListener(sbn, info)) continue;
2847 StatusBarNotification sbnToSend =
2848 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2849 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002850 }
Christoph Studercee44ba2014-05-20 18:36:43 +02002851 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002852 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002853 }
2854
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002855 /**
2856 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2857 * seen by the current user. Useful when starting up, after which point the listener
2858 * callbacks should be used.
2859 *
2860 * @param token The binder for the listener, to check that the caller is allowed
2861 * @returns The return value will contain the notifications specified in keys, in that
2862 * order, or if keys is null, all the notifications, in natural order.
2863 */
2864 @Override
2865 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2866 INotificationListener token, int trim) {
2867 synchronized (mNotificationLock) {
2868 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2869 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2870 final int N = snoozedRecords.size();
2871 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2872 for (int i=0; i < N; i++) {
2873 final NotificationRecord r = snoozedRecords.get(i);
2874 if (r == null) continue;
2875 StatusBarNotification sbn = r.sbn;
2876 if (!isVisibleToListener(sbn, info)) continue;
2877 StatusBarNotification sbnToSend =
2878 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2879 list.add(sbnToSend);
2880 }
2881 return new ParceledListSlice<>(list);
2882 }
2883 }
2884
Adam Lesinski182f73f2013-12-05 16:48:06 -08002885 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002886 public void requestHintsFromListener(INotificationListener token, int hints) {
2887 final long identity = Binder.clearCallingIdentity();
2888 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002889 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002890 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07002891 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2892 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2893 | HINT_HOST_DISABLE_CALL_EFFECTS;
2894 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04002895 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07002896 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002897 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07002898 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002899 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002900 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04002901 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04002902 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002903 } finally {
2904 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04002905 }
2906 }
2907
2908 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002909 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002910 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002911 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04002912 }
2913 }
2914
2915 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02002916 public void requestInterruptionFilterFromListener(INotificationListener token,
2917 int interruptionFilter) throws RemoteException {
2918 final long identity = Binder.clearCallingIdentity();
2919 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002920 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002921 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2922 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02002923 updateInterruptionFilterLocked();
2924 }
2925 } finally {
2926 Binder.restoreCallingIdentity(identity);
2927 }
2928 }
2929
2930 @Override
2931 public int getInterruptionFilterFromListener(INotificationListener token)
2932 throws RemoteException {
2933 synchronized (mNotificationLight) {
2934 return mInterruptionFilter;
2935 }
2936 }
2937
2938 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02002939 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2940 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002941 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02002942 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2943 if (info == null) return;
2944 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2945 }
2946 }
2947
2948 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002949 public int getZenMode() {
2950 return mZenModeHelper.getZenMode();
2951 }
2952
2953 @Override
John Spurlock056c5192014-04-20 21:52:01 -04002954 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002955 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04002956 return mZenModeHelper.getConfig();
2957 }
2958
2959 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002960 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002961 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05002962 final long identity = Binder.clearCallingIdentity();
2963 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002964 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05002965 } finally {
2966 Binder.restoreCallingIdentity(identity);
2967 }
2968 }
2969
2970 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002971 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002972 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05002973 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002974 }
2975
2976 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002977 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2978 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002979 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002980 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002981 }
2982
2983 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002984 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002985 throws RemoteException {
2986 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2987 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2988 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2989 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002990 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002991
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002992 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2993 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002994 }
2995
2996 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002997 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002998 throws RemoteException {
2999 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
3000 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
3001 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
3002 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
3003 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003004
Julia Reynolds361e82d32016-02-26 18:19:49 -05003005 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003006 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003007 }
3008
3009 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003010 public boolean removeAutomaticZenRule(String id) throws RemoteException {
3011 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003012 // Verify that they can modify zen rules.
3013 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
3014
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003015 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003016 }
3017
3018 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05003019 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
3020 Preconditions.checkNotNull(packageName, "Package name is null");
3021 enforceSystemOrSystemUI("removeAutomaticZenRules");
3022
3023 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
3024 }
3025
3026 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05003027 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
3028 Preconditions.checkNotNull(owner, "Owner is null");
3029 enforceSystemOrSystemUI("getRuleInstanceCount");
3030
3031 return mZenModeHelper.getCurrentInstanceCount(owner);
3032 }
3033
3034 @Override
John Spurlock80774932015-05-07 17:38:50 -04003035 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
3036 enforcePolicyAccess(pkg, "setInterruptionFilter");
3037 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
3038 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
3039 final long identity = Binder.clearCallingIdentity();
3040 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04003041 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04003042 } finally {
3043 Binder.restoreCallingIdentity(identity);
3044 }
3045 }
3046
3047 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04003048 public void notifyConditions(final String pkg, IConditionProvider provider,
3049 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04003050 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3051 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04003052 mHandler.post(new Runnable() {
3053 @Override
3054 public void run() {
3055 mConditionProviders.notifyConditions(pkg, info, conditions);
3056 }
3057 });
John Spurlocke77bb362014-04-26 10:24:59 -04003058 }
3059
Julia Reynolds38e6ca42016-08-08 08:38:09 -04003060 @Override
3061 public void requestUnbindProvider(IConditionProvider provider) {
3062 long identity = Binder.clearCallingIdentity();
3063 try {
3064 // allow bound services to disable themselves
3065 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3066 info.getOwner().setComponentState(info.component, false);
3067 } finally {
3068 Binder.restoreCallingIdentity(identity);
3069 }
3070 }
3071
3072 @Override
3073 public void requestBindProvider(ComponentName component) {
3074 checkCallerIsSystemOrSameApp(component.getPackageName());
3075 long identity = Binder.clearCallingIdentity();
3076 try {
3077 mConditionProviders.setComponentState(component, true);
3078 } finally {
3079 Binder.restoreCallingIdentity(identity);
3080 }
3081 }
3082
John Spurlocke77bb362014-04-26 10:24:59 -04003083 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003084 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04003085 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
3086 message);
John Spurlock7340fc82014-04-24 18:50:12 -04003087 }
3088
Julia Reynolds48034f82016-03-09 10:15:16 -05003089 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
3090 try {
3091 checkCallerIsSystemOrSameApp(pkg);
3092 } catch (SecurityException e) {
3093 getContext().enforceCallingPermission(
3094 android.Manifest.permission.STATUS_BAR_SERVICE,
3095 message);
3096 }
3097 }
3098
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003099 private void enforcePolicyAccess(int uid, String method) {
3100 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3101 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3102 return;
3103 }
3104 boolean accessAllowed = false;
3105 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
3106 final int packageCount = packages.length;
3107 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003108 if (mConditionProviders.isPackageOrComponentAllowed(
3109 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003110 accessAllowed = true;
3111 }
3112 }
3113 if (!accessAllowed) {
3114 Slog.w(TAG, "Notification policy access denied calling " + method);
3115 throw new SecurityException("Notification policy access denied");
3116 }
3117 }
3118
John Spurlock80774932015-05-07 17:38:50 -04003119 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04003120 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3121 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3122 return;
3123 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04003124 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003125 if (!checkPolicyAccess(pkg)) {
3126 Slog.w(TAG, "Notification policy access denied calling " + method);
3127 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04003128 }
3129 }
3130
John Spurlock80774932015-05-07 17:38:50 -04003131 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003132 return mConditionProviders.isPackageOrComponentAllowed(
3133 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04003134 }
3135
3136 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003137 try {
Jason Parks50322ff2018-03-27 10:23:33 -05003138 int uid = getContext().getPackageManager().getPackageUidAsUser(pkg,
3139 UserHandle.getCallingUserId());
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003140 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
3141 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
3142 -1, true)) {
3143 return true;
3144 }
3145 } catch (NameNotFoundException e) {
3146 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003147 }
Jason Parks50322ff2018-03-27 10:23:33 -05003148 return checkPackagePolicyAccess(pkg)
3149 || mListeners.isComponentEnabledForPackage(pkg)
3150 || (mDpm != null &&
3151 mDpm.isActiveAdminWithPolicy(Binder.getCallingUid(),
3152 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER));
John Spurlock1fc476d2015-04-14 16:05:20 -04003153 }
3154
John Spurlock7340fc82014-04-24 18:50:12 -04003155 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08003156 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003157 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04003158 final DumpFilter filter = DumpFilter.parseFromArguments(args);
Makoto Onukibbb4b222018-06-25 16:01:02 -07003159 final long token = Binder.clearCallingIdentity();
3160 try {
3161 if (filter.stats) {
3162 dumpJson(pw, filter);
3163 } else if (filter.proto) {
3164 dumpProto(fd, filter);
3165 } else if (filter.criticalPriority) {
3166 dumpNotificationRecords(pw, filter);
3167 } else {
3168 dumpImpl(pw, filter);
3169 }
3170 } finally {
3171 Binder.restoreCallingIdentity(token);
Chris Wrene4b38802015-07-07 15:54:19 -04003172 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003173 }
John Spurlockb4782522014-08-22 14:54:46 -04003174
3175 @Override
3176 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07003177 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04003178 }
John Spurlock2b122f42014-08-27 16:29:47 -04003179
3180 @Override
3181 public boolean matchesCallFilter(Bundle extras) {
3182 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02003183 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003184 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02003185 extras,
3186 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
3187 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
3188 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04003189 }
John Spurlock530052a2014-11-30 16:26:19 -05003190
3191 @Override
3192 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003193 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04003194 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05003195 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003196
Christopher Tatef9767d62015-04-08 14:35:43 -07003197 // Backup/restore interface
3198 @Override
3199 public byte[] getBackupPayload(int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003200 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003201 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003202 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003203 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003204 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
3205 return null;
3206 }
songjinshi9bf22712017-02-04 10:47:45 +08003207 synchronized(mPolicyFile) {
3208 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
3209 try {
3210 writePolicyXml(baos, true /*forBackup*/);
3211 return baos.toByteArray();
3212 } catch (IOException e) {
3213 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
3214 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003215 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003216 return null;
3217 }
3218
3219 @Override
3220 public void applyRestore(byte[] payload, int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003221 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003222 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
3223 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
3224 if (payload == null) {
3225 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
3226 return;
3227 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003228 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003229 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003230 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
3231 return;
3232 }
songjinshi9bf22712017-02-04 10:47:45 +08003233 synchronized(mPolicyFile) {
3234 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
3235 try {
3236 readPolicyXml(bais, true /*forRestore*/);
3237 savePolicyFile();
3238 } catch (NumberFormatException | XmlPullParserException | IOException e) {
3239 Slog.w(TAG, "applyRestore: error reading payload", e);
3240 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003241 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003242 }
3243
John Spurlock1fc476d2015-04-14 16:05:20 -04003244 @Override
John Spurlock80774932015-05-07 17:38:50 -04003245 public boolean isNotificationPolicyAccessGranted(String pkg) {
3246 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04003247 }
3248
3249 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05003250 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
3251 enforceSystemOrSystemUIOrSamePackage(pkg,
3252 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003253 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003254 }
3255
3256 @Override
John Spurlock80774932015-05-07 17:38:50 -04003257 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
3258 throws RemoteException {
Julia Reynolds92febc32017-10-26 11:30:31 -04003259 setNotificationPolicyAccessGrantedForUser(
3260 pkg, getCallingUserHandle().getIdentifier(), granted);
3261 }
3262
3263 @Override
3264 public void setNotificationPolicyAccessGrantedForUser(
3265 String pkg, int userId, boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003266 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003267 final long identity = Binder.clearCallingIdentity();
3268 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003269 if (mAllowedManagedServicePackages.test(pkg)) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003270 mConditionProviders.setPackageOrComponentEnabled(
Julia Reynolds92febc32017-10-26 11:30:31 -04003271 pkg, userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003272
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003273 getContext().sendBroadcastAsUser(new Intent(
3274 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3275 .setPackage(pkg)
3276 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003277 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003278 savePolicyFile();
3279 }
3280 } finally {
3281 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003282 }
John Spurlock80774932015-05-07 17:38:50 -04003283 }
3284
3285 @Override
3286 public Policy getNotificationPolicy(String pkg) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003287 final long identity = Binder.clearCallingIdentity();
3288 try {
3289 return mZenModeHelper.getNotificationPolicy();
3290 } finally {
3291 Binder.restoreCallingIdentity(identity);
3292 }
3293 }
3294
Beverly6697eff2017-12-14 15:00:27 -05003295 /**
3296 * Sets the notification policy. Apps that target API levels below
Beverly98ef61b2018-02-15 10:36:28 -05003297 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
Beverlyd6964762018-02-16 14:07:03 -05003298 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3299 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3300 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
Beverly6697eff2017-12-14 15:00:27 -05003301 */
John Spurlock1fc476d2015-04-14 16:05:20 -04003302 @Override
John Spurlock80774932015-05-07 17:38:50 -04003303 public void setNotificationPolicy(String pkg, Policy policy) {
3304 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04003305 final long identity = Binder.clearCallingIdentity();
3306 try {
Beverly6697eff2017-12-14 15:00:27 -05003307 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3308 0, UserHandle.getUserId(MY_UID));
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003309 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
Beverly6697eff2017-12-14 15:00:27 -05003310
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06003311 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
Beverly98ef61b2018-02-15 10:36:28 -05003312 int priorityCategories = policy.priorityCategories;
3313 // ignore alarm and media values from new policy
3314 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
Beverlyd6964762018-02-16 14:07:03 -05003315 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3316 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003317 // use user-designated values
Beverlyd6964762018-02-16 14:07:03 -05003318 priorityCategories |= currPolicy.priorityCategories
3319 & Policy.PRIORITY_CATEGORY_ALARMS;
3320 priorityCategories |= currPolicy.priorityCategories
3321 & Policy.PRIORITY_CATEGORY_MEDIA;
3322 priorityCategories |= currPolicy.priorityCategories
3323 & Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003324
Beverly6697eff2017-12-14 15:00:27 -05003325 policy = new Policy(priorityCategories,
3326 policy.priorityCallSenders, policy.priorityMessageSenders,
3327 policy.suppressedVisualEffects);
3328 }
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003329 int newVisualEffects = calculateSuppressedVisualEffects(
3330 policy, currPolicy, applicationInfo.targetSdkVersion);
3331 policy = new Policy(policy.priorityCategories,
3332 policy.priorityCallSenders, policy.priorityMessageSenders,
3333 newVisualEffects);
Beverly5e073222018-03-08 10:36:25 -05003334 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
John Spurlock1fc476d2015-04-14 16:05:20 -04003335 mZenModeHelper.setNotificationPolicy(policy);
Beverly6697eff2017-12-14 15:00:27 -05003336 } catch (RemoteException e) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003337 } finally {
3338 Binder.restoreCallingIdentity(identity);
3339 }
3340 }
Chris Wren51017d02015-12-15 15:34:46 -05003341
3342 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003343 public List<String> getEnabledNotificationListenerPackages() {
3344 checkCallerIsSystem();
3345 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3346 }
3347
3348 @Override
3349 public List<ComponentName> getEnabledNotificationListeners(int userId) {
3350 checkCallerIsSystem();
3351 return mListeners.getAllowedComponents(userId);
3352 }
3353
3354 @Override
3355 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3356 Preconditions.checkNotNull(listener);
3357 checkCallerIsSystemOrSameApp(listener.getPackageName());
3358 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3359 getCallingUserHandle().getIdentifier());
3360 }
3361
3362 @Override
3363 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3364 int userId) {
3365 Preconditions.checkNotNull(listener);
3366 checkCallerIsSystem();
3367 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3368 userId);
3369 }
3370
3371 @Override
3372 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3373 Preconditions.checkNotNull(assistant);
3374 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003375 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04003376 getCallingUserHandle().getIdentifier());
3377 }
3378
3379 @Override
3380 public void setNotificationListenerAccessGranted(ComponentName listener,
3381 boolean granted) throws RemoteException {
3382 setNotificationListenerAccessGrantedForUser(
3383 listener, getCallingUserHandle().getIdentifier(), granted);
3384 }
3385
3386 @Override
3387 public void setNotificationAssistantAccessGranted(ComponentName assistant,
3388 boolean granted) throws RemoteException {
3389 setNotificationAssistantAccessGrantedForUser(
3390 assistant, getCallingUserHandle().getIdentifier(), granted);
3391 }
3392
3393 @Override
3394 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3395 boolean granted) throws RemoteException {
3396 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04003397 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003398 final long identity = Binder.clearCallingIdentity();
3399 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003400 if (mAllowedManagedServicePackages.test(listener.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003401 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3402 userId, false, granted);
3403 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3404 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003405
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003406 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds92febc32017-10-26 11:30:31 -04003407 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003408 .setPackage(listener.getPackageName())
3409 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003410 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003411
3412 savePolicyFile();
3413 }
3414 } finally {
3415 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003416 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003417 }
3418
3419 @Override
3420 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3421 int userId, boolean granted) throws RemoteException {
3422 Preconditions.checkNotNull(assistant);
Julia Reynolds0d217642017-08-11 11:26:04 -04003423 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003424 final long identity = Binder.clearCallingIdentity();
3425 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003426 if (mAllowedManagedServicePackages.test(assistant.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003427 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
3428 userId, false, granted);
3429 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
3430 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003431
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003432 getContext().sendBroadcastAsUser(new Intent(
3433 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3434 .setPackage(assistant.getPackageName())
3435 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003436 UserHandle.of(userId), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003437
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003438 savePolicyFile();
3439 }
3440 } finally {
3441 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003442 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003443 }
3444
3445 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003446 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003447 Adjustment adjustment) {
3448 boolean foundEnqueued = false;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003449 final long identity = Binder.clearCallingIdentity();
3450 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003451 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003452 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003453 int N = mEnqueuedNotifications.size();
3454 for (int i = 0; i < N; i++) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003455 final NotificationRecord r = mEnqueuedNotifications.get(i);
3456 if (Objects.equals(adjustment.getKey(), r.getKey())
Julia Reynolds70aaea72018-07-13 13:38:34 -04003457 && Objects.equals(adjustment.getUser(), r.getUserId())
3458 && mAssistants.isSameUser(token, r.getUserId())) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003459 applyAdjustment(r, adjustment);
3460 r.applyAdjustments();
3461 foundEnqueued = true;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003462 break;
3463 }
3464 }
Julia Reynolds666ccf02018-06-18 10:19:20 -04003465 if (!foundEnqueued) {
3466 // adjustment arrived too late to apply to enqueued; apply to posted
3467 applyAdjustmentFromAssistant(token, adjustment);
3468 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003469 }
3470 } finally {
3471 Binder.restoreCallingIdentity(identity);
3472 }
3473 }
3474
3475 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003476 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003477 Adjustment adjustment) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003478 List<Adjustment> adjustments = new ArrayList<>();
3479 adjustments.add(adjustment);
3480 applyAdjustmentsFromAssistant(token, adjustments);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003481 }
3482
3483 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003484 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003485 List<Adjustment> adjustments) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003486
3487 final long identity = Binder.clearCallingIdentity();
3488 try {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003489 boolean appliedAdjustment = false;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003490 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003491 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003492 for (Adjustment adjustment : adjustments) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003493 NotificationRecord r = mNotificationsByKey.get(adjustment.getKey());
3494 if (r != null && mAssistants.isSameUser(token, r.getUserId())) {
3495 applyAdjustment(r, adjustment);
3496 appliedAdjustment = true;
3497 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003498 }
3499 }
Julia Reynolds70aaea72018-07-13 13:38:34 -04003500 if (appliedAdjustment) {
3501 mRankingHandler.requestSort();
3502 }
Chris Wren51017d02015-12-15 15:34:46 -05003503 } finally {
3504 Binder.restoreCallingIdentity(identity);
3505 }
3506 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003507
3508 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04003509 public void updateNotificationChannelGroupFromPrivilegedListener(
3510 INotificationListener token, String pkg, UserHandle user,
3511 NotificationChannelGroup group) throws RemoteException {
3512 Preconditions.checkNotNull(user);
3513 verifyPrivilegedListener(token, user);
3514 createNotificationChannelGroup(
3515 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
3516 savePolicyFile();
3517 }
3518
3519 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003520 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003521 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003522 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003523 Preconditions.checkNotNull(pkg);
3524 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003525
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003526 verifyPrivilegedListener(token, user);
3527 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003528 }
3529
3530 @Override
3531 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003532 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3533 Preconditions.checkNotNull(pkg);
3534 Preconditions.checkNotNull(user);
3535 verifyPrivilegedListener(token, user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003536
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003537 return mPreferencesHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003538 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003539 }
3540
3541 @Override
3542 public ParceledListSlice<NotificationChannelGroup>
3543 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003544 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3545 Preconditions.checkNotNull(pkg);
3546 Preconditions.checkNotNull(user);
3547 verifyPrivilegedListener(token, user);
3548
3549 List<NotificationChannelGroup> groups = new ArrayList<>();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003550 groups.addAll(mPreferencesHelper.getNotificationChannelGroups(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003551 pkg, getUidForPackageAndUser(pkg, user)));
3552 return new ParceledListSlice<>(groups);
3553 }
3554
3555 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003556 ManagedServiceInfo info;
3557 synchronized (mNotificationLock) {
3558 info = mListeners.checkServiceTokenLocked(token);
3559 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003560 if (!hasCompanionDevice(info)) {
3561 throw new SecurityException(info + " does not have access");
3562 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003563 if (!info.enabledAndUserMatches(user.getIdentifier())) {
3564 throw new SecurityException(info + " does not have access");
3565 }
3566 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003567
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003568 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3569 int uid = 0;
3570 long identity = Binder.clearCallingIdentity();
3571 try {
3572 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3573 } finally {
3574 Binder.restoreCallingIdentity(identity);
3575 }
3576 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003577 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003578
3579 @Override
3580 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3581 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3582 throws RemoteException {
3583 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3584 }
John Spurlock1fc476d2015-04-14 16:05:20 -04003585 };
John Spurlocka4294292014-03-24 18:02:32 -04003586
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003587 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3588 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003589 return;
3590 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003591 if (adjustment.getSignals() != null) {
3592 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003593 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003594 }
3595 }
3596
Julia Reynolds88860ce2017-06-01 16:55:49 -04003597 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003598 void addAutogroupKeyLocked(String key) {
3599 NotificationRecord r = mNotificationsByKey.get(key);
3600 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003601 return;
3602 }
Julia Reynolds51710712017-07-19 13:48:07 -04003603 if (r.sbn.getOverrideGroupKey() == null) {
3604 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3605 EventLogTags.writeNotificationAutogrouped(key);
3606 mRankingHandler.requestSort();
3607 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003608 }
3609
Julia Reynolds88860ce2017-06-01 16:55:49 -04003610 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003611 void removeAutogroupKeyLocked(String key) {
3612 NotificationRecord r = mNotificationsByKey.get(key);
3613 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003614 return;
3615 }
Julia Reynolds51710712017-07-19 13:48:07 -04003616 if (r.sbn.getOverrideGroupKey() != null) {
3617 addAutoGroupAdjustment(r, null);
3618 EventLogTags.writeNotificationUnautogrouped(key);
3619 mRankingHandler.requestSort();
3620 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003621 }
3622
3623 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3624 Bundle signals = new Bundle();
3625 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3626 Adjustment adjustment =
3627 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3628 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003629 }
3630
3631 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04003632 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04003633 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3634 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3635 if (summaries != null && summaries.containsKey(pkg)) {
3636 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003637 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04003638 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04003639 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003640 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003641 }
3642 }
3643 }
3644
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003645 @GuardedBy("mNotificationLock")
3646 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3647 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3648 return summaries != null && summaries.containsKey(sbn.getPackageName());
3649 }
3650
Julia Reynoldse46bb372016-03-17 11:05:58 -04003651 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04003652 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3653 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003654 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003655 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3656 if (notificationRecord == null) {
3657 // The notification could have been cancelled again already. A successive
3658 // adjustment will post a summary if needed.
3659 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003660 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003661 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3662 userId = adjustedSbn.getUser().getIdentifier();
3663 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3664 if (summaries == null) {
3665 summaries = new ArrayMap<>();
3666 }
3667 mAutobundledSummaries.put(userId, summaries);
3668 if (!summaries.containsKey(pkg)) {
3669 // Add summary
3670 final ApplicationInfo appInfo =
3671 adjustedSbn.getNotification().extras.getParcelable(
3672 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3673 final Bundle extras = new Bundle();
3674 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003675 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04003676 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003677 new Notification.Builder(getContext(), channelId)
3678 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04003679 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04003680 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04003681 .setGroup(GroupHelper.AUTOGROUP_KEY)
3682 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3683 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3684 .setColor(adjustedSbn.getNotification().color)
3685 .setLocalOnly(true)
3686 .build();
3687 summaryNotification.extras.putAll(extras);
3688 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3689 if (appIntent != null) {
3690 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3691 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3692 }
3693 final StatusBarNotification summarySbn =
3694 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003695 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003696 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04003697 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3698 adjustedSbn.getInitialPid(), summaryNotification,
3699 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3700 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05003701 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003702 notificationRecord.getChannel());
Rohan Shah590e1b22018-04-10 23:48:47 -04003703 summaryRecord.setIsAppImportanceLocked(
3704 notificationRecord.getIsAppImportanceLocked());
Julia Reynolds8f488d32016-10-14 10:59:01 -04003705 summaries.put(pkg, summarySbn.getKey());
3706 }
3707 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003708 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04003709 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003710 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04003711 }
3712 }
3713
John Spurlock32fe4c62014-10-02 12:16:02 -04003714 private String disableNotificationEffects(NotificationRecord record) {
3715 if (mDisableNotificationEffects) {
3716 return "booleanState";
3717 }
3718 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3719 return "listenerHints";
3720 }
3721 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3722 return "callState";
3723 }
3724 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04003725 };
3726
Kweku Adams887f09c2017-11-13 17:12:20 -08003727 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
Chris Wrene4b38802015-07-07 15:54:19 -04003728 JSONObject dump = new JSONObject();
3729 try {
3730 dump.put("service", "Notification Manager");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003731 dump.put("bans", mPreferencesHelper.dumpBansJson(filter));
3732 dump.put("ranking", mPreferencesHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003733 dump.put("stats", mUsageStats.dumpJson(filter));
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003734 dump.put("channels", mPreferencesHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003735 } catch (JSONException e) {
3736 e.printStackTrace();
3737 }
3738 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04003739 }
3740
Kweku Adams887f09c2017-11-13 17:12:20 -08003741 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003742 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3743 synchronized (mNotificationLock) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003744 int N = mNotificationList.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003745 for (int i = 0; i < N; i++) {
3746 final NotificationRecord nr = mNotificationList.get(i);
3747 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3748 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3749 NotificationRecordProto.POSTED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003750 }
3751 N = mEnqueuedNotifications.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003752 for (int i = 0; i < N; i++) {
3753 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3754 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3755 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3756 NotificationRecordProto.ENQUEUED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003757 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003758 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3759 N = snoozed.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003760 for (int i = 0; i < N; i++) {
3761 final NotificationRecord nr = snoozed.get(i);
3762 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3763 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3764 NotificationRecordProto.SNOOZED);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003765 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003766
Kweku Adams93304b62017-09-20 17:03:00 -07003767 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3768 mZenModeHelper.dump(proto);
3769 for (ComponentName suppressor : mEffectsSuppressors) {
Kweku Adams99546332018-01-24 17:03:50 -08003770 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
Kweku Adams93304b62017-09-20 17:03:00 -07003771 }
3772 proto.end(zenLog);
3773
3774 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
3775 mListeners.dump(proto, filter);
3776 proto.end(listenersToken);
3777
3778 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
3779
3780 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
3781 long effectsToken = proto.start(
3782 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
3783
3784 proto.write(
3785 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
3786 final ArraySet<ManagedServiceInfo> listeners =
3787 mListenersDisablingEffects.valueAt(i);
3788 for (int j = 0; j < listeners.size(); j++) {
3789 final ManagedServiceInfo listener = listeners.valueAt(i);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08003790 listener.writeToProto(proto, ListenersDisablingEffectsProto.LISTENERS, null);
Kweku Adams93304b62017-09-20 17:03:00 -07003791 }
3792
3793 proto.end(effectsToken);
3794 }
3795
3796 long assistantsToken = proto.start(
3797 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
3798 mAssistants.dump(proto, filter);
3799 proto.end(assistantsToken);
3800
3801 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
3802 mConditionProviders.dump(proto, filter);
3803 proto.end(conditionsToken);
Kweku Adams62b42242017-09-25 12:54:02 -07003804
3805 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
3806 mRankingHelper.dump(proto, filter);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003807 mPreferencesHelper.dump(proto, filter);
Kweku Adams62b42242017-09-25 12:54:02 -07003808 proto.end(rankingToken);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003809 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003810
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003811 proto.flush();
3812 }
3813
Vishnu Naire3e4d252018-03-01 11:26:57 -08003814 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
3815 synchronized (mNotificationLock) {
3816 int N;
3817 N = mNotificationList.size();
3818 if (N > 0) {
3819 pw.println(" Notification List:");
3820 for (int i = 0; i < N; i++) {
3821 final NotificationRecord nr = mNotificationList.get(i);
3822 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3823 nr.dump(pw, " ", getContext(), filter.redact);
3824 }
3825 pw.println(" ");
3826 }
3827 }
3828 }
3829
Kweku Adams887f09c2017-11-13 17:12:20 -08003830 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
John Spurlock25e2d242014-06-27 13:58:23 -04003831 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04003832 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003833 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04003834 }
3835 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08003836 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003837 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003838
John Spurlock50806fc2014-07-15 10:22:02 -04003839 if (!zenOnly) {
3840 synchronized (mToastQueue) {
3841 N = mToastQueue.size();
3842 if (N > 0) {
3843 pw.println(" Toast Queue:");
3844 for (int i=0; i<N; i++) {
3845 mToastQueue.get(i).dump(pw, " ", filter);
3846 }
3847 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003848 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003849 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003850 }
3851
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003852 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04003853 if (!zenOnly) {
Vishnu Naire3e4d252018-03-01 11:26:57 -08003854 // Priority filters are only set when called via bugreport. If set
3855 // skip sections that are part of the critical section.
3856 if (!filter.normalPriority) {
3857 dumpNotificationRecords(pw, filter);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003858 }
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003859 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003860 N = mLights.size();
3861 if (N > 0) {
3862 pw.println(" Lights List:");
3863 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05003864 if (i == N - 1) {
3865 pw.print(" > ");
3866 } else {
3867 pw.print(" ");
3868 }
3869 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04003870 }
3871 pw.println(" ");
3872 }
John Spurlockcb566aa2014-08-03 22:58:28 -04003873 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
Julia Reynolds28149f62018-07-03 10:43:35 -04003874 pw.println(" mHasLight=" + mHasLight);
John Spurlockcb566aa2014-08-03 22:58:28 -04003875 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05003876 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3877 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003878 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04003879 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04003880 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04003881 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04003882 }
3883 pw.println(" mArchive=" + mArchive.toString());
3884 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003885 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04003886 while (iter.hasNext()) {
3887 final StatusBarNotification sbn = iter.next();
3888 if (filter != null && !filter.matches(sbn)) continue;
3889 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003890 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04003891 if (iter.hasNext()) pw.println(" ...");
3892 break;
3893 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003894 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003895
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003896 if (!zenOnly) {
3897 N = mEnqueuedNotifications.size();
3898 if (N > 0) {
3899 pw.println(" Enqueued Notification List:");
3900 for (int i = 0; i < N; i++) {
3901 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3902 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3903 nr.dump(pw, " ", getContext(), filter.redact);
3904 }
3905 pw.println(" ");
3906 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003907
3908 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003909 }
3910 }
3911
John Spurlock50806fc2014-07-15 10:22:02 -04003912 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04003913 pw.println("\n Ranking Config:");
3914 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04003915
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003916 pw.println("\n Notification Preferences:");
3917 mPreferencesHelper.dump(pw, " ", filter);
3918
John Spurlock50806fc2014-07-15 10:22:02 -04003919 pw.println("\n Notification listeners:");
3920 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003921 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3922 pw.print(" mListenersDisablingEffects: (");
3923 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04003924 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003925 final int hint = mListenersDisablingEffects.keyAt(i);
3926 if (i > 0) pw.print(';');
3927 pw.print("hint[" + hint + "]:");
3928
3929 final ArraySet<ManagedServiceInfo> listeners =
3930 mListenersDisablingEffects.valueAt(i);
3931 final int listenerSize = listeners.size();
3932
3933 for (int j = 0; j < listenerSize; j++) {
3934 if (i > 0) pw.print(',');
3935 final ManagedServiceInfo listener = listeners.valueAt(i);
Julia Reynolds1f580572018-04-27 14:48:36 -04003936 if (listener != null) {
3937 pw.print(listener.component);
3938 }
Bryce Lee7219ada2016-04-08 10:54:23 -07003939 }
John Spurlock1fa865f2014-07-21 14:56:39 -04003940 }
3941 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05003942 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003943 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04003944 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003945
Julia Reynolds520df6e2017-02-13 09:05:10 -05003946 if (!filter.filtered || zenOnly) {
3947 pw.println("\n Zen Mode:");
3948 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3949 mZenModeHelper.dump(pw, " ");
3950
3951 pw.println("\n Zen Log:");
3952 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003953 }
3954
John Spurlocke77bb362014-04-26 10:24:59 -04003955 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04003956 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02003957
3958 pw.println("\n Group summaries:");
3959 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3960 NotificationRecord r = entry.getValue();
3961 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3962 if (mNotificationsByKey.get(r.getKey()) != r) {
3963 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04003964 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02003965 }
3966 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003967
3968 if (!zenOnly) {
3969 pw.println("\n Usage Stats:");
3970 mUsageStats.dump(pw, " ", filter);
3971 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003972 }
3973 }
3974
Adam Lesinski182f73f2013-12-05 16:48:06 -08003975 /**
3976 * The private API only accessible to the system process.
3977 */
3978 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3979 @Override
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04003980 public NotificationChannel getNotificationChannel(String pkg, int uid, String
3981 channelId) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003982 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false);
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04003983 }
3984
3985 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003986 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003987 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003988 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003989 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003990 }
Christoph Studer365e4c32014-09-18 20:35:36 +02003991
3992 @Override
3993 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3994 int userId) {
3995 checkCallerIsSystem();
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003996 mHandler.post(new Runnable() {
3997 @Override
3998 public void run() {
3999 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04004000 removeForegroundServiceFlagByListLocked(
4001 mEnqueuedNotifications, pkg, notificationId, userId);
4002 removeForegroundServiceFlagByListLocked(
4003 mNotificationList, pkg, notificationId, userId);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004004 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004005 }
4006 });
4007 }
4008
Julia Reynolds88860ce2017-06-01 16:55:49 -04004009 @GuardedBy("mNotificationLock")
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004010 private void removeForegroundServiceFlagByListLocked(
Julia Reynolds88860ce2017-06-01 16:55:49 -04004011 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
4012 int userId) {
4013 NotificationRecord r = findNotificationByListLocked(
4014 notificationList, pkg, null, notificationId, userId);
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004015 if (r == null) {
4016 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02004017 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004018 StatusBarNotification sbn = r.sbn;
4019 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
4020 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
4021 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
4022 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
4023 sbn.getNotification().flags =
Julia Reynoldse5c60452018-04-30 14:41:36 -04004024 (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004025 mRankingHelper.sort(mNotificationList);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06004026 mListeners.notifyPostedLocked(r, r);
Christoph Studer365e4c32014-09-18 20:35:36 +02004027 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004028 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004029
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004030 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04004031 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004032 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04004033 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08004034 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
4035 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04004036 }
John Spurlock7340fc82014-04-24 18:50:12 -04004037 checkCallerIsSystemOrSameApp(pkg);
Brad Stenning8c991ea2018-07-31 13:33:01 -07004038 checkRestrictedCategories(notification);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004039
Scott Greenwald9b05c612013-06-25 23:44:05 -04004040 final int userId = ActivityManager.handleIncomingUser(callingPid,
4041 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
Jeff Sharkey65c4a2b2012-09-25 17:22:27 -07004042 final UserHandle user = new UserHandle(userId);
Dianne Hackborn41203752012-08-31 14:05:51 -07004043
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004044 if (pkg == null || notification == null) {
4045 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
4046 + " id=" + id + " notification=" + notification);
4047 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004048
4049 // The system can post notifications for any package, let us resolve that.
4050 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
4051
Julia Reynoldse46bb372016-03-17 11:05:58 -04004052 // Fix the notification as best we can.
4053 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004054 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06004055 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
Julia Reynoldse0d711f2017-09-01 08:50:47 -04004056 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
Julia Reynoldse071abd2017-03-22 10:52:11 -04004057 Notification.addFieldsFromContext(ai, notification);
Julia Reynolds4db59552017-06-30 13:34:01 -04004058
4059 int canColorize = mPackageManagerClient.checkPermission(
4060 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
4061 if (canColorize == PERMISSION_GRANTED) {
4062 notification.flags |= Notification.FLAG_CAN_COLORIZE;
4063 } else {
4064 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
4065 }
4066
Julia Reynoldse46bb372016-03-17 11:05:58 -04004067 } catch (NameNotFoundException e) {
4068 Slog.e(TAG, "Cannot create a context for sending app", e);
4069 return;
4070 }
4071
Chris Wren888b7a82016-06-17 15:47:19 -04004072 mUsageStats.registerEnqueuedByApp(pkg);
4073
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004074 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04004075 String channelId = notification.getChannelId();
4076 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
4077 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05004078 }
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004079 final NotificationChannel channel = mPreferencesHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004080 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004081 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004082 final String noChannelStr = "No Channel found for "
4083 + "pkg=" + pkg
4084 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04004085 + ", id=" + id
4086 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004087 + ", opPkg=" + opPkg
4088 + ", callingUid=" + callingUid
4089 + ", userId=" + userId
4090 + ", incomingUserId=" + incomingUserId
4091 + ", notificationUid=" + notificationUid
4092 + ", notification=" + notification;
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004093 Log.e(TAG, noChannelStr);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004094 boolean appNotificationsOff = mPreferencesHelper.getImportance(pkg, notificationUid)
Beverly5d4564b2018-04-10 20:09:23 -04004095 == NotificationManager.IMPORTANCE_NONE;
4096
4097 if (!appNotificationsOff) {
4098 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
4099 "Failed to post notification on channel \"" + channelId + "\"\n" +
4100 "See log for more details");
4101 }
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004102 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004103 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004104
Chris Wrena61f1792016-08-04 11:24:42 -04004105 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004106 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004107 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004108 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004109 r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
Chris Wrena61f1792016-08-04 11:24:42 -04004110
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004111 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4112 final boolean fgServiceShown = channel.isFgServiceShown();
4113 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
4114 || !fgServiceShown)
4115 && (r.getImportance() == IMPORTANCE_MIN
4116 || r.getImportance() == IMPORTANCE_NONE)) {
4117 // Increase the importance of foreground service notifications unless the user had
4118 // an opinion otherwise (and the channel hasn't yet shown a fg service).
4119 if (TextUtils.isEmpty(channelId)
4120 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4121 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
4122 } else {
4123 channel.setImportance(IMPORTANCE_LOW);
4124 if (!fgServiceShown) {
4125 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
4126 channel.setFgServiceShown(true);
4127 }
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004128 mPreferencesHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004129 r.updateNotificationChannel(channel);
4130 }
4131 } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
4132 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4133 channel.setFgServiceShown(true);
Julia Reynolds8617e4e2017-09-18 16:52:37 -04004134 r.updateNotificationChannel(channel);
4135 }
4136 }
4137
Julia Reynolds5e702192017-08-18 09:22:40 -04004138 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
4139 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004140 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07004141 }
4142
Felipe Lemedd85da62016-06-28 11:29:54 -07004143 // Whitelist pending intents.
4144 if (notification.allPendingIntents != null) {
4145 final int intentCount = notification.allPendingIntents.size();
4146 if (intentCount > 0) {
4147 final ActivityManagerInternal am = LocalServices
4148 .getService(ActivityManagerInternal.class);
4149 final long duration = LocalServices.getService(
4150 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
4151 for (int i = 0; i < intentCount; i++) {
4152 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4153 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07004154 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4155 WHITELIST_TOKEN, duration);
Felipe Lemedd85da62016-06-28 11:29:54 -07004156 }
4157 }
4158 }
4159 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07004160
Chris Wren47633422016-01-22 09:56:59 -05004161 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004162 }
4163
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04004164 private void doChannelWarningToast(CharSequence toastText) {
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04004165 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04004166 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04004167 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4168 if (warningEnabled) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04004169 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
Geoffrey Pitsch5bdddbd2017-05-26 10:50:05 -04004170 Toast.LENGTH_SHORT);
Geoffrey Pitschd34c1872017-05-04 16:02:15 -04004171 toast.show();
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004172 }
4173 }
4174
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004175 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
4176 // The system can post notifications on behalf of any package it wants
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004177 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004178 try {
4179 return getContext().getPackageManager()
4180 .getPackageUidAsUser(opPackageName, userId);
4181 } catch (NameNotFoundException e) {
4182 /* ignore */
4183 }
4184 }
4185 return callingUid;
4186 }
4187
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004188 /**
4189 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4190 *
4191 * Has side effects.
4192 */
4193 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04004194 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004195 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004196 final boolean isSystemNotification =
4197 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004198 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
4199
4200 // Limit the number of notifications that any given package except the android
4201 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
4202 if (!isSystemNotification && !isNotificationFromListener) {
4203 synchronized (mNotificationLock) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004204 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
4205 // Ephemeral apps have some special constraints for notifications.
4206 // They are not allowed to create new notifications however they are allowed to
4207 // update notifications created by the system (e.g. a foreground service
4208 // notification).
4209 throw new SecurityException("Instant app " + pkg
4210 + " cannot create notifications");
4211 }
4212
4213 // rate limit updates that aren't completed progress notifications
4214 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04004215 && !r.getNotification().hasCompletedProgress()
4216 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004217
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004218 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
4219 if (appEnqueueRate > mMaxPackageEnqueueRate) {
4220 mUsageStats.registerOverRateQuota(pkg);
4221 final long now = SystemClock.elapsedRealtime();
4222 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
4223 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04004224 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004225 mLastOverRateLogTime = now;
4226 }
4227 return false;
4228 }
4229 }
4230
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004231 // limit the number of outstanding notificationrecords an app can have
4232 int count = getNotificationCountLocked(pkg, userId, id, tag);
4233 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
4234 mUsageStats.registerOverCountQuota(pkg);
4235 Slog.e(TAG, "Package has already posted or enqueued " + count
4236 + " notifications. Not showing more. package=" + pkg);
4237 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004238 }
4239 }
4240 }
4241
4242 // snoozed apps
4243 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05004244 MetricsLogger.action(r.getLogMaker()
4245 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
4246 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004247 if (DBG) {
4248 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
4249 }
4250 mSnoozeHelper.update(userId, r);
4251 savePolicyFile();
4252 return false;
4253 }
4254
4255
4256 // blocked apps
4257 if (isBlocked(r, mUsageStats)) {
4258 return false;
4259 }
4260
4261 return true;
4262 }
4263
Andreas Gampea36dc622018-02-05 17:19:22 -08004264 @GuardedBy("mNotificationLock")
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004265 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
4266 String excludedTag) {
4267 int count = 0;
4268 final int N = mNotificationList.size();
4269 for (int i = 0; i < N; i++) {
4270 final NotificationRecord existing = mNotificationList.get(i);
4271 if (existing.sbn.getPackageName().equals(pkg)
4272 && existing.sbn.getUserId() == userId) {
4273 if (existing.sbn.getId() == excludedId
4274 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
4275 continue;
4276 }
4277 count++;
4278 }
4279 }
4280 final int M = mEnqueuedNotifications.size();
4281 for (int i = 0; i < M; i++) {
4282 final NotificationRecord existing = mEnqueuedNotifications.get(i);
4283 if (existing.sbn.getPackageName().equals(pkg)
4284 && existing.sbn.getUserId() == userId) {
4285 count++;
4286 }
4287 }
4288 return count;
4289 }
4290
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004291 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
4292 final String pkg = r.sbn.getPackageName();
4293 final int callingUid = r.sbn.getUid();
4294
4295 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
4296 if (isPackageSuspended) {
4297 Slog.e(TAG, "Suppressing notification from package due to package "
4298 + "suspended by administrator.");
4299 usageStats.registerSuspendedByAdmin(r);
4300 return isPackageSuspended;
4301 }
Julia Reynolds4da79702017-06-01 11:06:10 -04004302 final boolean isBlocked =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004303 mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
4304 || mPreferencesHelper.getImportance(pkg, callingUid)
Julia Reynolds005c8b92017-08-24 10:35:53 -04004305 == NotificationManager.IMPORTANCE_NONE
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04004306 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004307 if (isBlocked) {
4308 Slog.e(TAG, "Suppressing notification from package by user request.");
4309 usageStats.registerBlocked(r);
4310 }
4311 return isBlocked;
4312 }
4313
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004314 protected class SnoozeNotificationRunnable implements Runnable {
4315 private final String mKey;
4316 private final long mDuration;
4317 private final String mSnoozeCriterionId;
4318
4319 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
4320 mKey = key;
4321 mDuration = duration;
4322 mSnoozeCriterionId = snoozeCriterionId;
4323 }
4324
4325 @Override
4326 public void run() {
4327 synchronized (mNotificationLock) {
4328 final NotificationRecord r = findNotificationByKeyLocked(mKey);
4329 if (r != null) {
4330 snoozeLocked(r);
4331 }
4332 }
4333 }
4334
Julia Reynolds88860ce2017-06-01 16:55:49 -04004335 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004336 void snoozeLocked(NotificationRecord r) {
4337 if (r.sbn.isGroup()) {
4338 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
4339 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
4340 if (r.getNotification().isGroupSummary()) {
4341 // snooze summary and all children
4342 for (int i = 0; i < groupNotifications.size(); i++) {
4343 snoozeNotificationLocked(groupNotifications.get(i));
4344 }
4345 } else {
4346 // if there is a valid summary for this group, and we are snoozing the only
4347 // child, also snooze the summary
4348 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
4349 if (groupNotifications.size() != 2) {
4350 snoozeNotificationLocked(r);
4351 } else {
4352 // snooze summary and the one child
4353 for (int i = 0; i < groupNotifications.size(); i++) {
4354 snoozeNotificationLocked(groupNotifications.get(i));
4355 }
4356 }
4357 } else {
4358 snoozeNotificationLocked(r);
4359 }
4360 }
4361 } else {
4362 // just snooze the one notification
4363 snoozeNotificationLocked(r);
4364 }
4365 }
4366
Julia Reynolds88860ce2017-06-01 16:55:49 -04004367 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004368 void snoozeNotificationLocked(NotificationRecord r) {
4369 MetricsLogger.action(r.getLogMaker()
4370 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4371 .setType(MetricsEvent.TYPE_CLOSE)
Chris Wren21a2e722017-10-02 17:44:53 -04004372 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
4373 mDuration)
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004374 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4375 mSnoozeCriterionId == null ? 0 : 1));
Julia Reynolds0839c022017-06-15 15:24:01 -04004376 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004377 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004378 updateLightsLocked();
4379 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004380 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004381 mSnoozeHelper.snooze(r);
4382 } else {
4383 mSnoozeHelper.snooze(r, mDuration);
4384 }
Julia Reynolds503ed942017-10-04 16:04:56 -04004385 r.recordSnoozed();
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004386 savePolicyFile();
4387 }
4388 }
4389
Julia Reynoldsbaff4002016-12-15 11:34:26 -05004390 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05004391 private final NotificationRecord r;
4392 private final int userId;
4393
4394 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
4395 this.userId = userId;
4396 this.r = r;
4397 };
4398
4399 @Override
4400 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004401 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05004402 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05004403 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05004404
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004405 final StatusBarNotification n = r.sbn;
4406 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
4407 NotificationRecord old = mNotificationsByKey.get(n.getKey());
4408 if (old != null) {
4409 // Retain ranking information from previous record
4410 r.copyRankingInformation(old);
4411 }
4412
4413 final int callingUid = n.getUid();
4414 final int callingPid = n.getInitialPid();
4415 final Notification notification = n.getNotification();
4416 final String pkg = n.getPackageName();
4417 final int id = n.getId();
4418 final String tag = n.getTag();
4419
4420 // Handle grouped notifications and bail out early if we
4421 // can to avoid extracting signals.
4422 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
4423
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004424 // if this is a group child, unsnooze parent summary
4425 if (n.isGroup() && notification.isGroupChild()) {
4426 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
4427 }
4428
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004429 // This conditional is a dirty hack to limit the logging done on
4430 // behalf of the download manager without affecting other apps.
4431 if (!pkg.equals("com.android.providers.downloads")
4432 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
4433 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05004434 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004435 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05004436 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004437 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
4438 pkg, id, tag, userId, notification.toString(),
4439 enqueueStatus);
4440 }
Chris Wren6676dab2016-12-21 18:26:27 -05004441
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004442 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05004443
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004444 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004445 if (mAssistants.isEnabled()) {
4446 mAssistants.onNotificationEnqueued(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004447 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004448 DELAY_FOR_ASSISTANT_TIME);
4449 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004450 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004451 }
4452 }
4453 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004454 }
4455
Beverly5a20a5e2018-03-06 15:02:44 -05004456 @GuardedBy("mNotificationLock")
4457 private boolean isPackageSuspendedLocked(NotificationRecord r) {
4458 final String pkg = r.sbn.getPackageName();
4459 final int callingUid = r.sbn.getUid();
4460
4461 return isPackageSuspendedForUser(pkg, callingUid);
4462 }
4463
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004464 protected class PostNotificationRunnable implements Runnable {
4465 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004466
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004467 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004468 this.key = key;
4469 }
4470
4471 @Override
4472 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004473 synchronized (mNotificationLock) {
4474 try {
4475 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004476 int N = mEnqueuedNotifications.size();
4477 for (int i = 0; i < N; i++) {
4478 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4479 if (Objects.equals(key, enqueued.getKey())) {
4480 r = enqueued;
4481 break;
Chris Wren6676dab2016-12-21 18:26:27 -05004482 }
Chris Wren6676dab2016-12-21 18:26:27 -05004483 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004484 if (r == null) {
4485 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
4486 return;
4487 }
Beverly5a20a5e2018-03-06 15:02:44 -05004488
4489 r.setHidden(isPackageSuspendedLocked(r));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004490 NotificationRecord old = mNotificationsByKey.get(key);
4491 final StatusBarNotification n = r.sbn;
4492 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05004493 int index = indexOfNotificationLocked(n.getKey());
4494 if (index < 0) {
4495 mNotificationList.add(r);
4496 mUsageStats.registerPostedByApp(r);
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004497 r.setInterruptive(isVisuallyInterruptive(null, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004498 } else {
4499 old = mNotificationList.get(index);
4500 mNotificationList.set(index, r);
4501 mUsageStats.registerUpdatedByApp(r, old);
4502 // Make sure we don't lose the foreground service state.
4503 notification.flags |=
Julia Reynoldse5c60452018-04-30 14:41:36 -04004504 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
Chris Wren6676dab2016-12-21 18:26:27 -05004505 r.isUpdate = true;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04004506 r.setTextChanged(isVisuallyInterruptive(old, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004507 }
4508
4509 mNotificationsByKey.put(n.getKey(), r);
4510
4511 // Ensure if this is a foreground service that the proper additional
4512 // flags are set.
Julia Reynoldse5c60452018-04-30 14:41:36 -04004513 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
Chris Wren6676dab2016-12-21 18:26:27 -05004514 notification.flags |= Notification.FLAG_ONGOING_EVENT
4515 | Notification.FLAG_NO_CLEAR;
4516 }
4517
4518 applyZenModeLocked(r);
4519 mRankingHelper.sort(mNotificationList);
4520
4521 if (notification.getSmallIcon() != null) {
4522 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06004523 mListeners.notifyPostedLocked(r, old);
Julia Reynolds8aebf352017-06-26 11:35:33 -04004524 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
4525 mHandler.post(new Runnable() {
4526 @Override
4527 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04004528 mGroupHelper.onNotificationPosted(
4529 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04004530 }
4531 });
4532 }
Chris Wren6676dab2016-12-21 18:26:27 -05004533 } else {
4534 Slog.e(TAG, "Not posting notification without small icon: " + notification);
4535 if (old != null && !old.isCanceled) {
Beverly5a20a5e2018-03-06 15:02:44 -05004536 mListeners.notifyRemovedLocked(r,
Julia Reynolds503ed942017-10-04 16:04:56 -04004537 NotificationListenerService.REASON_ERROR, null);
Chris Wren6676dab2016-12-21 18:26:27 -05004538 mHandler.post(new Runnable() {
4539 @Override
4540 public void run() {
4541 mGroupHelper.onNotificationRemoved(n);
4542 }
4543 });
4544 }
4545 // ATTENTION: in a future release we will bail out here
4546 // so that we do not play sounds, show lights, etc. for invalid
4547 // notifications
4548 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
4549 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05004550 }
Chris Wren47633422016-01-22 09:56:59 -05004551
Beverly5a20a5e2018-03-06 15:02:44 -05004552 if (!r.isHidden()) {
4553 buzzBeepBlinkLocked(r);
4554 }
Julia Reynolds1fac86e2018-03-07 08:30:37 -05004555 maybeRecordInterruptionLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004556 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004557 int N = mEnqueuedNotifications.size();
4558 for (int i = 0; i < N; i++) {
4559 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4560 if (Objects.equals(key, enqueued.getKey())) {
4561 mEnqueuedNotifications.remove(i);
4562 break;
4563 }
4564 }
Chris Wren6676dab2016-12-21 18:26:27 -05004565 }
Chris Wren47633422016-01-22 09:56:59 -05004566 }
4567 }
4568 }
4569
Christoph Studer265c1052014-07-23 17:14:33 +02004570 /**
Julia Reynolds7217dc92018-03-07 12:12:09 -05004571 * If the notification differs enough visually, consider it a new interruptive notification.
4572 */
4573 @GuardedBy("mNotificationLock")
4574 @VisibleForTesting
4575 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
Julia Reynolds760fa762018-06-19 15:39:23 -04004576 // Ignore summary updates because we don't display most of the information.
4577 if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
4578 if (DEBUG_INTERRUPTIVENESS) {
4579 Log.v(TAG, "INTERRUPTIVENESS: "
4580 + r.getKey() + " is not interruptive: summary");
4581 }
4582 return false;
4583 }
4584
Dan Sandler7d67bd42018-05-15 14:06:38 -04004585 if (old == null) {
4586 if (DEBUG_INTERRUPTIVENESS) {
4587 Log.v(TAG, "INTERRUPTIVENESS: "
4588 + r.getKey() + " is interruptive: new notification");
4589 }
4590 return true;
4591 }
4592
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004593 if (r == null) {
4594 if (DEBUG_INTERRUPTIVENESS) {
4595 Log.v(TAG, "INTERRUPTIVENESS: "
4596 + r.getKey() + " is not interruptive: null");
4597 }
4598 return false;
4599 }
4600
Julia Reynolds7217dc92018-03-07 12:12:09 -05004601 Notification oldN = old.sbn.getNotification();
4602 Notification newN = r.sbn.getNotification();
Dan Sandler7d67bd42018-05-15 14:06:38 -04004603
Julia Reynolds7217dc92018-03-07 12:12:09 -05004604 if (oldN.extras == null || newN.extras == null) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004605 if (DEBUG_INTERRUPTIVENESS) {
4606 Log.v(TAG, "INTERRUPTIVENESS: "
4607 + r.getKey() + " is not interruptive: no extras");
4608 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004609 return false;
4610 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004611
4612 // Ignore visual interruptions from foreground services because users
4613 // consider them one 'session'. Count them for everything else.
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004614 if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004615 if (DEBUG_INTERRUPTIVENESS) {
4616 Log.v(TAG, "INTERRUPTIVENESS: "
4617 + r.getKey() + " is not interruptive: foreground service");
4618 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004619 return false;
4620 }
4621
Dan Sandler7d67bd42018-05-15 14:06:38 -04004622 final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
4623 final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
4624 if (!Objects.equals(oldTitle, newTitle)) {
4625 if (DEBUG_INTERRUPTIVENESS) {
4626 Log.v(TAG, "INTERRUPTIVENESS: "
4627 + r.getKey() + " is interruptive: changed title");
4628 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)",
4629 oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
4630 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)",
4631 newTitle, newTitle.getClass(), newTitle.hashCode()));
4632 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004633 return true;
4634 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004635 // Do not compare Spannables (will always return false); compare unstyled Strings
4636 final String oldText = String.valueOf(oldN.extras.get(Notification.EXTRA_TEXT));
4637 final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT));
4638 if (!Objects.equals(oldText, newText)) {
4639 if (DEBUG_INTERRUPTIVENESS) {
4640 Log.v(TAG, "INTERRUPTIVENESS: "
4641 + r.getKey() + " is interruptive: changed text");
4642 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)",
4643 oldText, oldText.getClass(), oldText.hashCode()));
4644 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)",
4645 newText, newText.getClass(), newText.hashCode()));
4646 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004647 return true;
4648 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004649 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
4650 if (DEBUG_INTERRUPTIVENESS) {
4651 Log.v(TAG, "INTERRUPTIVENESS: "
4652 + r.getKey() + " is interruptive: completed progress");
4653 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004654 return true;
4655 }
4656 // Actions
4657 if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004658 if (DEBUG_INTERRUPTIVENESS) {
4659 Log.v(TAG, "INTERRUPTIVENESS: "
4660 + r.getKey() + " is interruptive: changed actions");
4661 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004662 return true;
4663 }
4664
4665 try {
4666 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
4667 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
4668
4669 // Style based comparisons
4670 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004671 if (DEBUG_INTERRUPTIVENESS) {
4672 Log.v(TAG, "INTERRUPTIVENESS: "
4673 + r.getKey() + " is interruptive: styles differ");
4674 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004675 return true;
4676 }
4677
4678 // Remote views
4679 if (Notification.areRemoteViewsChanged(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004680 if (DEBUG_INTERRUPTIVENESS) {
4681 Log.v(TAG, "INTERRUPTIVENESS: "
4682 + r.getKey() + " is interruptive: remoteviews differ");
4683 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004684 return true;
4685 }
4686 } catch (Exception e) {
4687 Slog.w(TAG, "error recovering builder", e);
4688 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004689
Julia Reynolds7217dc92018-03-07 12:12:09 -05004690 return false;
4691 }
4692
4693 /**
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05004694 * Keeps the last 5 packages that have notified, by user.
4695 */
4696 @GuardedBy("mNotificationLock")
4697 @VisibleForTesting
4698 protected void logRecentLocked(NotificationRecord r) {
4699 if (r.isUpdate) {
4700 return;
4701 }
4702 ArrayList<NotifyingApp> recentAppsForUser =
4703 mRecentApps.getOrDefault(r.getUser().getIdentifier(), new ArrayList<>(6));
4704 NotifyingApp na = new NotifyingApp()
4705 .setPackage(r.sbn.getPackageName())
4706 .setUid(r.sbn.getUid())
4707 .setLastNotified(r.sbn.getPostTime());
4708 // A new notification gets an app moved to the front of the list
4709 for (int i = recentAppsForUser.size() - 1; i >= 0; i--) {
4710 NotifyingApp naExisting = recentAppsForUser.get(i);
4711 if (na.getPackage().equals(naExisting.getPackage())
4712 && na.getUid() == naExisting.getUid()) {
4713 recentAppsForUser.remove(i);
4714 break;
4715 }
4716 }
4717 // time is always increasing, so always add to the front of the list
4718 recentAppsForUser.add(0, na);
4719 if (recentAppsForUser.size() > 5) {
4720 recentAppsForUser.remove(recentAppsForUser.size() -1);
4721 }
4722 mRecentApps.put(r.getUser().getIdentifier(), recentAppsForUser);
4723 }
4724
4725 /**
Christoph Studer265c1052014-07-23 17:14:33 +02004726 * Ensures that grouped notification receive their special treatment.
4727 *
4728 * <p>Cancels group children if the new notification causes a group to lose
4729 * its summary.</p>
4730 *
4731 * <p>Updates mSummaryByGroupKey.</p>
4732 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004733 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02004734 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
4735 int callingUid, int callingPid) {
4736 StatusBarNotification sbn = r.sbn;
4737 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07004738 if (n.isGroupSummary() && !sbn.isAppGroup()) {
4739 // notifications without a group shouldn't be a summary, otherwise autobundling can
4740 // lead to bugs
4741 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
4742 }
4743
Christoph Studer265c1052014-07-23 17:14:33 +02004744 String group = sbn.getGroupKey();
4745 boolean isSummary = n.isGroupSummary();
4746
4747 Notification oldN = old != null ? old.sbn.getNotification() : null;
4748 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
4749 boolean oldIsSummary = old != null && oldN.isGroupSummary();
4750
4751 if (oldIsSummary) {
4752 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
4753 if (removedSummary != old) {
4754 String removedKey =
4755 removedSummary != null ? removedSummary.getKey() : "<null>";
4756 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
4757 ", removed=" + removedKey);
4758 }
4759 }
4760 if (isSummary) {
4761 mSummaryByGroupKey.put(group, r);
4762 }
4763
4764 // Clear out group children of the old notification if the update
4765 // causes the group summary to go away. This happens when the old
4766 // notification was a summary and the new one isn't, or when the old
4767 // notification was a summary and its group key changed.
4768 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04004769 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
4770 null);
Christoph Studer265c1052014-07-23 17:14:33 +02004771 }
4772 }
4773
Chris Wren93bb8b82016-03-29 14:35:05 -04004774 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004775 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05004776 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04004777 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05004778 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4779 REQUEST_CODE_TIMEOUT,
4780 new Intent(ACTION_NOTIFICATION_TIMEOUT)
4781 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4782 .appendPath(record.getKey()).build())
4783 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4784 .putExtra(EXTRA_KEY, record.getKey()),
4785 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05004786 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04004787 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05004788 }
4789 }
4790
4791 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004792 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04004793 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04004794 boolean buzz = false;
4795 boolean beep = false;
4796 boolean blink = false;
4797
Chris Wrena3446562014-06-03 18:11:47 -04004798 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04004799 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04004800
4801 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04004802 final boolean aboveThreshold =
4803 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04004804
4805 // Remember if this notification already owns the notification channels.
4806 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4807 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04004808 // These are set inside the conditional if the notification is allowed to make noise.
4809 boolean hasValidVibrate = false;
4810 boolean hasValidSound = false;
Julia Reynolds94187562017-10-10 13:58:49 -04004811 boolean sentAccessibilityEvent = false;
4812 // If the notification will appear in the status bar, it should send an accessibility
4813 // event
4814 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4815 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4816 sentAccessibilityEvent = true;
4817 }
Chris Wrena3446562014-06-03 18:11:47 -04004818
Julia Reynolds76c096d2017-06-19 08:16:04 -04004819 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004820
Julia Reynolds76c096d2017-06-19 08:16:04 -04004821 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004822 Uri soundUri = record.getSound();
4823 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4824 long[] vibration = record.getVibration();
4825 // Demote sound to vibration if vibration missing & phone in vibration mode.
4826 if (vibration == null
4827 && hasValidSound
4828 && (mAudioManager.getRingerModeInternal()
Julia Reynolds85896572017-09-20 12:54:52 -04004829 == AudioManager.RINGER_MODE_VIBRATE)
4830 && mAudioManager.getStreamVolume(
4831 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004832 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04004833 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004834 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01004835
Julia Reynolds76c096d2017-06-19 08:16:04 -04004836 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
Julia Reynolds76c096d2017-06-19 08:16:04 -04004837 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004838 if (!sentAccessibilityEvent) {
4839 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4840 sentAccessibilityEvent = true;
4841 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004842 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04004843 if (hasValidSound) {
4844 mSoundNotificationKey = key;
4845 if (mInCall) {
4846 playInCallNotification();
4847 beep = true;
4848 } else {
4849 beep = playSound(record, soundUri);
4850 }
4851 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004852
Julia Reynolds7c96b582017-05-25 12:35:36 -04004853 final boolean ringerModeSilent =
4854 mAudioManager.getRingerModeInternal()
4855 == AudioManager.RINGER_MODE_SILENT;
4856 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
4857 mVibrateNotificationKey = key;
4858
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004859 buzz = playVibration(record, vibration, hasValidSound);
Julia Reynolds7c96b582017-05-25 12:35:36 -04004860 }
Tyler Gunn48f86272018-07-03 12:38:49 -07004861 } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
4862 hasValidSound = false;
Chris Wrena3446562014-06-03 18:11:47 -04004863 }
4864 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004865 }
4866 // If a notification is updated to remove the actively playing sound or vibrate,
4867 // cancel that feedback now
4868 if (wasBeep && !hasValidSound) {
4869 clearSoundLocked();
4870 }
4871 if (wasBuzz && !hasValidVibrate) {
4872 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04004873 }
4874
4875 // light
4876 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04004877 boolean wasShowLights = mLights.remove(key);
Julia Reynolds28149f62018-07-03 10:43:35 -04004878 if (canShowLightsLocked(record, aboveThreshold)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04004879 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04004880 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04004881 if (mUseAttentionLight) {
4882 mAttentionLight.pulse();
4883 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004884 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04004885 } else if (wasShowLights) {
4886 updateLightsLocked();
4887 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004888 if (buzz || beep || blink) {
Julia Reynolds28149f62018-07-03 10:43:35 -04004889 // Ignore summary updates because we don't display most of the information.
4890 if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) {
4891 if (DEBUG_INTERRUPTIVENESS) {
4892 Log.v(TAG, "INTERRUPTIVENESS: "
4893 + record.getKey() + " is not interruptive: summary");
4894 }
4895 } else {
4896 if (DEBUG_INTERRUPTIVENESS) {
4897 Log.v(TAG, "INTERRUPTIVENESS: "
4898 + record.getKey() + " is interruptive: alerted");
4899 }
4900 record.setInterruptive(true);
4901 }
Julia Reynolds445cfa82017-05-08 15:41:45 -04004902 MetricsLogger.action(record.getLogMaker()
4903 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4904 .setType(MetricsEvent.TYPE_OPEN)
4905 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4906 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04004907 }
Chris Wrena3446562014-06-03 18:11:47 -04004908 }
4909
Julia Reynolds88860ce2017-06-01 16:55:49 -04004910 @GuardedBy("mNotificationLock")
Julia Reynolds28149f62018-07-03 10:43:35 -04004911 boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
4912 // device lacks light
4913 if (!mHasLight) {
4914 return false;
4915 }
4916 // user turned lights off globally
4917 if (!mNotificationPulseEnabled) {
4918 return false;
4919 }
4920 // the notification/channel has no light
4921 if (record.getLight() == null) {
4922 return false;
4923 }
4924 // unimportant notification
4925 if (!aboveThreshold) {
4926 return false;
4927 }
4928 // suppressed due to DND
4929 if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
4930 return false;
4931 }
4932 // Suppressed because it's a silent update
4933 final Notification notification = record.getNotification();
4934 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4935 return false;
4936 }
4937 // Suppressed because another notification in its group handles alerting
4938 if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
4939 return false;
4940 }
4941 // not if in call or the screen's on
4942 if (mInCall || mScreenOn) {
4943 return false;
4944 }
4945
4946 return true;
4947 }
4948
4949 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004950 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04004951 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004952 final Notification notification = record.getNotification();
Julia Reynolds28149f62018-07-03 10:43:35 -04004953 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004954 return true;
4955 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004956
Julia Reynolds76c096d2017-06-19 08:16:04 -04004957 // muted by listener
4958 final String disableEffects = disableNotificationEffects(record);
4959 if (disableEffects != null) {
4960 ZenLog.traceDisableEffects(record, disableEffects);
4961 return true;
4962 }
4963
4964 // suppressed due to DND
4965 if (record.isIntercepted()) {
4966 return true;
4967 }
4968
4969 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004970 if (record.sbn.isGroup()) {
Julia Reynolds79dfdd62018-04-17 15:36:33 -04004971 if (notification.suppressAlertingDueToGrouping()) {
4972 return true;
4973 }
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004974 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004975
Julia Reynolds65b85cf2017-07-20 09:19:20 -04004976 // Suppressed for being too recently noisy
4977 final String pkg = record.sbn.getPackageName();
4978 if (mUsageStats.isAlertRateLimited(pkg)) {
4979 Slog.e(TAG, "Muting recently noisy " + record.getKey());
4980 return true;
4981 }
4982
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004983 return false;
4984 }
4985
Julia Reynolds0c299d42016-11-15 14:37:04 -05004986 private boolean playSound(final NotificationRecord record, Uri soundUri) {
4987 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
Jean-Michel Triviec2bb182018-03-23 18:04:00 -07004988 // play notifications if there is no user of exclusive audio focus
4989 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
4990 // VIBRATE ringer mode)
4991 if (!mAudioManager.isAudioFocusExclusive()
4992 && (mAudioManager.getStreamVolume(
4993 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05004994 final long identity = Binder.clearCallingIdentity();
4995 try {
4996 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4997 if (player != null) {
4998 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4999 + " with attributes " + record.getAudioAttributes());
5000 player.playAsync(soundUri, record.sbn.getUser(), looping,
5001 record.getAudioAttributes());
5002 return true;
5003 }
5004 } catch (RemoteException e) {
5005 } finally {
5006 Binder.restoreCallingIdentity(identity);
5007 }
5008 }
5009 return false;
5010 }
5011
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005012 private boolean playVibration(final NotificationRecord record, long[] vibration,
5013 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005014 // Escalate privileges so we can use the vibrator even if the
5015 // notifying app does not have the VIBRATE permission.
5016 long identity = Binder.clearCallingIdentity();
5017 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005018 final VibrationEffect effect;
5019 try {
5020 final boolean insistent =
5021 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
5022 effect = VibrationEffect.createWaveform(
5023 vibration, insistent ? 0 : -1 /*repeatIndex*/);
5024 } catch (IllegalArgumentException e) {
5025 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
5026 Arrays.toString(vibration));
5027 return false;
5028 }
5029 if (delayVibForSound) {
5030 new Thread(() -> {
5031 // delay the vibration by the same amount as the notification sound
5032 final int waitMs = mAudioManager.getFocusRampTimeMs(
5033 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
5034 record.getAudioAttributes());
5035 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
5036 try {
5037 Thread.sleep(waitMs);
5038 } catch (InterruptedException e) { }
5039 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01005040 effect, "Notification (delayed)", record.getAudioAttributes());
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005041 }).start();
5042 } else {
5043 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01005044 effect, "Notification", record.getAudioAttributes());
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005045 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005046 return true;
5047 } finally{
5048 Binder.restoreCallingIdentity(identity);
5049 }
5050 }
5051
Julia Reynolds7c96b582017-05-25 12:35:36 -04005052 private boolean isNotificationForCurrentUser(NotificationRecord record) {
5053 final int currentUser;
5054 final long token = Binder.clearCallingIdentity();
5055 try {
5056 currentUser = ActivityManager.getCurrentUser();
5057 } finally {
5058 Binder.restoreCallingIdentity(token);
5059 }
5060 return (record.getUserId() == UserHandle.USER_ALL ||
5061 record.getUserId() == currentUser ||
5062 mUserProfiles.isCurrentProfile(record.getUserId()));
5063 }
5064
Beverly5d463b62017-07-26 14:13:40 -04005065 protected void playInCallNotification() {
Beverly28c3d162018-06-28 11:37:53 -04005066 if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL
5067 && Settings.Secure.getInt(getContext().getContentResolver(),
5068 Settings.Secure.IN_CALL_NOTIFICATION_ENABLED, 1) != 0) {
5069 new Thread() {
5070 @Override
5071 public void run() {
5072 final long identity = Binder.clearCallingIdentity();
5073 try {
5074 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5075 if (player != null) {
5076 if (mCallNotificationToken != null) {
5077 player.stop(mCallNotificationToken);
5078 }
5079 mCallNotificationToken = new Binder();
5080 player.play(mCallNotificationToken, mInCallNotificationUri,
5081 mInCallNotificationAudioAttributes,
5082 mInCallNotificationVolume, false);
luochaojiang50e5273c2018-04-16 16:55:03 +08005083 }
Beverly28c3d162018-06-28 11:37:53 -04005084 } catch (RemoteException e) {
5085 } finally {
5086 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01005087 }
Marta Białka39c992f2011-03-10 10:27:24 +01005088 }
Beverly28c3d162018-06-28 11:37:53 -04005089 }.start();
5090 }
Marta Białka39c992f2011-03-10 10:27:24 +01005091 }
5092
Julia Reynolds88860ce2017-06-01 16:55:49 -04005093 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005094 void showNextToastLocked() {
5095 ToastRecord record = mToastQueue.get(0);
5096 while (record != null) {
5097 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
5098 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005099 record.callback.show(record.token);
Robert Carr997427342018-02-28 18:06:10 -08005100 scheduleDurationReachedLocked(record);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005101 return;
5102 } catch (RemoteException e) {
5103 Slog.w(TAG, "Object died trying to show notification " + record.callback
5104 + " in package " + record.pkg);
5105 // remove it from the list and let the process die
5106 int index = mToastQueue.indexOf(record);
5107 if (index >= 0) {
5108 mToastQueue.remove(index);
5109 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005110 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005111 if (mToastQueue.size() > 0) {
5112 record = mToastQueue.get(0);
5113 } else {
5114 record = null;
5115 }
5116 }
5117 }
5118 }
5119
Julia Reynolds88860ce2017-06-01 16:55:49 -04005120 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005121 void cancelToastLocked(int index) {
5122 ToastRecord record = mToastQueue.get(index);
5123 try {
5124 record.callback.hide();
5125 } catch (RemoteException e) {
5126 Slog.w(TAG, "Object died trying to hide notification " + record.callback
5127 + " in package " + record.pkg);
5128 // don't worry about this, we're about to remove it from
5129 // the list anyway
5130 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005131
5132 ToastRecord lastToast = mToastQueue.remove(index);
Robert Carr997427342018-02-28 18:06:10 -08005133
5134 mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
5135 DEFAULT_DISPLAY);
5136 // We passed 'false' for 'removeWindows' so that the client has time to stop
5137 // rendering (as hide above is a one-way message), otherwise we could crash
5138 // a client which was actively using a surface made from the token. However
5139 // we need to schedule a timeout to make sure the token is eventually killed
5140 // one way or another.
5141 scheduleKillTokenTimeout(lastToast.token);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005142
5143 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005144 if (mToastQueue.size() > 0) {
5145 // Show the next one. If the callback fails, this will remove
5146 // it from the list, so don't assume that the list hasn't changed
5147 // after this point.
5148 showNextToastLocked();
5149 }
5150 }
5151
Robert Carr997427342018-02-28 18:06:10 -08005152 void finishTokenLocked(IBinder t) {
5153 mHandler.removeCallbacksAndMessages(t);
5154 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
5155 // remaining surfaces as either the client has called finishToken indicating
5156 // it has successfully removed the views, or the client has timed out
5157 // at which point anything goes.
5158 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */,
5159 DEFAULT_DISPLAY);
5160 }
5161
Julia Reynolds88860ce2017-06-01 16:55:49 -04005162 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08005163 private void scheduleDurationReachedLocked(ToastRecord r)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005164 {
5165 mHandler.removeCallbacksAndMessages(r);
Robert Carr997427342018-02-28 18:06:10 -08005166 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005167 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
5168 mHandler.sendMessageDelayed(m, delay);
5169 }
5170
Robert Carr997427342018-02-28 18:06:10 -08005171 private void handleDurationReached(ToastRecord record)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005172 {
5173 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
5174 synchronized (mToastQueue) {
5175 int index = indexOfToastLocked(record.pkg, record.callback);
5176 if (index >= 0) {
5177 cancelToastLocked(index);
5178 }
5179 }
5180 }
5181
Julia Reynolds88860ce2017-06-01 16:55:49 -04005182 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08005183 private void scheduleKillTokenTimeout(IBinder token)
5184 {
5185 mHandler.removeCallbacksAndMessages(token);
5186 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, token);
Robert Carr3406d462018-03-15 16:19:07 -07005187 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
Robert Carr997427342018-02-28 18:06:10 -08005188 }
5189
5190 private void handleKillTokenTimeout(IBinder token)
5191 {
5192 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + token);
5193 synchronized (mToastQueue) {
5194 finishTokenLocked(token);
5195 }
5196 }
5197
5198 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005199 int indexOfToastLocked(String pkg, ITransientNotification callback)
5200 {
5201 IBinder cbak = callback.asBinder();
5202 ArrayList<ToastRecord> list = mToastQueue;
5203 int len = list.size();
5204 for (int i=0; i<len; i++) {
5205 ToastRecord r = list.get(i);
Beverly Taia7ed0ab2018-06-11 14:50:36 +00005206 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08005207 return i;
5208 }
5209 }
5210 return -1;
5211 }
5212
Julia Reynolds88860ce2017-06-01 16:55:49 -04005213 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005214 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005215 {
5216 int toastCount = 0; // toasts from this pid
5217 ArrayList<ToastRecord> list = mToastQueue;
5218 int N = list.size();
5219 for (int i=0; i<N; i++) {
5220 ToastRecord r = list.get(i);
5221 if (r.pid == pid) {
5222 toastCount++;
5223 }
5224 }
5225 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07005226 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08005227 } catch (RemoteException e) {
5228 // Shouldn't happen.
5229 }
5230 }
5231
Chris Wrenf9536642014-04-17 10:01:54 -04005232 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005233 if (!(message.obj instanceof RankingReconsideration)) return;
5234 RankingReconsideration recon = (RankingReconsideration) message.obj;
5235 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04005236 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005237 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005238 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
5239 if (record == null) {
5240 return;
Chris Wrenf9536642014-04-17 10:01:54 -04005241 }
Chris Wren333a61c2014-05-28 16:40:57 -04005242 int indexBefore = findNotificationRecordIndexLocked(record);
5243 boolean interceptBefore = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005244 float contactAffinityBefore = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005245 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04005246 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04005247 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04005248 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04005249 int indexAfter = findNotificationRecordIndexLocked(record);
5250 boolean interceptAfter = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005251 float contactAffinityAfter = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005252 int visibilityAfter = record.getPackageVisibilityOverride();
5253 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
5254 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005255 if (interceptBefore && !interceptAfter
5256 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
Chris Wrena3446562014-06-03 18:11:47 -04005257 buzzBeepBlinkLocked(record);
5258 }
Chris Wrenf9536642014-04-17 10:01:54 -04005259 }
Chris Wren333a61c2014-05-28 16:40:57 -04005260 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005261 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04005262 }
5263 }
5264
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005265 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04005266 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005267 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04005268 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005269 // Any field that can change via one of the extractors needs to be added here.
5270 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005271 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05005272 boolean[] showBadges = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005273 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
5274 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
5275 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
5276 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Julia Reynolds503ed942017-10-04 16:04:56 -04005277 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005278 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
Tony Mak628cb932018-06-19 18:30:41 +01005279 ArrayList<ArrayList<Notification.Action>> smartActionsBefore = new ArrayList<>(N);
Tony Makc9acf672018-07-20 13:58:24 +02005280 ArrayList<ArrayList<CharSequence>> smartRepliesBefore = new ArrayList<>(N);
Chris Wren54bbef42014-07-09 18:37:56 -04005281 for (int i = 0; i < N; i++) {
5282 final NotificationRecord r = mNotificationList.get(i);
5283 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005284 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05005285 showBadges[i] = r.canShowBadge();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005286 channelBefore.add(r.getChannel());
5287 groupKeyBefore.add(r.getGroupKey());
5288 overridePeopleBefore.add(r.getPeopleOverride());
5289 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Julia Reynolds503ed942017-10-04 16:04:56 -04005290 userSentimentBefore.add(r.getUserSentiment());
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005291 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
Tony Mak628cb932018-06-19 18:30:41 +01005292 smartActionsBefore.add(r.getSmartActions());
Tony Makc9acf672018-07-20 13:58:24 +02005293 smartRepliesBefore.add(r.getSmartReplies());
Chris Wren54bbef42014-07-09 18:37:56 -04005294 mRankingHelper.extractSignals(r);
5295 }
Chris Wren19a02b02015-12-22 10:34:22 -05005296 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04005297 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005298 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005299 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05005300 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005301 || showBadges[i] != r.canShowBadge()
5302 || !Objects.equals(channelBefore.get(i), r.getChannel())
5303 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
5304 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
Julia Reynolds503ed942017-10-04 16:04:56 -04005305 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005306 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
5307 || !Objects.equals(suppressVisuallyBefore.get(i),
Tony Mak628cb932018-06-19 18:30:41 +01005308 r.getSuppressedVisualEffects())
Tony Makc9acf672018-07-20 13:58:24 +02005309 || !Objects.equals(smartActionsBefore.get(i), r.getSmartActions())
5310 || !Objects.equals(smartRepliesBefore.get(i), r.getSmartReplies())) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005311 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04005312 return;
5313 }
5314 }
5315 }
5316 }
5317
Julia Reynolds88860ce2017-06-01 16:55:49 -04005318 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005319 private void recordCallerLocked(NotificationRecord record) {
5320 if (mZenModeHelper.isCall(record)) {
5321 mZenModeHelper.recordCaller(record);
5322 }
5323 }
5324
Christoph Studerd5092bc2014-07-03 17:47:58 +02005325 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04005326 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005327 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02005328 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005329 if (record.isIntercepted()) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05005330 record.setSuppressedVisualEffects(
5331 mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
Julia Reynolds445cfa82017-05-08 15:41:45 -04005332 } else {
5333 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005334 }
Chris Wren333a61c2014-05-28 16:40:57 -04005335 }
5336
Julia Reynolds88860ce2017-06-01 16:55:49 -04005337 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04005338 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04005339 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04005340 }
5341
Chris Wrenf9536642014-04-17 10:01:54 -04005342 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005343 synchronized (mNotificationLock) {
Beverly5a20a5e2018-03-06 15:02:44 -05005344 mListeners.notifyRankingUpdateLocked(null);
Chris Wrenf9536642014-04-17 10:01:54 -04005345 }
5346 }
5347
John Spurlockd8afe3c2014-08-01 14:04:07 -04005348 private void scheduleListenerHintsChanged(int state) {
5349 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
5350 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04005351 }
5352
Christoph Studer85a384b2014-08-27 20:16:15 +02005353 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
5354 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
5355 mHandler.obtainMessage(
5356 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
5357 listenerInterruptionFilter,
5358 0).sendToTarget();
5359 }
5360
John Spurlockd8afe3c2014-08-01 14:04:07 -04005361 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005362 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005363 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005364 }
5365 }
5366
Christoph Studer85a384b2014-08-27 20:16:15 +02005367 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005368 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02005369 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
5370 }
5371 }
5372
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005373 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08005374 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005375 public WorkerHandler(Looper looper) {
5376 super(looper);
5377 }
5378
Adam Lesinski182f73f2013-12-05 16:48:06 -08005379 @Override
5380 public void handleMessage(Message msg)
5381 {
5382 switch (msg.what)
5383 {
Robert Carr997427342018-02-28 18:06:10 -08005384 case MESSAGE_DURATION_REACHED:
5385 handleDurationReached((ToastRecord)msg.obj);
5386 break;
5387 case MESSAGE_FINISH_TOKEN_TIMEOUT:
5388 handleKillTokenTimeout((IBinder)msg.obj);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005389 break;
John Spurlock056c5192014-04-20 21:52:01 -04005390 case MESSAGE_SAVE_POLICY_FILE:
5391 handleSavePolicyFile();
5392 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005393 case MESSAGE_SEND_RANKING_UPDATE:
5394 handleSendRankingUpdate();
5395 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04005396 case MESSAGE_LISTENER_HINTS_CHANGED:
5397 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04005398 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02005399 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
5400 handleListenerInterruptionFilterChanged(msg.arg1);
5401 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005402 }
5403 }
5404
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005405 protected void scheduleSendRankingUpdate() {
5406 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
5407 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
5408 sendMessage(m);
5409 }
5410 }
5411
Chris Wrenf9536642014-04-17 10:01:54 -04005412 }
5413
Chris Wren51017d02015-12-15 15:34:46 -05005414 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04005415 {
Chris Wren51017d02015-12-15 15:34:46 -05005416 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04005417 super(looper);
5418 }
5419
5420 @Override
5421 public void handleMessage(Message msg) {
5422 switch (msg.what) {
5423 case MESSAGE_RECONSIDER_RANKING:
5424 handleRankingReconsideration(msg);
5425 break;
Chris Wren51017d02015-12-15 15:34:46 -05005426 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005427 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04005428 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08005429 }
5430 }
Chris Wren51017d02015-12-15 15:34:46 -05005431
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005432 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05005433 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05005434 Message msg = Message.obtain();
5435 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05005436 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05005437 }
5438
5439 public void requestReconsideration(RankingReconsideration recon) {
5440 Message m = Message.obtain(this,
5441 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
5442 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
5443 sendMessageDelayed(m, delay);
5444 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08005445 }
5446
Adam Lesinski182f73f2013-12-05 16:48:06 -08005447 // Notifications
5448 // ============================================================================
5449 static int clamp(int x, int low, int high) {
5450 return (x < low) ? low : ((x > high) ? high : x);
5451 }
5452
5453 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
Eugene Suslad4128ec2017-12-04 19:48:41 +00005454 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07005455 return;
5456 }
5457
5458 AccessibilityEvent event =
5459 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
5460 event.setPackageName(packageName);
5461 event.setClassName(Notification.class.getName());
5462 event.setParcelableData(notification);
5463 CharSequence tickerText = notification.tickerText;
5464 if (!TextUtils.isEmpty(tickerText)) {
5465 event.getText().add(tickerText);
5466 }
5467
Julia Reynolds94187562017-10-10 13:58:49 -04005468 mAccessibilityManager.sendAccessibilityEvent(event);
svetoslavganov75986cf2009-05-14 22:28:01 -07005469 }
5470
Julia Reynolds0839c022017-06-15 15:24:01 -04005471 /**
5472 * Removes all NotificationsRecords with the same key as the given notification record
5473 * from both lists. Do not call this method while iterating over either list.
5474 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005475 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04005476 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
5477 // Remove from both lists, either list could have a separate Record for what is
5478 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005479 boolean wasPosted = false;
5480 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04005481 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
5482 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005483 mNotificationList.remove(recordInList);
5484 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005485 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005486 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005487 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005488 != null) {
5489 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005490 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005491 return wasPosted;
5492 }
5493
5494 @GuardedBy("mNotificationLock")
5495 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04005496 boolean wasPosted, String listenerName) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005497 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName);
5498 }
5499
5500 @GuardedBy("mNotificationLock")
5501 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
5502 int rank, int count, boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04005503 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005504
5505 // Record caller.
5506 recordCallerLocked(r);
5507
Julia Reynolds503ed942017-10-04 16:04:56 -04005508 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
5509 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
5510 }
5511
Joe Onorato46439ce2010-11-19 13:56:21 -08005512 // tell the app
5513 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005514 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08005515 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005516 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08005517 } catch (PendingIntent.CanceledException ex) {
5518 // do nothing - there's no relevant way to recover, and
5519 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04005520 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08005521 }
5522 }
5523 }
5524
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005525 // Only cancel these if this notification actually got to be posted.
5526 if (wasPosted) {
5527 // status bar
5528 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005529 if (reason != REASON_SNOOZED) {
5530 r.isCanceled = true;
5531 }
Beverly5a20a5e2018-03-06 15:02:44 -05005532 mListeners.notifyRemovedLocked(r, reason, r.getStats());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005533 mHandler.post(new Runnable() {
5534 @Override
5535 public void run() {
5536 mGroupHelper.onNotificationRemoved(r.sbn);
5537 }
5538 });
5539 }
5540
5541 // sound
5542 if (canceledKey.equals(mSoundNotificationKey)) {
5543 mSoundNotificationKey = null;
5544 final long identity = Binder.clearCallingIdentity();
5545 try {
5546 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5547 if (player != null) {
5548 player.stopAsync();
5549 }
5550 } catch (RemoteException e) {
5551 } finally {
5552 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04005553 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005554 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005555
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005556 // vibrate
5557 if (canceledKey.equals(mVibrateNotificationKey)) {
5558 mVibrateNotificationKey = null;
5559 long identity = Binder.clearCallingIdentity();
5560 try {
5561 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005562 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005563 finally {
5564 Binder.restoreCallingIdentity(identity);
5565 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005566 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005567
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005568 // light
5569 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005570 }
5571
Christoph Studer546bec82014-03-14 12:17:12 +01005572 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04005573 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01005574 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005575 case REASON_CANCEL:
5576 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005577 case REASON_LISTENER_CANCEL:
5578 case REASON_LISTENER_CANCEL_ALL:
5579 mUsageStats.registerDismissedByUser(r);
5580 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05005581 case REASON_APP_CANCEL:
5582 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005583 mUsageStats.registerRemovedByApp(r);
5584 break;
Christoph Studer546bec82014-03-14 12:17:12 +01005585 }
5586
Christoph Studer265c1052014-07-23 17:14:33 +02005587 String groupKey = r.getGroupKey();
5588 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005589 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02005590 mSummaryByGroupKey.remove(groupKey);
5591 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04005592 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
5593 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
5594 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04005595 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005596
Daniel Sandler23d7c702013-03-07 16:32:06 -05005597 // Save it for users of getHistoricalNotifications()
5598 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02005599
Chris Wren6650e572015-05-15 17:19:25 -04005600 final long now = System.currentTimeMillis();
Dieter Hsud39f0d52018-04-14 02:08:30 +08005601 final LogMaker logMaker = r.getLogMaker(now)
Chris Wren9eb5e102017-01-26 13:15:06 -05005602 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
5603 .setType(MetricsEvent.TYPE_DISMISS)
Dieter Hsud39f0d52018-04-14 02:08:30 +08005604 .setSubtype(reason);
5605 if (rank != -1 && count != -1) {
5606 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
5607 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
5608 }
5609 MetricsLogger.action(logMaker);
Chris Wrene6ddb8a2015-05-27 15:21:00 -04005610 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Dieter Hsud39f0d52018-04-14 02:08:30 +08005611 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
5612 rank, count, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005613 }
5614
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005615 @VisibleForTesting
5616 void updateUriPermissions(@Nullable NotificationRecord newRecord,
5617 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) {
5618 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey();
5619 if (DBG) Slog.d(TAG, key + ": updating permissions");
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005620
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005621 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null;
5622 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null;
5623
5624 // Shortcut when no Uris involved
5625 if (newUris == null && oldUris == null) {
5626 return;
5627 }
5628
5629 // Inherit any existing owner
5630 IBinder permissionOwner = null;
5631 if (newRecord != null && permissionOwner == null) {
5632 permissionOwner = newRecord.permissionOwner;
5633 }
5634 if (oldRecord != null && permissionOwner == null) {
5635 permissionOwner = oldRecord.permissionOwner;
5636 }
5637
5638 // If we have Uris to grant, but no owner yet, go create one
5639 if (newUris != null && permissionOwner == null) {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07005640 if (DBG) Slog.d(TAG, key + ": creating owner");
5641 permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005642 }
5643
5644 // If we have no Uris to grant, but an existing owner, go destroy it
5645 if (newUris == null && permissionOwner != null) {
5646 final long ident = Binder.clearCallingIdentity();
5647 try {
5648 if (DBG) Slog.d(TAG, key + ": destroying owner");
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07005649 mUgmInternal.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005650 UserHandle.getUserId(oldRecord.getUid()));
5651 permissionOwner = null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005652 } finally {
5653 Binder.restoreCallingIdentity(ident);
5654 }
5655 }
5656
5657 // Grant access to new Uris
5658 if (newUris != null && permissionOwner != null) {
5659 for (int i = 0; i < newUris.size(); i++) {
5660 final Uri uri = newUris.valueAt(i);
5661 if (oldUris == null || !oldUris.contains(uri)) {
5662 if (DBG) Slog.d(TAG, key + ": granting " + uri);
5663 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
5664 targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005665 }
5666 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005667 }
5668
5669 // Revoke access to old Uris
5670 if (oldUris != null && permissionOwner != null) {
5671 for (int i = 0; i < oldUris.size(); i++) {
5672 final Uri uri = oldUris.valueAt(i);
5673 if (newUris == null || !newUris.contains(uri)) {
5674 if (DBG) Slog.d(TAG, key + ": revoking " + uri);
5675 revokeUriPermission(permissionOwner, uri, oldRecord.getUid());
5676 }
5677 }
5678 }
5679
5680 if (newRecord != null) {
5681 newRecord.permissionOwner = permissionOwner;
5682 }
5683 }
5684
5685 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg,
5686 int targetUserId) {
5687 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5688
5689 final long ident = Binder.clearCallingIdentity();
5690 try {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07005691 mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005692 ContentProvider.getUriWithoutUserId(uri),
5693 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5694 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
5695 targetUserId);
5696 } catch (RemoteException ignored) {
5697 // Ignored because we're in same process
5698 } finally {
5699 Binder.restoreCallingIdentity(ident);
5700 }
5701 }
5702
5703 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUid) {
5704 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5705
5706 final long ident = Binder.clearCallingIdentity();
5707 try {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07005708 mUgmInternal.revokeUriPermissionFromOwner(
5709 owner,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005710 ContentProvider.getUriWithoutUserId(uri),
5711 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5712 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005713 } finally {
5714 Binder.restoreCallingIdentity(ident);
5715 }
5716 }
5717
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005718 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07005719 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005720 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005721 */
John Spurlocke6a7d932014-03-13 12:29:00 -04005722 void cancelNotification(final int callingUid, final int callingPid,
5723 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005724 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04005725 final int userId, final int reason, final ManagedServiceInfo listener) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005726 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
5727 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
5728 }
5729
5730 /**
5731 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
5732 * and none of the {@code mustNotHaveFlags}.
5733 */
5734 void cancelNotification(final int callingUid, final int callingPid,
5735 final String pkg, final String tag, final int id,
5736 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
5737 final int userId, final int reason, int rank, int count, final ManagedServiceInfo listener) {
Beverly5a20a5e2018-03-06 15:02:44 -05005738
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005739 // In enqueueNotificationInternal notifications are added by scheduling the
5740 // work on the worker handler. Hence, we also schedule the cancel on this
5741 // handler to avoid a scenario where an add notification call followed by a
5742 // remove notification call ends up in not removing the notification.
5743 mHandler.post(new Runnable() {
5744 @Override
5745 public void run() {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005746 String listenerName = listener == null ? null : listener.component.toShortString();
Chris Wrenbddb5bc2015-03-04 08:47:46 -08005747 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
5748 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005749
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005750 synchronized (mNotificationLock) {
5751 // Look for the notification, searching both the posted and enqueued lists.
5752 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
5753 if (r != null) {
5754 // The notification was found, check if it should be removed.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005755
Christoph Studer546bec82014-03-14 12:17:12 +01005756 // Ideally we'd do this in the caller of this method. However, that would
5757 // require the caller to also find the notification.
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005758 if (reason == REASON_CLICK) {
Christoph Studer546bec82014-03-14 12:17:12 +01005759 mUsageStats.registerClickedByUser(r);
5760 }
5761
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005762 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
5763 return;
5764 }
5765 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
5766 return;
5767 }
5768
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005769 // Cancel the notification.
Julia Reynolds0839c022017-06-15 15:24:01 -04005770 boolean wasPosted = removeFromNotificationListsLocked(r);
Dieter Hsud39f0d52018-04-14 02:08:30 +08005771 cancelNotificationLocked(r, sendDelete, reason, rank, count, wasPosted, listenerName);
Christoph Studer265c1052014-07-23 17:14:33 +02005772 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005773 sendDelete, null);
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005774 updateLightsLocked();
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005775 } else {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005776 // No notification was found, assume that it is snoozed and cancel it.
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005777 if (reason != REASON_SNOOZED) {
5778 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
5779 if (wasSnoozed) {
5780 savePolicyFile();
5781 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005782 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005783 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005784 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005785 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005786 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005787 }
5788
5789 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07005790 * Determine whether the userId applies to the notification in question, either because
5791 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
5792 */
5793 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
5794 return
5795 // looking for USER_ALL notifications? match everything
5796 userId == UserHandle.USER_ALL
5797 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005798 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07005799 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005800 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07005801 }
5802
5803 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005804 * Determine whether the userId applies to the notification in question, either because
5805 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01005806 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005807 */
Kenny Guy2a764942014-04-02 13:29:20 +01005808 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00005809 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04005810 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005811 }
5812
5813 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05005814 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005815 * {@code mustHaveFlags}.
5816 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005817 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005818 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005819 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005820 mHandler.post(new Runnable() {
5821 @Override
5822 public void run() {
5823 String listenerName = listener == null ? null : listener.component.toShortString();
5824 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5825 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
5826 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005827
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005828 // Why does this parameter exist? Do we actually want to execute the above if doit
5829 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005830 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005831 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005832 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005833
5834 synchronized (mNotificationLock) {
5835 FlagChecker flagChecker = (int flags) -> {
5836 if ((flags & mustHaveFlags) != mustHaveFlags) {
5837 return false;
5838 }
5839 if ((flags & mustNotHaveFlags) != 0) {
5840 return false;
5841 }
5842 return true;
5843 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005844 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5845 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
5846 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005847 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005848 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5849 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
5850 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005851 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005852 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005853 }
5854 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005855 });
5856 }
5857
5858 private interface FlagChecker {
5859 // Returns false if these flags do not pass the defined flag test.
5860 public boolean apply(int flags);
5861 }
5862
Julia Reynolds88860ce2017-06-01 16:55:49 -04005863 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005864 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
5865 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
5866 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005867 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005868 ArrayList<NotificationRecord> canceledNotifications = null;
5869 for (int i = notificationList.size() - 1; i >= 0; --i) {
5870 NotificationRecord r = notificationList.get(i);
5871 if (includeCurrentProfiles) {
5872 if (!notificationMatchesCurrentProfiles(r, userId)) {
5873 continue;
5874 }
5875 } else if (!notificationMatchesUserId(r, userId)) {
5876 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005877 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005878 // Don't remove notifications to all, if there's no package name specified
5879 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
5880 continue;
5881 }
5882 if (!flagChecker.apply(r.getFlags())) {
5883 continue;
5884 }
5885 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
5886 continue;
5887 }
5888 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
5889 continue;
5890 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005891 if (canceledNotifications == null) {
5892 canceledNotifications = new ArrayList<>();
5893 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005894 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005895 mNotificationsByKey.remove(r.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005896 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04005897 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005898 }
5899 if (canceledNotifications != null) {
5900 final int M = canceledNotifications.size();
5901 for (int i = 0; i < M; i++) {
5902 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005903 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005904 }
5905 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005906 }
5907 }
5908
Julia Reynolds50989772017-02-23 14:32:16 -05005909 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005910 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05005911 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005912 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05005913 return;
5914 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05005915
Julia Reynolds79672302017-01-12 08:30:16 -05005916 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05005917 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
5918 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05005919 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005920 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005921 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005922 }
5923
5924 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
5925 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005926 if (DBG) {
5927 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
5928 }
Julia Reynolds79672302017-01-12 08:30:16 -05005929 mSnoozeHelper.repost(key);
5930 savePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005931 }
5932
Julia Reynolds88860ce2017-06-01 16:55:49 -04005933 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07005934 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005935 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005936 mHandler.post(new Runnable() {
5937 @Override
5938 public void run() {
5939 synchronized (mNotificationLock) {
5940 String listenerName =
5941 listener == null ? null : listener.component.toShortString();
5942 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5943 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01005944
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005945 FlagChecker flagChecker = (int flags) -> {
5946 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
5947 != 0) {
5948 return false;
5949 }
5950 return true;
5951 };
5952
5953 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5954 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
5955 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005956 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005957 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5958 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
5959 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04005960 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005961 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00005962 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005963 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005964 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005965 }
5966
Christoph Studere4ef156b2014-07-04 18:41:57 +02005967 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04005968 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02005969 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005970 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005971 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02005972 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005973 return;
5974 }
5975
5976 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02005977
5978 if (pkg == null) {
5979 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
5980 return;
5981 }
5982
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005983 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005984 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005985 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005986 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005987 }
5988
Julia Reynolds88860ce2017-06-01 16:55:49 -04005989 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005990 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
5991 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005992 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005993 final String pkg = parentNotification.sbn.getPackageName();
5994 final int userId = parentNotification.getUserId();
5995 final int reason = REASON_GROUP_SUMMARY_CANCELED;
5996 for (int i = notificationList.size() - 1; i >= 0; i--) {
5997 final NotificationRecord childR = notificationList.get(i);
5998 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04005999 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006000 childR.getGroupKey().equals(parentNotification.getGroupKey())
Julia Reynoldse5c60452018-04-30 14:41:36 -04006001 && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
Beverly40239d92017-07-07 10:20:41 -04006002 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02006003 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
6004 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04006005 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04006006 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04006007 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02006008 }
6009 }
6010 }
6011
Julia Reynolds88860ce2017-06-01 16:55:49 -04006012 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08006013 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006014 {
The Android Open Source Project10592532009-03-18 17:39:46 -07006015 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05006016 NotificationRecord ledNotification = null;
6017 while (ledNotification == null && !mLights.isEmpty()) {
6018 final String owner = mLights.get(mLights.size() - 1);
6019 ledNotification = mNotificationsByKey.get(owner);
6020 if (ledNotification == null) {
6021 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
6022 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006023 }
6024 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006025
Mike Lockwood63b5ad92011-08-30 09:55:30 -04006026 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05006027 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05006028 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07006029 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006030 NotificationRecord.Light light = ledNotification.getLight();
6031 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05006032 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006033 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
6034 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05006035 }
The Android Open Source Project10592532009-03-18 17:39:46 -07006036 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006037 }
6038
Julia Reynolds88860ce2017-06-01 16:55:49 -04006039 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006040 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
6041 String groupKey, int userId) {
6042 List<NotificationRecord> records = new ArrayList<>();
6043 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
6044 records.addAll(
6045 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
6046 return records;
6047 }
6048
6049
Julia Reynolds88860ce2017-06-01 16:55:49 -04006050 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006051 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
6052 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
6053 List<NotificationRecord> records = new ArrayList<>();
6054 final int len = list.size();
6055 for (int i = 0; i < len; i++) {
6056 NotificationRecord r = list.get(i);
6057 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
6058 && r.sbn.getPackageName().equals(pkg)) {
6059 records.add(r);
6060 }
6061 }
6062 return records;
6063 }
6064
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006065 // Searches both enqueued and posted notifications by key.
6066 // TODO: need to combine a bunch of these getters with slightly different behavior.
6067 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04006068 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006069 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006070 NotificationRecord r;
6071 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
6072 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006073 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006074 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
6075 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006076 }
6077 return null;
6078 }
6079
Julia Reynolds88860ce2017-06-01 16:55:49 -04006080 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006081 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006082 NotificationRecord r;
6083 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
6084 return r;
6085 }
6086 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
6087 != null) {
6088 return r;
6089 }
6090 return null;
6091 }
6092
Julia Reynolds88860ce2017-06-01 16:55:49 -04006093 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006094 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006095 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006096 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006097 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006098 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01006099 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
6100 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006101 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006102 }
6103 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006104 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006105 }
6106
Julia Reynolds88860ce2017-06-01 16:55:49 -04006107 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006108 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04006109 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006110 final int N = list.size();
6111 for (int i = 0; i < N; i++) {
6112 if (key.equals(list.get(i).getKey())) {
6113 return list.get(i);
6114 }
6115 }
6116 return null;
6117 }
6118
Julia Reynolds88860ce2017-06-01 16:55:49 -04006119 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02006120 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02006121 final int N = mNotificationList.size();
6122 for (int i = 0; i < N; i++) {
6123 if (key.equals(mNotificationList.get(i).getKey())) {
6124 return i;
6125 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02006126 }
Christoph Studerc5115552014-06-12 20:22:31 +02006127 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02006128 }
6129
Beverly5a20a5e2018-03-06 15:02:44 -05006130 @VisibleForTesting
6131 protected void hideNotificationsForPackages(String[] pkgs) {
6132 synchronized (mNotificationLock) {
6133 List<String> pkgList = Arrays.asList(pkgs);
6134 List<NotificationRecord> changedNotifications = new ArrayList<>();
6135 int numNotifications = mNotificationList.size();
6136 for (int i = 0; i < numNotifications; i++) {
6137 NotificationRecord rec = mNotificationList.get(i);
6138 if (pkgList.contains(rec.sbn.getPackageName())) {
6139 rec.setHidden(true);
6140 changedNotifications.add(rec);
6141 }
6142 }
6143
6144 mListeners.notifyHiddenLocked(changedNotifications);
6145 }
6146 }
6147
6148 @VisibleForTesting
6149 protected void unhideNotificationsForPackages(String[] pkgs) {
6150 synchronized (mNotificationLock) {
6151 List<String> pkgList = Arrays.asList(pkgs);
6152 List<NotificationRecord> changedNotifications = new ArrayList<>();
6153 int numNotifications = mNotificationList.size();
6154 for (int i = 0; i < numNotifications; i++) {
6155 NotificationRecord rec = mNotificationList.get(i);
6156 if (pkgList.contains(rec.sbn.getPackageName())) {
6157 rec.setHidden(false);
6158 changedNotifications.add(rec);
6159 }
6160 }
6161
6162 mListeners.notifyUnhiddenLocked(changedNotifications);
6163 }
6164 }
6165
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006166 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006167 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006168 updateLightsLocked();
6169 }
6170 }
John Spurlocke677d712014-02-13 12:52:19 -05006171
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006172 protected boolean isCallingUidSystem() {
6173 final int uid = Binder.getCallingUid();
6174 return uid == Process.SYSTEM_UID;
6175 }
6176
6177 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04006178 final int appid = UserHandle.getAppId(uid);
6179 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
6180 }
John Spurlockb408e8e2014-04-23 21:12:45 -04006181
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006182 // TODO: Most calls should probably move to isCallerSystem.
6183 protected boolean isCallerSystemOrPhone() {
6184 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04006185 }
6186
Julia Reynoldsb852e562017-06-06 16:14:18 -04006187 private void checkCallerIsSystemOrShell() {
6188 if (Binder.getCallingUid() == Process.SHELL_UID) {
6189 return;
6190 }
6191 checkCallerIsSystem();
6192 }
6193
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006194 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006195 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006196 return;
6197 }
6198 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
6199 }
6200
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006201 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006202 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006203 return;
6204 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04006205 checkCallerIsSameApp(pkg);
6206 }
6207
Brad Stenning8c991ea2018-07-31 13:33:01 -07006208 /**
6209 * Check if the notification is of a category type that is restricted to system use only,
6210 * if so throw SecurityException
6211 */
6212 private void checkRestrictedCategories(final Notification notification) {
6213 try {
6214 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) {
6215 return;
6216 }
6217 } catch (RemoteException re) {
6218 if (DBG) Log.e(TAG, "Unable to confirm if it's safe to skip category "
6219 + "restrictions check thus the check will be done anyway");
6220 }
6221 if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category)
6222 || Notification.CATEGORY_CAR_WARNING.equals(notification.category)
6223 || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) {
6224 checkCallerIsSystem();
6225 }
6226 }
6227
Chad Brubaker6b68f102017-01-27 13:39:00 -08006228 private boolean isCallerInstantApp(String pkg) {
6229 // System is always allowed to act for ephemeral apps.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006230 if (isCallerSystemOrPhone()) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08006231 return false;
6232 }
6233
6234 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
6235
6236 try {
6237 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
6238 UserHandle.getCallingUserId());
6239 if (ai == null) {
6240 throw new SecurityException("Unknown package " + pkg);
6241 }
6242 return ai.isInstantApp();
6243 } catch (RemoteException re) {
6244 throw new SecurityException("Unknown package " + pkg, re);
6245 }
6246
6247 }
6248
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006249 private void checkCallerIsSameApp(String pkg) {
John Spurlock7340fc82014-04-24 18:50:12 -04006250 final int uid = Binder.getCallingUid();
6251 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006252 ApplicationInfo ai = mPackageManager.getApplicationInfo(
John Spurlock7340fc82014-04-24 18:50:12 -04006253 pkg, 0, UserHandle.getCallingUserId());
Dan Sandler09afc2e2014-07-18 14:29:20 -04006254 if (ai == null) {
6255 throw new SecurityException("Unknown package " + pkg);
6256 }
John Spurlock7340fc82014-04-24 18:50:12 -04006257 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006258 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04006259 + pkg + " which is owned by uid " + ai.uid);
6260 }
6261 } catch (RemoteException re) {
6262 throw new SecurityException("Unknown package " + pkg + "\n" + re);
6263 }
6264 }
6265
John Spurlock32fe4c62014-10-02 12:16:02 -04006266 private static String callStateToString(int state) {
6267 switch (state) {
6268 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
6269 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
6270 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
6271 default: return "CALL_STATE_UNKNOWN_" + state;
6272 }
6273 }
6274
6275 private void listenForCallState() {
6276 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
6277 @Override
6278 public void onCallStateChanged(int state, String incomingNumber) {
6279 if (mCallState == state) return;
6280 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
6281 mCallState = state;
6282 }
6283 }, PhoneStateListener.LISTEN_CALL_STATE);
6284 }
6285
Christoph Studer05ad4822014-05-16 14:16:03 +02006286 /**
6287 * Generates a NotificationRankingUpdate from 'sbns', considering only
6288 * notifications visible to the given listener.
6289 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006290 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04006291 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04006292 final int N = mNotificationList.size();
6293 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02006294 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05006295 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04006296 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006297 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006298 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05006299 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006300 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05006301 Bundle overridePeople = new Bundle();
6302 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006303 Bundle showBadge = new Bundle();
Julia Reynolds503ed942017-10-04 16:04:56 -04006304 Bundle userSentiment = new Bundle();
Beverly5a20a5e2018-03-06 15:02:44 -05006305 Bundle hidden = new Bundle();
Tony Mak628cb932018-06-19 18:30:41 +01006306 Bundle smartActions = new Bundle();
Tony Makc9acf672018-07-20 13:58:24 +02006307 Bundle smartReplies = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04006308 for (int i = 0; i < N; i++) {
6309 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02006310 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006311 continue;
6312 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006313 final String key = record.sbn.getKey();
6314 keys.add(key);
6315 importance.add(record.getImportance());
6316 if (record.getImportanceExplanation() != null) {
6317 explanation.putCharSequence(key, record.getImportanceExplanation());
6318 }
Chris Wren333a61c2014-05-28 16:40:57 -04006319 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006320 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006321
Christoph Studer05ad4822014-05-16 14:16:03 +02006322 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006323 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006324 if (record.getPackageVisibilityOverride()
6325 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006326 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006327 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04006328 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05006329 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05006330 overridePeople.putStringArrayList(key, record.getPeopleOverride());
6331 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05006332 showBadge.putBoolean(key, record.canShowBadge());
Julia Reynolds503ed942017-10-04 16:04:56 -04006333 userSentiment.putInt(key, record.getUserSentiment());
Beverly5a20a5e2018-03-06 15:02:44 -05006334 hidden.putBoolean(key, record.isHidden());
Tony Mak628cb932018-06-19 18:30:41 +01006335 smartActions.putParcelableArrayList(key, record.getSmartActions());
Tony Makc9acf672018-07-20 13:58:24 +02006336 smartReplies.putCharSequenceArrayList(key, record.getSmartReplies());
Christoph Studer05ad4822014-05-16 14:16:03 +02006337 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006338 final int M = keys.size();
6339 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02006340 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05006341 int[] importanceAr = new int[M];
6342 for (int i = 0; i < M; i++) {
6343 importanceAr[i] = importance.get(i);
6344 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006345 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05006346 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Tony Mak628cb932018-06-19 18:30:41 +01006347 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden,
Tony Makc9acf672018-07-20 13:58:24 +02006348 smartActions, smartReplies);
Christoph Studer05ad4822014-05-16 14:16:03 +02006349 }
6350
Julia Reynoldsda781472017-04-12 09:41:16 -04006351 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006352 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04006353 mCompanionManager = getCompanionManager();
6354 }
6355 // Companion mgr doesn't exist on all device types
6356 if (mCompanionManager == null) {
6357 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006358 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006359 long identity = Binder.clearCallingIdentity();
6360 try {
6361 List<String> associations = mCompanionManager.getAssociations(
6362 info.component.getPackageName(), info.userid);
6363 if (!ArrayUtils.isEmpty(associations)) {
6364 return true;
6365 }
6366 } catch (SecurityException se) {
6367 // Not a privileged listener
6368 } catch (RemoteException re) {
6369 Slog.e(TAG, "Cannot reach companion device service", re);
6370 } catch (Exception e) {
6371 Slog.e(TAG, "Cannot verify listener " + info, e);
6372 } finally {
6373 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006374 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006375 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006376 }
6377
Julia Reynolds727a7282017-04-13 10:54:01 -04006378 protected ICompanionDeviceManager getCompanionManager() {
6379 return ICompanionDeviceManager.Stub.asInterface(
6380 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
6381 }
6382
Christoph Studercef37cf2014-07-25 14:18:17 +02006383 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
6384 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
6385 return false;
6386 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07006387 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02006388 return true;
6389 }
6390
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00006391 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Beverly2be7a052018-03-27 11:37:58 -04006392 final long identity = Binder.clearCallingIdentity();
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006393 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006394 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006395 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006396 } catch (RemoteException re) {
6397 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00006398 } catch (IllegalArgumentException ex) {
6399 // Package not found.
6400 return false;
Beverly2be7a052018-03-27 11:37:58 -04006401 } finally {
6402 Binder.restoreCallingIdentity(identity);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006403 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006404 }
6405
Kristian Monsen30f59b22018-04-09 10:27:16 +02006406 @VisibleForTesting
6407 boolean canUseManagedServices(String pkg) {
6408 boolean canUseManagedServices = !mActivityManager.isLowRamDevice()
Julia Reynoldse1816412017-10-24 10:39:11 -04006409 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
Kristian Monsen30f59b22018-04-09 10:27:16 +02006410
6411 for (String whitelisted : getContext().getResources().getStringArray(
6412 R.array.config_allowedManagedServicesOnLowRamDevices)) {
6413 if (whitelisted.equals(pkg)) {
6414 canUseManagedServices = true;
6415 }
6416 }
6417
6418 return canUseManagedServices;
Julia Reynoldse1816412017-10-24 10:39:11 -04006419 }
6420
Chris Wren47633422016-01-22 09:56:59 -05006421 private class TrimCache {
6422 StatusBarNotification heavy;
6423 StatusBarNotification sbnClone;
6424 StatusBarNotification sbnCloneLight;
6425
6426 TrimCache(StatusBarNotification sbn) {
6427 heavy = sbn;
6428 }
6429
6430 StatusBarNotification ForListener(ManagedServiceInfo info) {
6431 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
6432 if (sbnCloneLight == null) {
6433 sbnCloneLight = heavy.cloneLight();
6434 }
6435 return sbnCloneLight;
6436 } else {
6437 if (sbnClone == null) {
6438 sbnClone = heavy.clone();
6439 }
6440 return sbnClone;
6441 }
6442 }
6443 }
6444
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006445 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006446 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05006447
Julia Reynolds7380d872018-01-12 10:28:26 -05006448 public NotificationAssistants(Context context, Object lock, UserProfiles up,
6449 IPackageManager pm) {
6450 super(context, lock, up, pm);
Chris Wren51017d02015-12-15 15:34:46 -05006451 }
6452
6453 @Override
6454 protected Config getConfig() {
6455 Config c = new Config();
Julia Reynolds503ed942017-10-04 16:04:56 -04006456 c.caption = "notification assistant";
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006457 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006458 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006459 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
6460 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05006461 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006462 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05006463 return c;
6464 }
6465
6466 @Override
6467 protected IInterface asInterface(IBinder binder) {
6468 return INotificationListener.Stub.asInterface(binder);
6469 }
6470
6471 @Override
6472 protected boolean checkType(IInterface service) {
6473 return service instanceof INotificationListener;
6474 }
6475
6476 @Override
6477 protected void onServiceAdded(ManagedServiceInfo info) {
6478 mListeners.registerGuestService(info);
6479 }
6480
6481 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006482 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05006483 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
6484 mListeners.unregisterService(removed.service, removed.userid);
6485 }
Chris Wren47633422016-01-22 09:56:59 -05006486
Julia Reynoldsef934fd2018-02-01 14:39:17 -05006487 @Override
6488 public void onUserUnlocked(int user) {
6489 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
6490 rebindServices(true);
6491 }
6492
Chris Wren47633422016-01-22 09:56:59 -05006493 public void onNotificationEnqueued(final NotificationRecord r) {
6494 final StatusBarNotification sbn = r.sbn;
6495 TrimCache trimCache = new TrimCache(sbn);
6496
Chris Wren47633422016-01-22 09:56:59 -05006497 // There should be only one, but it's a list, so while we enforce
6498 // singularity elsewhere, we keep it general here, to avoid surprises.
Julia Reynolds00314d92017-04-14 10:01:24 -04006499 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04006500 boolean sbnVisible = isVisibleToListener(sbn, info)
6501 && info.isSameUser(r.getUserId());
Chris Wren47633422016-01-22 09:56:59 -05006502 if (!sbnVisible) {
6503 continue;
6504 }
6505
Chris Wren47633422016-01-22 09:56:59 -05006506 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006507 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05006508 @Override
6509 public void run() {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006510 notifyEnqueued(info, sbnToPost);
Chris Wren47633422016-01-22 09:56:59 -05006511 }
6512 });
6513 }
6514 }
6515
6516 private void notifyEnqueued(final ManagedServiceInfo info,
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006517 final StatusBarNotification sbn) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006518 final INotificationListener assistant = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05006519 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6520 try {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006521 assistant.onNotificationEnqueued(sbnHolder);
Chris Wren47633422016-01-22 09:56:59 -05006522 } catch (RemoteException ex) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006523 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Chris Wren47633422016-01-22 09:56:59 -05006524 }
6525 }
6526
Julia Reynolds79672302017-01-12 08:30:16 -05006527 /**
6528 * asynchronously notify the assistant that a notification has been snoozed until a
6529 * context
6530 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006531 @GuardedBy("mNotificationLock")
Julia Reynolds79672302017-01-12 08:30:16 -05006532 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
6533 final String snoozeCriterionId) {
6534 TrimCache trimCache = new TrimCache(sbn);
Julia Reynolds00314d92017-04-14 10:01:24 -04006535 for (final ManagedServiceInfo info : getServices()) {
Julia Reynolds503ed942017-10-04 16:04:56 -04006536 boolean sbnVisible = isVisibleToListener(sbn, info);
6537 if (!sbnVisible) {
6538 continue;
6539 }
Julia Reynolds79672302017-01-12 08:30:16 -05006540 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
6541 mHandler.post(new Runnable() {
6542 @Override
6543 public void run() {
6544 final INotificationListener assistant =
6545 (INotificationListener) info.service;
6546 StatusBarNotificationHolder sbnHolder
6547 = new StatusBarNotificationHolder(sbnToPost);
6548 try {
6549 assistant.onNotificationSnoozedUntilContext(
6550 sbnHolder, snoozeCriterionId);
6551 } catch (RemoteException ex) {
6552 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
6553 }
6554 }
6555 });
6556 }
6557 }
6558
Chris Wren47633422016-01-22 09:56:59 -05006559 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04006560 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05006561 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006562
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04006563 protected void ensureAssistant() {
6564 final List<UserInfo> activeUsers = mUm.getUsers(true);
6565 for (UserInfo userInfo : activeUsers) {
6566 int userId = userInfo.getUserHandle().getIdentifier();
6567 if (getAllowedPackages(userId).isEmpty()) {
6568 Slog.d(TAG, "Approving default notification assistant for user " + userId);
6569 readDefaultAssistant(userId);
6570 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006571 }
6572 }
Chris Wren51017d02015-12-15 15:34:46 -05006573 }
6574
John Spurlock7340fc82014-04-24 18:50:12 -04006575 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006576 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04006577
Christoph Studerb82bc782014-08-20 14:29:43 +02006578 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
6579
Julia Reynoldsb852e562017-06-06 16:14:18 -04006580 public NotificationListeners(IPackageManager pm) {
6581 super(getContext(), mNotificationLock, mUserProfiles, pm);
6582
John Spurlock7340fc82014-04-24 18:50:12 -04006583 }
6584
6585 @Override
6586 protected Config getConfig() {
6587 Config c = new Config();
6588 c.caption = "notification listener";
6589 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006590 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04006591 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
6592 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
6593 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
6594 c.clientLabel = R.string.notification_listener_binding_label;
6595 return c;
6596 }
6597
6598 @Override
6599 protected IInterface asInterface(IBinder binder) {
6600 return INotificationListener.Stub.asInterface(binder);
6601 }
6602
6603 @Override
Chris Wren51017d02015-12-15 15:34:46 -05006604 protected boolean checkType(IInterface service) {
6605 return service instanceof INotificationListener;
6606 }
6607
6608 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04006609 public void onServiceAdded(ManagedServiceInfo info) {
6610 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04006611 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006612 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04006613 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006614 }
John Spurlock7340fc82014-04-24 18:50:12 -04006615 try {
Chris Wren333a61c2014-05-28 16:40:57 -04006616 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04006617 } catch (RemoteException e) {
6618 // we tried
6619 }
6620 }
6621
John Spurlock1fa865f2014-07-21 14:56:39 -04006622 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006623 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04006624 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07006625 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006626 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01006627 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04006628 }
Christoph Studerb82bc782014-08-20 14:29:43 +02006629 mLightTrimListeners.remove(removed);
6630 }
6631
Julia Reynolds88860ce2017-06-01 16:55:49 -04006632 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02006633 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
6634 if (trim == TRIM_LIGHT) {
6635 mLightTrimListeners.add(info);
6636 } else {
6637 mLightTrimListeners.remove(info);
6638 }
6639 }
6640
6641 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
6642 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04006643 }
6644
John Spurlock7340fc82014-04-24 18:50:12 -04006645 /**
6646 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02006647 *
6648 * <p>
6649 * Also takes care of removing a notification that has been visible to a listener before,
6650 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04006651 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006652 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006653 public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
6654 notifyPostedLocked(r, old, true);
Beverly5a20a5e2018-03-06 15:02:44 -05006655 }
6656
6657 /**
6658 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
6659 * targetting <= O_MR1
6660 */
6661 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006662 private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
Beverly5a20a5e2018-03-06 15:02:44 -05006663 boolean notifyAllListeners) {
Christoph Studerb82bc782014-08-20 14:29:43 +02006664 // Lazily initialized snapshots of the notification.
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006665 StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006666 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Chris Wren47633422016-01-22 09:56:59 -05006667 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02006668
Julia Reynolds00314d92017-04-14 10:01:24 -04006669 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02006670 boolean sbnVisible = isVisibleToListener(sbn, info);
6671 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
6672 // This notification hasn't been and still isn't visible -> ignore.
6673 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006674 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04006675 }
Beverly5a20a5e2018-03-06 15:02:44 -05006676
6677 // If the notification is hidden, don't notifyPosted listeners targeting < P.
6678 // Instead, those listeners will receive notifyPosted when the notification is
6679 // unhidden.
6680 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
6681 continue;
6682 }
6683
6684 // If we shouldn't notify all listeners, this means the hidden state of
6685 // a notification was changed. Don't notifyPosted listeners targeting >= P.
6686 // Instead, those listeners will receive notifyRankingUpdate.
6687 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6688 continue;
6689 }
6690
Chris Wren333a61c2014-05-28 16:40:57 -04006691 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02006692
6693 // This notification became invisible -> remove the old one.
6694 if (oldSbnVisible && !sbnVisible) {
6695 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
6696 mHandler.post(new Runnable() {
6697 @Override
6698 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04006699 notifyRemoved(
6700 info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02006701 }
6702 });
Christoph Studer05ad4822014-05-16 14:16:03 +02006703 continue;
6704 }
Christoph Studercef37cf2014-07-25 14:18:17 +02006705
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006706 // Grant access before listener is notified
6707 final int targetUserId = (info.userid == UserHandle.USER_ALL)
6708 ? UserHandle.USER_SYSTEM : info.userid;
6709 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006710
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006711 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006712 mHandler.post(new Runnable() {
6713 @Override
6714 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02006715 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02006716 }
6717 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006718 }
6719 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006720
John Spurlock7340fc82014-04-24 18:50:12 -04006721 /**
6722 * asynchronously notify all listeners about a removed notification
6723 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006724 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05006725 public void notifyRemovedLocked(NotificationRecord r, int reason,
Julia Reynolds503ed942017-10-04 16:04:56 -04006726 NotificationStats notificationStats) {
Beverly5a20a5e2018-03-06 15:02:44 -05006727 final StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006728
John Spurlock7340fc82014-04-24 18:50:12 -04006729 // make a copy in case changes are made to the underlying Notification object
6730 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
6731 // notification
6732 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04006733 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02006734 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006735 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04006736 }
Beverly5a20a5e2018-03-06 15:02:44 -05006737
6738 // don't notifyRemoved for listeners targeting < P
6739 // if not for reason package suspended
6740 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
6741 && info.targetSdkVersion < Build.VERSION_CODES.P) {
6742 continue;
6743 }
6744
6745 // don't notifyRemoved for listeners targeting >= P
6746 // if the reason is package suspended
6747 if (reason == REASON_PACKAGE_SUSPENDED
6748 && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6749 continue;
6750 }
6751
Julia Reynolds503ed942017-10-04 16:04:56 -04006752 // Only assistants can get stats
6753 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
6754 ? notificationStats : null;
Chris Wren333a61c2014-05-28 16:40:57 -04006755 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006756 mHandler.post(new Runnable() {
6757 @Override
6758 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04006759 notifyRemoved(info, sbnLight, update, stats, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02006760 }
6761 });
Chris Wrenf9536642014-04-17 10:01:54 -04006762 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006763
6764 // Revoke access after all listeners have been updated
6765 mHandler.post(() -> {
6766 updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM);
6767 });
Chris Wrenf9536642014-04-17 10:01:54 -04006768 }
6769
6770 /**
Beverly5a20a5e2018-03-06 15:02:44 -05006771 * Asynchronously notify all listeners about a reordering of notifications
6772 * unless changedHiddenNotifications is populated.
6773 * If changedHiddenNotifications is populated, there was a change in the hidden state
6774 * of the notifications. In this case, we only send updates to listeners that
6775 * target >= P.
Chris Wrenf9536642014-04-17 10:01:54 -04006776 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006777 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05006778 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
6779 boolean isHiddenRankingUpdate = changedHiddenNotifications != null
6780 && changedHiddenNotifications.size() > 0;
6781
Julia Reynolds00314d92017-04-14 10:01:24 -04006782 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006783 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6784 continue;
6785 }
Beverly5a20a5e2018-03-06 15:02:44 -05006786
6787 boolean notifyThisListener = false;
6788 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
6789 Build.VERSION_CODES.P) {
6790 for (NotificationRecord rec : changedHiddenNotifications) {
6791 if (isVisibleToListener(rec.sbn, serviceInfo)) {
6792 notifyThisListener = true;
6793 break;
6794 }
John Spurlock7340fc82014-04-24 18:50:12 -04006795 }
Beverly5a20a5e2018-03-06 15:02:44 -05006796 }
6797
6798 if (notifyThisListener || !isHiddenRankingUpdate) {
6799 final NotificationRankingUpdate update = makeRankingUpdateLocked(
6800 serviceInfo);
6801
6802 mHandler.post(new Runnable() {
6803 @Override
6804 public void run() {
6805 notifyRankingUpdate(serviceInfo, update);
6806 }
6807 });
6808 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006809 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006810 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006811
Julia Reynolds88860ce2017-06-01 16:55:49 -04006812 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04006813 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006814 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04006815 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6816 continue;
6817 }
6818 mHandler.post(new Runnable() {
6819 @Override
6820 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006821 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006822 }
6823 });
6824 }
6825 }
6826
Beverly5a20a5e2018-03-06 15:02:44 -05006827 /**
6828 * asynchronously notify relevant listeners their notification is hidden
6829 * NotificationListenerServices that target P+:
6830 * NotificationListenerService#notifyRankingUpdateLocked()
6831 * NotificationListenerServices that target <= P:
6832 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
6833 */
6834 @GuardedBy("mNotificationLock")
6835 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
6836 if (changedNotifications == null || changedNotifications.size() == 0) {
6837 return;
6838 }
6839
6840 notifyRankingUpdateLocked(changedNotifications);
6841
6842 // for listeners that target < P, notifyRemoveLocked
6843 int numChangedNotifications = changedNotifications.size();
6844 for (int i = 0; i < numChangedNotifications; i++) {
6845 NotificationRecord rec = changedNotifications.get(i);
6846 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
6847 }
6848 }
6849
6850 /**
6851 * asynchronously notify relevant listeners their notification is unhidden
6852 * NotificationListenerServices that target P+:
6853 * NotificationListenerService#notifyRankingUpdateLocked()
6854 * NotificationListenerServices that target <= P:
6855 * NotificationListeners#notifyPostedLocked()
6856 */
6857 @GuardedBy("mNotificationLock")
6858 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
6859 if (changedNotifications == null || changedNotifications.size() == 0) {
6860 return;
6861 }
6862
6863 notifyRankingUpdateLocked(changedNotifications);
6864
6865 // for listeners that target < P, notifyPostedLocked
6866 int numChangedNotifications = changedNotifications.size();
6867 for (int i = 0; i < numChangedNotifications; i++) {
6868 NotificationRecord rec = changedNotifications.get(i);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006869 mListeners.notifyPostedLocked(rec, rec, false);
Beverly5a20a5e2018-03-06 15:02:44 -05006870 }
6871 }
6872
Christoph Studer85a384b2014-08-27 20:16:15 +02006873 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006874 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02006875 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6876 continue;
6877 }
6878 mHandler.post(new Runnable() {
6879 @Override
6880 public void run() {
6881 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
6882 }
6883 });
6884 }
6885 }
6886
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006887 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006888 final NotificationChannel channel, final int modificationType) {
6889 if (channel == null) {
6890 return;
6891 }
6892 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04006893 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006894 continue;
6895 }
Julia Reynolds018aa622017-04-20 11:31:30 -04006896
Eugene Suslaa25d17f2017-08-24 11:28:08 -07006897 BackgroundThread.getHandler().post(() -> {
6898 if (hasCompanionDevice(serviceInfo)) {
6899 notifyNotificationChannelChanged(
6900 serviceInfo, pkg, user, channel, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04006901 }
6902 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006903 }
6904 }
6905
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006906 protected void notifyNotificationChannelGroupChanged(
6907 final String pkg, final UserHandle user, final NotificationChannelGroup group,
6908 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006909 if (group == null) {
6910 return;
6911 }
6912 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04006913 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006914 continue;
6915 }
Julia Reynolds018aa622017-04-20 11:31:30 -04006916
Eugene Suslaa25d17f2017-08-24 11:28:08 -07006917 BackgroundThread.getHandler().post(() -> {
6918 if (hasCompanionDevice(serviceInfo)) {
6919 notifyNotificationChannelGroupChanged(
6920 serviceInfo, pkg, user, group, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04006921 }
6922 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006923 }
6924 }
6925
Christoph Studercef37cf2014-07-25 14:18:17 +02006926 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02006927 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04006928 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006929 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04006930 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07006931 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04006932 } catch (RemoteException ex) {
6933 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
6934 }
6935 }
6936
Christoph Studercef37cf2014-07-25 14:18:17 +02006937 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds503ed942017-10-04 16:04:56 -04006938 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04006939 if (!info.enabledAndUserMatches(sbn.getUserId())) {
6940 return;
6941 }
Christoph Studer05ad4822014-05-16 14:16:03 +02006942 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006943 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04006944 try {
Julia Reynolds503ed942017-10-04 16:04:56 -04006945 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04006946 } catch (RemoteException ex) {
6947 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04006948 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006949 }
Chris Wrenf9536642014-04-17 10:01:54 -04006950
Christoph Studer05ad4822014-05-16 14:16:03 +02006951 private void notifyRankingUpdate(ManagedServiceInfo info,
6952 NotificationRankingUpdate rankingUpdate) {
6953 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04006954 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02006955 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04006956 } catch (RemoteException ex) {
6957 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
6958 }
6959 }
John Spurlock1fa865f2014-07-21 14:56:39 -04006960
John Spurlockd8afe3c2014-08-01 14:04:07 -04006961 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04006962 final INotificationListener listener = (INotificationListener) info.service;
6963 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006964 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006965 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006966 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04006967 }
6968 }
Justin Koh38156c52014-06-04 13:57:49 -07006969
Christoph Studer85a384b2014-08-27 20:16:15 +02006970 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
6971 int interruptionFilter) {
6972 final INotificationListener listener = (INotificationListener) info.service;
6973 try {
6974 listener.onInterruptionFilterChanged(interruptionFilter);
6975 } catch (RemoteException ex) {
6976 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
6977 }
6978 }
6979
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006980 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006981 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006982 final int modificationType) {
6983 final INotificationListener listener = (INotificationListener) info.service;
6984 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006985 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006986 } catch (RemoteException ex) {
6987 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
6988 }
6989 }
6990
6991 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006992 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006993 final int modificationType) {
6994 final INotificationListener listener = (INotificationListener) info.service;
6995 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006996 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006997 } catch (RemoteException ex) {
6998 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
6999 }
7000 }
7001
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007002 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07007003 if (packageName == null) {
7004 return false;
7005 }
7006 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007007 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04007008 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07007009 if (packageName.equals(serviceInfo.component.getPackageName())) {
7010 return true;
7011 }
7012 }
7013 }
7014 return false;
7015 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007016 }
John Spurlock25e2d242014-06-27 13:58:23 -04007017
7018 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04007019 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04007020 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04007021 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04007022 public long since;
7023 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04007024 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05007025 public boolean proto = false;
Vishnu Naire3e4d252018-03-01 11:26:57 -08007026 public boolean criticalPriority = false;
7027 public boolean normalPriority = false;
John Spurlock25e2d242014-06-27 13:58:23 -04007028
Kweku Adams887f09c2017-11-13 17:12:20 -08007029 @NonNull
John Spurlock25e2d242014-06-27 13:58:23 -04007030 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04007031 final DumpFilter filter = new DumpFilter();
7032 for (int ai = 0; ai < args.length; ai++) {
7033 final String a = args[ai];
Kweku Adams62b42242017-09-25 12:54:02 -07007034 if ("--proto".equals(a)) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05007035 filter.proto = true;
Kweku Adams62b42242017-09-25 12:54:02 -07007036 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
Dan Sandlera1770312015-07-10 13:59:29 -04007037 filter.redact = false;
7038 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
7039 if (ai < args.length-1) {
7040 ai++;
7041 filter.pkgFilter = args[ai].trim().toLowerCase();
7042 if (filter.pkgFilter.isEmpty()) {
7043 filter.pkgFilter = null;
7044 } else {
7045 filter.filtered = true;
7046 }
7047 }
7048 } else if ("--zen".equals(a) || "zen".equals(a)) {
7049 filter.filtered = true;
7050 filter.zen = true;
7051 } else if ("--stats".equals(a)) {
7052 filter.stats = true;
7053 if (ai < args.length-1) {
7054 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01007055 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04007056 } else {
7057 filter.since = 0;
7058 }
Vishnu Naire3e4d252018-03-01 11:26:57 -08007059 } else if (PRIORITY_ARG.equals(a)) {
7060 // Bugreport will call the service twice with priority arguments, first to dump
7061 // critical sections and then non critical ones. Set approriate filters
7062 // to generate the desired data.
7063 if (ai < args.length - 1) {
7064 ai++;
7065 switch (args[ai]) {
7066 case PRIORITY_ARG_CRITICAL:
7067 filter.criticalPriority = true;
7068 break;
7069 case PRIORITY_ARG_NORMAL:
7070 filter.normalPriority = true;
7071 break;
7072 }
7073 }
Dan Sandlera1770312015-07-10 13:59:29 -04007074 }
John Spurlock25e2d242014-06-27 13:58:23 -04007075 }
Dan Sandlera1770312015-07-10 13:59:29 -04007076 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04007077 }
7078
7079 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04007080 if (!filtered) return true;
7081 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04007082 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04007083 }
7084
7085 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04007086 if (!filtered) return true;
7087 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04007088 }
7089
7090 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04007091 if (!filtered) return true;
7092 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04007093 }
7094
7095 @Override
7096 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04007097 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04007098 }
7099 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07007100
Beverly5a20a5e2018-03-06 15:02:44 -05007101 @VisibleForTesting
7102 protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
7103 // only use for testing: mimic receive broadcast that package is (un)suspended
7104 // but does not actually (un)suspend the package
7105 final Bundle extras = new Bundle();
7106 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
7107 new String[]{pkg});
7108
7109 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
7110 : Intent.ACTION_PACKAGES_UNSUSPENDED;
7111 final Intent intent = new Intent(action);
7112 intent.putExtras(extras);
7113
7114 mPackageIntentReceiver.onReceive(getContext(), intent);
7115 }
7116
Griff Hazen84a00ea2014-09-02 17:10:47 -07007117 /**
7118 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
7119 * binder without sending large amounts of data over a oneway transaction.
7120 */
7121 private static final class StatusBarNotificationHolder
7122 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07007123 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007124
7125 public StatusBarNotificationHolder(StatusBarNotification value) {
7126 mValue = value;
7127 }
7128
Griff Hazene9aac5f2014-09-05 20:04:09 -07007129 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07007130 @Override
7131 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07007132 StatusBarNotification value = mValue;
7133 mValue = null;
7134 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007135 }
7136 }
John Spurlock7c74f782015-06-04 13:01:42 -04007137
Julia Reynoldsb852e562017-06-06 16:14:18 -04007138 private class ShellCmd extends ShellCommand {
7139 public static final String USAGE = "help\n"
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007140 + "allow_listener COMPONENT [user_id]\n"
7141 + "disallow_listener COMPONENT [user_id]\n"
Julia Reynolds7380d872018-01-12 10:28:26 -05007142 + "allow_assistant COMPONENT\n"
Julia Reynoldseb3dca72017-07-11 10:39:58 -04007143 + "remove_assistant COMPONENT\n"
Julia Reynoldsb852e562017-06-06 16:14:18 -04007144 + "allow_dnd PACKAGE\n"
Beverly5a20a5e2018-03-06 15:02:44 -05007145 + "disallow_dnd PACKAGE\n"
7146 + "suspend_package PACKAGE\n"
7147 + "unsuspend_package PACKAGE";
John Spurlock7c74f782015-06-04 13:01:42 -04007148
Julia Reynoldsb852e562017-06-06 16:14:18 -04007149 @Override
7150 public int onCommand(String cmd) {
Felipe Leme68d80412017-07-14 11:18:08 -07007151 if (cmd == null) {
7152 return handleDefaultCommands(cmd);
7153 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007154 final PrintWriter pw = getOutPrintWriter();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04007155 try {
Julia Reynoldsb852e562017-06-06 16:14:18 -04007156 switch (cmd) {
7157 case "allow_dnd": {
7158 getBinderService().setNotificationPolicyAccessGranted(
7159 getNextArgRequired(), true);
John Spurlock7c74f782015-06-04 13:01:42 -04007160 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04007161 break;
7162
7163 case "disallow_dnd": {
7164 getBinderService().setNotificationPolicyAccessGranted(
7165 getNextArgRequired(), false);
7166 }
7167 break;
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007168 case "allow_listener": {
7169 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7170 if (cn == null) {
7171 pw.println("Invalid listener - must be a ComponentName");
7172 return -1;
7173 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007174 String userId = getNextArg();
7175 if (userId == null) {
7176 getBinderService().setNotificationListenerAccessGranted(cn, true);
7177 } else {
7178 getBinderService().setNotificationListenerAccessGrantedForUser(
7179 cn, Integer.parseInt(userId), true);
7180 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007181 }
7182 break;
7183 case "disallow_listener": {
7184 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7185 if (cn == null) {
7186 pw.println("Invalid listener - must be a ComponentName");
7187 return -1;
7188 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007189 String userId = getNextArg();
7190 if (userId == null) {
7191 getBinderService().setNotificationListenerAccessGranted(cn, false);
7192 } else {
7193 getBinderService().setNotificationListenerAccessGrantedForUser(
7194 cn, Integer.parseInt(userId), false);
7195 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007196 }
7197 break;
Julia Reynoldseb3dca72017-07-11 10:39:58 -04007198 case "allow_assistant": {
7199 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7200 if (cn == null) {
7201 pw.println("Invalid assistant - must be a ComponentName");
7202 return -1;
7203 }
7204 getBinderService().setNotificationAssistantAccessGranted(cn, true);
7205 }
7206 break;
7207 case "disallow_assistant": {
7208 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7209 if (cn == null) {
7210 pw.println("Invalid assistant - must be a ComponentName");
7211 return -1;
7212 }
7213 getBinderService().setNotificationAssistantAccessGranted(cn, false);
7214 }
7215 break;
Beverly5a20a5e2018-03-06 15:02:44 -05007216 case "suspend_package": {
7217 // only use for testing
7218 simulatePackageSuspendBroadcast(true, getNextArgRequired());
7219 }
7220 break;
7221 case "unsuspend_package": {
7222 // only use for testing
7223 simulatePackageSuspendBroadcast(false, getNextArgRequired());
7224 }
7225 break;
Julia Reynoldsb852e562017-06-06 16:14:18 -04007226 default:
7227 return handleDefaultCommands(cmd);
John Spurlock7c74f782015-06-04 13:01:42 -04007228 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007229 } catch (Exception e) {
7230 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
Julia Reynoldsb852e562017-06-06 16:14:18 -04007231 Slog.e(TAG, "Error running shell command", e);
John Spurlock7c74f782015-06-04 13:01:42 -04007232 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04007233 return 0;
John Spurlock7c74f782015-06-04 13:01:42 -04007234 }
7235
Julia Reynoldsb852e562017-06-06 16:14:18 -04007236 @Override
7237 public void onHelp() {
7238 getOutPrintWriter().println(USAGE);
John Spurlock7c74f782015-06-04 13:01:42 -04007239 }
7240 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007241}