blob: 58a1dc1468084716767f2ff502e70f8ced4c4ddc [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;
Amith Yamasanib7358302018-09-05 18:52:35 -070036import static android.content.Context.BIND_ADJUST_BELOW_PERCEPTIBLE;
37import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
38import static android.content.Context.BIND_AUTO_CREATE;
39import static android.content.Context.BIND_FOREGROUND_SERVICE;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -050040import static android.content.pm.PackageManager.FEATURE_LEANBACK;
41import static android.content.pm.PackageManager.FEATURE_TELEVISION;
Julia Reynolds4db59552017-06-30 13:34:01 -040042import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Vishnu Naire3e4d252018-03-01 11:26:57 -080043import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
44import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
Julia Reynolds88a879f2017-07-26 17:06:46 -040045import static android.os.UserHandle.USER_NULL;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040046import static android.os.UserHandle.USER_SYSTEM;
Julia Reynolds73ed76b2017-04-04 17:04:38 -040047import static android.service.notification.NotificationListenerService
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050048 .HINT_HOST_DISABLE_CALL_EFFECTS;
49import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
50import static android.service.notification.NotificationListenerService
51 .HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
52import static android.service.notification.NotificationListenerService
Julia Reynolds73ed76b2017-04-04 17:04:38 -040053 .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
54import static android.service.notification.NotificationListenerService
55 .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
56import static android.service.notification.NotificationListenerService
57 .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050058import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
59import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040060import static android.service.notification.NotificationListenerService.REASON_CANCEL;
61import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050062import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040063import static android.service.notification.NotificationListenerService.REASON_CLICK;
64import static android.service.notification.NotificationListenerService.REASON_ERROR;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050065import static android.service.notification.NotificationListenerService
66 .REASON_GROUP_SUMMARY_CANCELED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050067import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
68import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
69import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
70import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
71import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
72import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
73import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
Julia Reynolds2a128742016-11-28 14:29:25 -050074import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050075import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
76import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
Christoph Studerb82bc782014-08-20 14:29:43 +020077import static android.service.notification.NotificationListenerService.TRIM_FULL;
78import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
Wale Ogunwaleac2561e2016-11-01 15:43:46 -070079import static android.view.Display.DEFAULT_DISPLAY;
80import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
svetoslavganov75986cf2009-05-14 22:28:01 -070081
Vishnu Naire3e4d252018-03-01 11:26:57 -080082import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
83import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
84import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
85
Chris Wren51017d02015-12-15 15:34:46 -050086import android.Manifest;
Julia Reynoldsa78cdff2017-04-26 10:19:25 -040087import android.annotation.NonNull;
Wei Liu97e56662016-03-04 10:52:33 -080088import android.annotation.Nullable;
Dianne Hackborn41203752012-08-31 14:05:51 -070089import android.app.ActivityManager;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070090import android.app.ActivityManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -050091import android.app.AlarmManager;
John Spurlock7340fc82014-04-24 18:50:12 -040092import android.app.AppGlobals;
Daniel Sandler4a900ac2013-01-30 14:04:10 -050093import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040094import android.app.AutomaticZenRule;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.app.IActivityManager;
96import android.app.INotificationManager;
97import android.app.ITransientNotification;
98import android.app.Notification;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040099import android.app.NotificationChannel;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500100import android.app.NotificationChannelGroup;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500101import android.app.NotificationManager;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500102import android.app.NotificationManager.Policy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103import android.app.PendingIntent;
104import android.app.StatusBarManager;
Jason Parks50322ff2018-03-27 10:23:33 -0500105import android.app.admin.DeviceAdminInfo;
106import android.app.admin.DevicePolicyManagerInternal;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500107import android.app.backup.BackupManager;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700108import android.app.usage.UsageEvents;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700109import android.app.usage.UsageStatsManagerInternal;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400110import android.companion.ICompanionDeviceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111import android.content.BroadcastReceiver;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700112import android.content.ComponentName;
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400113import android.content.ContentProvider;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700114import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import android.content.Context;
116import android.content.Intent;
117import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -0400118import android.content.pm.ApplicationInfo;
Kenny Guy70058402014-10-28 20:45:06 +0000119import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120import android.content.pm.PackageManager;
121import android.content.pm.PackageManager.NameNotFoundException;
Christoph Studercee44ba2014-05-20 18:36:43 +0200122import android.content.pm.ParceledListSlice;
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400123import android.content.pm.UserInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700125import android.database.ContentObserver;
Beverly5d463b62017-07-26 14:13:40 -0400126import android.media.AudioAttributes;
svetoslavganov75986cf2009-05-14 22:28:01 -0700127import android.media.AudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500128import android.media.AudioManagerInternal;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700129import android.media.IRingtonePlayer;
Kenny Guy23991102018-04-05 21:18:38 +0100130import android.metrics.LogMaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132import android.os.Binder;
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -0400133import android.os.Build;
John Spurlock2b122f42014-08-27 16:29:47 -0400134import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -0400135import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136import android.os.Handler;
Chris Wrenf9536642014-04-17 10:01:54 -0400137import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138import android.os.IBinder;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800139import android.os.IDeviceIdleController;
John Spurlock7340fc82014-04-24 18:50:12 -0400140import android.os.IInterface;
Chris Wrenf9536642014-04-17 10:01:54 -0400141import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700143import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -0700144import android.os.RemoteException;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400145import android.os.ResultReceiver;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400146import android.os.ServiceManager;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400147import android.os.ShellCallback;
148import android.os.ShellCommand;
Chris Wrenc8673a82016-05-17 17:11:29 -0400149import android.os.SystemClock;
Selim Cinekb5605e52015-02-20 18:21:41 +0100150import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700151import android.os.UserHandle;
Michael Wright71216972017-01-31 18:33:54 +0000152import android.os.VibrationEffect;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500153import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154import android.provider.Settings;
Julia Reynoldse46bb372016-03-17 11:05:58 -0400155import android.service.notification.Adjustment;
Chris Wren333a61c2014-05-28 16:40:57 -0400156import android.service.notification.Condition;
John Spurlock7340fc82014-04-24 18:50:12 -0400157import android.service.notification.IConditionProvider;
Chris Wren333a61c2014-05-28 16:40:57 -0400158import android.service.notification.INotificationListener;
Griff Hazen84a00ea2014-09-02 17:10:47 -0700159import android.service.notification.IStatusBarNotificationHolder;
Kweku Adams93304b62017-09-20 17:03:00 -0700160import android.service.notification.ListenersDisablingEffectsProto;
Julia Reynolds77b2cc92016-11-08 14:41:09 -0500161import android.service.notification.NotificationAssistantService;
John Spurlock7340fc82014-04-24 18:50:12 -0400162import android.service.notification.NotificationListenerService;
Christoph Studer05ad4822014-05-16 14:16:03 +0200163import android.service.notification.NotificationRankingUpdate;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500164import android.service.notification.NotificationRecordProto;
165import android.service.notification.NotificationServiceDumpProto;
Julia Reynolds503ed942017-10-04 16:04:56 -0400166import android.service.notification.NotificationStats;
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500167import android.service.notification.NotifyingApp;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500168import android.service.notification.SnoozeCriterion;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700169import android.service.notification.StatusBarNotification;
John Spurlock056c5192014-04-20 21:52:01 -0400170import android.service.notification.ZenModeConfig;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500171import android.service.notification.ZenModeProto;
John Spurlock32fe4c62014-10-02 12:16:02 -0400172import android.telephony.PhoneStateListener;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500173import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -0700174import android.text.TextUtils;
John Spurlocka4294292014-03-24 18:02:32 -0400175import android.util.ArrayMap;
John Spurlock1fa865f2014-07-21 14:56:39 -0400176import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700177import android.util.AtomicFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -0800179import android.util.Slog;
Bryce Lee7219ada2016-04-08 10:54:23 -0700180import android.util.SparseArray;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400181import android.util.Xml;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500182import android.util.proto.ProtoOutputStream;
svetoslavganov75986cf2009-05-14 22:28:01 -0700183import android.view.accessibility.AccessibilityEvent;
184import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185import android.widget.Toast;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000186
Scott Greenwald9a05b312013-06-28 00:37:54 -0400187import com.android.internal.R;
Julia Reynolds88860ce2017-06-01 16:55:49 -0400188import com.android.internal.annotations.GuardedBy;
Chris Wren93bb8b82016-03-29 14:35:05 -0400189import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -0500190import com.android.internal.logging.MetricsLogger;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500191import com.android.internal.logging.nano.MetricsProto;
Chris Wren9eb5e102017-01-26 13:15:06 -0500192import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Beverly70dcd002018-03-29 17:09:16 -0400193import com.android.internal.notification.SystemNotificationChannels;
Eugene Suslaa25d17f2017-08-24 11:28:08 -0700194import com.android.internal.os.BackgroundThread;
Chris Wrend1dbc922015-06-19 17:51:16 -0400195import com.android.internal.statusbar.NotificationVisibility;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400196import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600197import com.android.internal.util.DumpUtils;
John Spurlock056c5192014-04-20 21:52:01 -0400198import com.android.internal.util.FastXmlSerializer;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400199import com.android.internal.util.Preconditions;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400200import com.android.internal.util.XmlUtils;
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700201import com.android.server.DeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800202import com.android.server.EventLogTags;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700203import com.android.server.LocalServices;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800204import com.android.server.SystemService;
205import com.android.server.lights.Light;
206import com.android.server.lights.LightsManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400207import com.android.server.notification.ManagedServices.ManagedServiceInfo;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500208import com.android.server.notification.ManagedServices.UserProfiles;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700209import com.android.server.policy.PhoneWindowManager;
John Spurlockb408e8e2014-04-23 21:12:45 -0400210import com.android.server.statusbar.StatusBarManagerInternal;
Adrian Roose99bc052017-11-20 17:55:31 +0100211import com.android.server.wm.WindowManagerInternal;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800212
John Spurlockb408e8e2014-04-23 21:12:45 -0400213import libcore.io.IoUtils;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000214
Chris Wrene4b38802015-07-07 15:54:19 -0400215import org.json.JSONException;
216import org.json.JSONObject;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700217import org.xmlpull.v1.XmlPullParser;
218import org.xmlpull.v1.XmlPullParserException;
John Spurlock056c5192014-04-20 21:52:01 -0400219import org.xmlpull.v1.XmlSerializer;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700220
John Spurlock35ef0a62015-05-28 11:24:10 -0400221import java.io.ByteArrayInputStream;
222import java.io.ByteArrayOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400223import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400225import java.io.FileNotFoundException;
John Spurlock056c5192014-04-20 21:52:01 -0400226import java.io.FileOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400227import java.io.IOException;
John Spurlock35ef0a62015-05-28 11:24:10 -0400228import java.io.InputStream;
229import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100231import java.nio.charset.StandardCharsets;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500232import java.util.ArrayDeque;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233import java.util.ArrayList;
Michael Wrightbc4d0d92017-03-23 18:57:57 +0000234import java.util.Arrays;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500235import java.util.Iterator;
John Spurlock7c74f782015-06-04 13:01:42 -0400236import java.util.List;
Christoph Studer265c1052014-07-23 17:14:33 +0200237import java.util.Map.Entry;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500238import java.util.Objects;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400239import java.util.Set;
Chris Wren51017d02015-12-15 15:34:46 -0500240import java.util.concurrent.TimeUnit;
Kristian Monsen30f59b22018-04-09 10:27:16 +0200241import java.util.function.Predicate;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400242
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400243/** {@hide} */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800244public class NotificationManagerService extends SystemService {
245 static final String TAG = "NotificationService";
Christoph Studer1f32c652014-11-26 15:32:20 +0100246 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Selim Cinek40412492015-12-08 18:03:22 -0800247 public static final boolean ENABLE_CHILD_NOTIFICATIONS
248 = SystemProperties.getBoolean("debug.child_notifs", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249
Dan Sandler7d67bd42018-05-15 14:06:38 -0400250 static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
251 "debug.notification.interruptiveness", false);
252
Adam Lesinski182f73f2013-12-05 16:48:06 -0800253 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
Julia Reynolds6ad0aec2017-07-05 08:47:03 -0400254 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
Joe Onoratobd73d012010-06-04 11:44:54 -0700255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 // message codes
Robert Carr997427342018-02-28 18:06:10 -0800257 static final int MESSAGE_DURATION_REACHED = 2;
John Spurlock056c5192014-04-20 21:52:01 -0400258 static final int MESSAGE_SAVE_POLICY_FILE = 3;
Chris Wren51017d02015-12-15 15:34:46 -0500259 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
260 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
261 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
Robert Carr997427342018-02-28 18:06:10 -0800262 static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
Chris Wren51017d02015-12-15 15:34:46 -0500263
264 // ranking thread messages
265 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
266 private static final int MESSAGE_RANKING_SORT = 1001;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700268 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800269 static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800270
Robert Carr3406d462018-03-15 16:19:07 -0700271 // 1 second past the ANR timeout.
272 static final int FINISH_TOKEN_TIMEOUT = 11 * 1000;
273
Adam Lesinski182f73f2013-12-05 16:48:06 -0800274 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
Christoph Studer265c1052014-07-23 17:14:33 +0200275
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500276 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
277
Adam Lesinski182f73f2013-12-05 16:48:06 -0800278 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279
Adam Lesinski182f73f2013-12-05 16:48:06 -0800280 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler526fa0e2012-12-04 14:51:50 -0500281
Adam Lesinski182f73f2013-12-05 16:48:06 -0800282 static final boolean ENABLE_BLOCKED_TOASTS = true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400283
Christoph Studer12aeda82014-09-23 19:08:56 +0200284 // When #matchesCallFilter is called from the ringer, wait at most
285 // 3s to resolve the contacts. This timeout is required since
286 // ContactsProvider might take a long time to start up.
287 //
288 // Return STARRED_CONTACT when the timeout is hit in order to avoid
289 // missed calls in ZEN mode "Important".
290 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
291 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
292 ValidateNotificationPeople.STARRED_CONTACT;
293
Christoph Studer265c1052014-07-23 17:14:33 +0200294 /** notification_enqueue status value for a newly enqueued notification. */
295 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
296
297 /** notification_enqueue status value for an existing notification. */
298 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
299
300 /** notification_enqueue status value for an ignored notification. */
301 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
Chris Wrenc8673a82016-05-17 17:11:29 -0400302 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
Christoph Studer265c1052014-07-23 17:14:33 +0200303
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500304 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
305
Julia Reynolds2a128742016-11-28 14:29:25 -0500306 private static final String ACTION_NOTIFICATION_TIMEOUT =
307 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
308 private static final int REQUEST_CODE_TIMEOUT = 1;
309 private static final String SCHEME_TIMEOUT = "timeout";
310 private static final String EXTRA_KEY = "key";
311
Adam Lesinski182f73f2013-12-05 16:48:06 -0800312 private IActivityManager mAm;
Julia Reynolds68263d12017-06-21 14:21:19 -0400313 private ActivityManager mActivityManager;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500314 private IPackageManager mPackageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500315 private PackageManager mPackageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800316 AudioManager mAudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500317 AudioManagerInternal mAudioManagerInternal;
Wei Liu97e56662016-03-04 10:52:33 -0800318 @Nullable StatusBarManagerInternal mStatusBar;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800319 Vibrator mVibrator;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700320 private WindowManagerInternal mWindowManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -0500321 private AlarmManager mAlarmManager;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400322 private ICompanionDeviceManager mCompanionManager;
Julia Reynolds94187562017-10-10 13:58:49 -0400323 private AccessibilityManager mAccessibilityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800324 private IDeviceIdleController mDeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800325
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 final IBinder mForegroundToken = new Binder();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400327 private WorkerHandler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400328 private final HandlerThread mRankingThread = new HandlerThread("ranker",
329 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330
Adam Lesinski182f73f2013-12-05 16:48:06 -0800331 private Light mNotificationLight;
332 Light mAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800333
Daniel Sandleredbb3802012-11-13 20:49:47 -0800334 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400335 private boolean mUseAttentionLight;
Julia Reynolds54369232018-07-03 10:43:35 -0400336 boolean mHasLight = true;
337 boolean mLightEnabled;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800338 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800339
John Spurlockd8afe3c2014-08-01 14:04:07 -0400340 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400341 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500342 private String mSoundNotificationKey;
343 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344
Bryce Lee7219ada2016-04-08 10:54:23 -0700345 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400346 new SparseArray<>();
347 private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400348 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500349 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400350
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500351 // for enabling and disabling notification pulse behavior
Julia Reynolds54369232018-07-03 10:43:35 -0400352 boolean mScreenOn = true;
Beverly5d463b62017-07-26 14:13:40 -0400353 protected boolean mInCall = false;
Julia Reynolds54369232018-07-03 10:43:35 -0400354 boolean mNotificationPulseEnabled;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500355
Beverly5d463b62017-07-26 14:13:40 -0400356 private Uri mInCallNotificationUri;
357 private AudioAttributes mInCallNotificationAudioAttributes;
358 private float mInCallNotificationVolume;
luochaojiang50e5273c2018-04-16 16:55:03 +0800359 private Binder mCallNotificationToken = null;
Marta Białka39c992f2011-03-10 10:27:24 +0100360
Daniel Sandler09a247e2013-02-14 10:24:17 -0500361 // used as a mutex for access to all active notifications & listeners
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500362 final Object mNotificationLock = new Object();
Julia Reynolds0839c022017-06-15 15:24:01 -0400363 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400364 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400365 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400366 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400367 @GuardedBy("mNotificationLock")
Chris Wren6676dab2016-12-21 18:26:27 -0500368 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400369 @GuardedBy("mNotificationLock")
Julia Reynoldseae43fb2016-05-09 12:42:58 -0400370 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400371 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
Christoph Studer265c1052014-07-23 17:14:33 +0200372 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500373 final ArrayMap<Integer, ArrayList<NotifyingApp>> mRecentApps = new ArrayMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374
Chris Wren6054e612014-11-25 17:16:46 -0500375 // The last key in this list owns the hardware.
376 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700377
Adam Lesinski182f73f2013-12-05 16:48:06 -0800378 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700379 private UsageStatsManagerInternal mAppUsageStats;
Jason Parks50322ff2018-03-27 10:23:33 -0500380 private DevicePolicyManagerInternal mDpm;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500381
Griff Hazen9f637d12014-06-10 11:13:51 -0700382 private Archive mArchive;
383
John Spurlock21258a32015-05-27 18:22:55 -0400384 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400385 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400386
Daniel Sandler0da673f2012-04-11 12:33:16 -0400387 private static final int DB_VERSION = 1;
388
John Spurlock21258a32015-05-27 18:22:55 -0400389 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400390 private static final String ATTR_VERSION = "version";
391
Chris Wren54bbef42014-07-09 18:37:56 -0400392 private RankingHelper mRankingHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400393
John Spurlockb408e8e2014-04-23 21:12:45 -0400394 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400395 private NotificationListeners mListeners;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400396 private NotificationAssistants mAssistants;
John Spurlock7340fc82014-04-24 18:50:12 -0400397 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200398 private NotificationUsageStats mUsageStats;
Christoph Studer546bec82014-03-14 12:17:12 +0100399
John Spurlocke6a7d932014-03-13 12:29:00 -0400400 private static final int MY_UID = Process.myUid();
401 private static final int MY_PID = Process.myPid();
Dianne Hackborn98305522017-05-05 17:53:53 -0700402 private static final IBinder WHITELIST_TOKEN = new Binder();
Chris Wren51017d02015-12-15 15:34:46 -0500403 private RankingHandler mRankingHandler;
Chris Wrenc8673a82016-05-17 17:11:29 -0400404 private long mLastOverRateLogTime;
Chris Wren763a9bb2016-05-31 17:14:12 -0400405 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
John Spurlocke6a7d932014-03-13 12:29:00 -0400406
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400407 private SnoozeHelper mSnoozeHelper;
Julia Reynolds8f488d32016-10-14 10:59:01 -0400408 private GroupHelper mGroupHelper;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -0500409 private boolean mIsTelevision;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400410
Kenny Guy23991102018-04-05 21:18:38 +0100411 private MetricsLogger mMetricsLogger;
Kristian Monsen30f59b22018-04-09 10:27:16 +0200412 private Predicate<String> mAllowedManagedServicePackages;
Kenny Guy23991102018-04-05 21:18:38 +0100413
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500414 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700415 final int mBufferSize;
416 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500417
Griff Hazen9f637d12014-06-10 11:13:51 -0700418 public Archive(int size) {
419 mBufferSize = size;
420 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500421 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700422
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400423 public String toString() {
424 final StringBuilder sb = new StringBuilder();
425 final int N = mBuffer.size();
426 sb.append("Archive (");
427 sb.append(N);
428 sb.append(" notification");
429 sb.append((N==1)?")":"s)");
430 return sb.toString();
431 }
432
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500433 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700434 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500435 mBuffer.removeFirst();
436 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400437
438 // We don't want to store the heavy bits of the notification in the archive,
439 // but other clients in the system process might be using the object, so we
440 // store a (lightened) copy.
441 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500442 }
443
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500444 public Iterator<StatusBarNotification> descendingIterator() {
445 return mBuffer.descendingIterator();
446 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500447
448 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700449 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500450 final StatusBarNotification[] a
451 = new StatusBarNotification[Math.min(count, mBuffer.size())];
452 Iterator<StatusBarNotification> iter = descendingIterator();
453 int i=0;
454 while (iter.hasNext() && i < count) {
455 a[i++] = iter.next();
456 }
457 return a;
458 }
459
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500460 }
461
Julia Reynolds88a879f2017-07-26 17:06:46 -0400462 protected void readDefaultApprovedServices(int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400463 String defaultListenerAccess = getContext().getResources().getString(
464 com.android.internal.R.string.config_defaultListenerAccessPackages);
465 if (defaultListenerAccess != null) {
466 for (String whitelisted :
467 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
468 // Gather all notification listener components for candidate pkgs.
469 Set<ComponentName> approvedListeners =
470 mListeners.queryPackageForServices(whitelisted,
471 PackageManager.MATCH_DIRECT_BOOT_AWARE
472 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
473 for (ComponentName cn : approvedListeners) {
474 try {
475 getBinderService().setNotificationListenerAccessGrantedForUser(cn,
476 userId, true);
477 } catch (RemoteException e) {
478 e.printStackTrace();
479 }
480 }
481 }
482 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500483
Julia Reynoldsb852e562017-06-06 16:14:18 -0400484 String defaultDndAccess = getContext().getResources().getString(
485 com.android.internal.R.string.config_defaultDndAccessPackages);
Edward Savage-Jones36a89422018-07-19 12:23:58 +0200486 if (defaultDndAccess != null) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400487 for (String whitelisted :
488 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
489 try {
490 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
491 } catch (RemoteException e) {
492 e.printStackTrace();
493 }
494 }
495 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500496
497 readDefaultAssistant(userId);
498 }
499
500 protected void readDefaultAssistant(int userId) {
501 String defaultAssistantAccess = getContext().getResources().getString(
502 com.android.internal.R.string.config_defaultAssistantAccessPackage);
503 if (defaultAssistantAccess != null) {
504 // Gather all notification assistant components for candidate pkg. There should
505 // only be one
506 Set<ComponentName> approvedAssistants =
507 mAssistants.queryPackageForServices(defaultAssistantAccess,
508 PackageManager.MATCH_DIRECT_BOOT_AWARE
509 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
510 for (ComponentName cn : approvedAssistants) {
511 try {
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400512 getBinderService().setNotificationAssistantAccessGrantedForUser(
513 cn, userId, true);
Julia Reynolds7380d872018-01-12 10:28:26 -0500514 } catch (RemoteException e) {
515 e.printStackTrace();
516 }
517 }
518 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400519 }
520
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400521 void readPolicyXml(InputStream stream, boolean forRestore)
John Spurlock35ef0a62015-05-28 11:24:10 -0400522 throws XmlPullParserException, NumberFormatException, IOException {
523 final XmlPullParser parser = Xml.newPullParser();
524 parser.setInput(stream, StandardCharsets.UTF_8.name());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400525 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
526 boolean migratedManagedServices = false;
527 int outerDepth = parser.getDepth();
528 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
529 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
530 mZenModeHelper.readXml(parser, forRestore);
531 } else if (RankingHelper.TAG_RANKING.equals(parser.getName())){
532 mRankingHelper.readXml(parser, forRestore);
533 }
Kristian Monsen30f59b22018-04-09 10:27:16 +0200534 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
535 mListeners.readXml(parser, mAllowedManagedServicePackages);
536 migratedManagedServices = true;
537 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
538 mAssistants.readXml(parser, mAllowedManagedServicePackages);
539 migratedManagedServices = true;
540 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
541 mConditionProviders.readXml(parser, mAllowedManagedServicePackages);
542 migratedManagedServices = true;
Julia Reynolds68263d12017-06-21 14:21:19 -0400543 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400544 }
545
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400546 if (!migratedManagedServices) {
547 mListeners.migrateToXml();
548 mAssistants.migrateToXml();
549 mConditionProviders.migrateToXml();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400550 savePolicyFile();
John Spurlock35ef0a62015-05-28 11:24:10 -0400551 }
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400552
553 mAssistants.ensureAssistant();
John Spurlock35ef0a62015-05-28 11:24:10 -0400554 }
555
John Spurlock056c5192014-04-20 21:52:01 -0400556 private void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400557 if (DBG) Slog.d(TAG, "loadPolicyFile");
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500558 synchronized (mPolicyFile) {
Daniel Sandler0da673f2012-04-11 12:33:16 -0400559
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400560 InputStream infile = null;
John Spurlock056c5192014-04-20 21:52:01 -0400561 try {
562 infile = mPolicyFile.openRead();
John Spurlock35ef0a62015-05-28 11:24:10 -0400563 readPolicyXml(infile, false /*forRestore*/);
John Spurlock056c5192014-04-20 21:52:01 -0400564 } catch (FileNotFoundException e) {
565 // No data yet
Julia Reynoldsb852e562017-06-06 16:14:18 -0400566 // Load default managed services approvals
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400567 readDefaultApprovedServices(USER_SYSTEM);
John Spurlock056c5192014-04-20 21:52:01 -0400568 } catch (IOException e) {
569 Log.wtf(TAG, "Unable to read notification policy", e);
570 } catch (NumberFormatException e) {
571 Log.wtf(TAG, "Unable to parse notification policy", e);
572 } catch (XmlPullParserException e) {
573 Log.wtf(TAG, "Unable to parse notification policy", e);
574 } finally {
575 IoUtils.closeQuietly(infile);
576 }
577 }
578 }
579
580 public void savePolicyFile() {
581 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
582 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
583 }
584
585 private void handleSavePolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400586 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400587 synchronized (mPolicyFile) {
588 final FileOutputStream stream;
589 try {
590 stream = mPolicyFile.startWrite();
591 } catch (IOException e) {
592 Slog.w(TAG, "Failed to save policy file", e);
593 return;
594 }
595
596 try {
John Spurlock35ef0a62015-05-28 11:24:10 -0400597 writePolicyXml(stream, false /*forBackup*/);
John Spurlock056c5192014-04-20 21:52:01 -0400598 mPolicyFile.finishWrite(stream);
599 } catch (IOException e) {
600 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
601 mPolicyFile.failWrite(stream);
Daniel Sandler0da673f2012-04-11 12:33:16 -0400602 }
603 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400604 BackupManager.dataChanged(getContext().getPackageName());
605 }
606
607 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
608 final XmlSerializer out = new FastXmlSerializer();
609 out.setOutput(stream, StandardCharsets.UTF_8.name());
610 out.startDocument(null, true);
611 out.startTag(null, TAG_NOTIFICATION_POLICY);
612 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
Beverly4e2f76c2018-03-16 15:43:49 -0400613 mZenModeHelper.writeXml(out, forBackup, null);
John Spurlock35ef0a62015-05-28 11:24:10 -0400614 mRankingHelper.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400615 mListeners.writeXml(out, forBackup);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400616 mAssistants.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400617 mConditionProviders.writeXml(out, forBackup);
John Spurlock35ef0a62015-05-28 11:24:10 -0400618 out.endTag(null, TAG_NOTIFICATION_POLICY);
619 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400620 }
621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 private static final class ToastRecord
623 {
624 final int pid;
625 final String pkg;
Beverly Tai98efc792018-06-11 14:50:36 +0000626 final ITransientNotification callback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 int duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700628 Binder token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700630 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
631 Binder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 this.pid = pid;
633 this.pkg = pkg;
634 this.callback = callback;
635 this.duration = duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700636 this.token = token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 }
638
639 void update(int duration) {
640 this.duration = duration;
641 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800642
John Spurlock25e2d242014-06-27 13:58:23 -0400643 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
644 if (filter != null && !filter.matches(pkg)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 pw.println(prefix + this);
646 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 @Override
649 public final String toString()
650 {
651 return "ToastRecord{"
652 + Integer.toHexString(System.identityHashCode(this))
653 + " pkg=" + pkg
654 + " callback=" + callback
655 + " duration=" + duration;
656 }
657 }
658
Beverly40239d92017-07-07 10:20:41 -0400659 @VisibleForTesting
660 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661
Adam Lesinski182f73f2013-12-05 16:48:06 -0800662 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 public void onSetDisabled(int status) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500664 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400665 mDisableNotificationEffects =
666 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
John Spurlock32fe4c62014-10-02 12:16:02 -0400667 if (disableNotificationEffects(null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 // cancel whatever's going on
669 long identity = Binder.clearCallingIdentity();
670 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800671 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700672 if (player != null) {
673 player.stopAsync();
674 }
675 } catch (RemoteException e) {
676 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 Binder.restoreCallingIdentity(identity);
678 }
679
680 identity = Binder.clearCallingIdentity();
681 try {
682 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700683 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 Binder.restoreCallingIdentity(identity);
685 }
686 }
687 }
688 }
689
Adam Lesinski182f73f2013-12-05 16:48:06 -0800690 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400691 public void onClearAll(int callingUid, int callingPid, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500692 synchronized (mNotificationLock) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400693 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
Kenny Guya263e4e2014-03-03 18:24:03 +0000694 /*includeCurrentProfiles*/ true);
Adam Lesinskie8240262014-03-26 16:01:00 -0700695 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 }
697
Adam Lesinski182f73f2013-12-05 16:48:06 -0800698 @Override
Dieter Hsud39f0d52018-04-14 02:08:30 +0800699 public void onNotificationClick(int callingUid, int callingPid, String key, NotificationVisibility nv) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800700 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500701 synchronized (mNotificationLock) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200702 NotificationRecord r = mNotificationsByKey.get(key);
703 if (r == null) {
704 Log.w(TAG, "No notification with key: " + key);
705 return;
706 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400707 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500708 MetricsLogger.action(r.getLogMaker(now)
709 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
Dieter Hsud39f0d52018-04-14 02:08:30 +0800710 .setType(MetricsEvent.TYPE_ACTION)
711 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
712 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400713 EventLogTags.writeNotificationClicked(key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800714 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
715 nv.rank, nv.count);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400716
Christoph Studer03b87a22014-04-30 17:33:27 +0200717 StatusBarNotification sbn = r.sbn;
718 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
719 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400720 FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
Dieter Hsud39f0d52018-04-14 02:08:30 +0800721 REASON_CLICK, nv.rank, nv.count, null);
722 nv.recycle();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800723 reportUserInteraction(r);
Christoph Studer03b87a22014-04-30 17:33:27 +0200724 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 }
726
Adam Lesinski182f73f2013-12-05 16:48:06 -0800727 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200728 public void onNotificationActionClick(int callingUid, int callingPid, String key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800729 int actionIndex, NotificationVisibility nv) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800730 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500731 synchronized (mNotificationLock) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200732 NotificationRecord r = mNotificationsByKey.get(key);
733 if (r == null) {
734 Log.w(TAG, "No notification with key: " + key);
735 return;
736 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400737 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500738 MetricsLogger.action(r.getLogMaker(now)
739 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
740 .setType(MetricsEvent.TYPE_ACTION)
Dieter Hsud39f0d52018-04-14 02:08:30 +0800741 .setSubtype(actionIndex)
742 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
743 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400744 EventLogTags.writeNotificationActionClicked(key, actionIndex,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800745 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
746 nv.rank, nv.count);
747 nv.recycle();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800748 reportUserInteraction(r);
Christoph Studer4da84cd2014-10-21 17:24:20 +0200749 }
750 }
751
752 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400753 public void onNotificationClear(int callingUid, int callingPid,
Julia Reynolds503ed942017-10-04 16:04:56 -0400754 String pkg, String tag, int id, int userId, String key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800755 @NotificationStats.DismissalSurface int dismissalSurface,
756 NotificationVisibility nv) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400757 synchronized (mNotificationLock) {
758 NotificationRecord r = mNotificationsByKey.get(key);
759 if (r != null) {
760 r.recordDismissalSurface(dismissalSurface);
761 }
762 }
John Spurlocke6a7d932014-03-13 12:29:00 -0400763 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400764 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800765 true, userId, REASON_CANCEL, nv.rank, nv.count,null);
766 nv.recycle();
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400767 }
768
Adam Lesinski182f73f2013-12-05 16:48:06 -0800769 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400770 public void onPanelRevealed(boolean clearEffects, int items) {
Chris Wren9eb5e102017-01-26 13:15:06 -0500771 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Chris Wren621933f2017-06-14 15:59:03 -0400772 MetricsLogger.histogram(getContext(), "note_load", items);
Chris Wrenb659c4f2015-06-25 17:12:27 -0400773 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100774 if (clearEffects) {
775 clearEffects();
776 }
777 }
778
779 @Override
780 public void onPanelHidden() {
Chris Wren9eb5e102017-01-26 13:15:06 -0500781 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Christoph Studer1f32c652014-11-26 15:32:20 +0100782 EventLogTags.writeNotificationPanelHidden();
783 }
784
785 @Override
786 public void clearEffects() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500787 synchronized (mNotificationLock) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100788 if (DBG) Slog.d(TAG, "clearEffects");
Chris Wren93bb8b82016-03-29 14:35:05 -0400789 clearSoundLocked();
790 clearVibrateLocked();
791 clearLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 }
793 }
Joe Onorato005847b2010-06-04 16:08:02 -0400794
Adam Lesinski182f73f2013-12-05 16:48:06 -0800795 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400796 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000797 int uid, int initialPid, String message, int userId) {
John Spurlocke6a7d932014-03-13 12:29:00 -0400798 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400799 REASON_ERROR, null);
Joe Onorato005847b2010-06-04 16:08:02 -0400800 }
John Spurlocke677d712014-02-13 12:52:19 -0500801
802 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400803 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
804 NotificationVisibility[] noLongerVisibleKeys) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500805 synchronized (mNotificationLock) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400806 for (NotificationVisibility nv : newlyVisibleKeys) {
807 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200808 if (r == null) continue;
Amith Yamasani803eab692017-11-09 17:47:04 -0800809 if (!r.isSeen()) {
810 // Report to usage stats that notification was made visible
811 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
812 reportSeen(r);
Kenny Guy23991102018-04-05 21:18:38 +0100813
814 // If the newly visible notification has smart replies
815 // then log that the user has seen them.
816 if (r.getNumSmartRepliesAdded() > 0
817 && !r.hasSeenSmartReplies()) {
818 r.setSeenSmartReplies(true);
819 LogMaker logMaker = r.getLogMaker()
820 .setCategory(MetricsEvent.SMART_REPLY_VISIBLE)
821 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT,
822 r.getNumSmartRepliesAdded());
823 mMetricsLogger.write(logMaker);
824 }
Amith Yamasani803eab692017-11-09 17:47:04 -0800825 }
Dieter Hsud39f0d52018-04-14 02:08:30 +0800826 r.setVisibility(true, nv.rank, nv.count);
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400827 maybeRecordInterruptionLocked(r);
Chris Wrend1dbc922015-06-19 17:51:16 -0400828 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200829 }
830 // Note that we might receive this event after notifications
831 // have already left the system, e.g. after dismissing from the
832 // shade. Hence not finding notifications in
833 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400834 for (NotificationVisibility nv : noLongerVisibleKeys) {
835 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200836 if (r == null) continue;
Dieter Hsud39f0d52018-04-14 02:08:30 +0800837 r.setVisibility(false, nv.rank, nv.count);
Chris Wrend1dbc922015-06-19 17:51:16 -0400838 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200839 }
840 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200841 }
Chris Wren78403d72014-07-28 10:23:24 +0100842
843 @Override
844 public void onNotificationExpansionChanged(String key,
845 boolean userAction, boolean expanded) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500846 synchronized (mNotificationLock) {
Chris Wren78403d72014-07-28 10:23:24 +0100847 NotificationRecord r = mNotificationsByKey.get(key);
848 if (r != null) {
849 r.stats.onExpansionChanged(userAction, expanded);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400850 final long now = System.currentTimeMillis();
Chris Wrenf7342712017-09-14 10:55:55 -0400851 if (userAction) {
Chris Wren377ac6d2017-09-12 14:15:23 -0400852 MetricsLogger.action(r.getLogMaker(now)
853 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
Chris Wrenf7342712017-09-14 10:55:55 -0400854 .setType(expanded ? MetricsEvent.TYPE_DETAIL
855 : MetricsEvent.TYPE_COLLAPSE));
Chris Wren377ac6d2017-09-12 14:15:23 -0400856 }
Julia Reynolds84dc96b2017-11-14 09:51:01 -0500857 if (expanded && userAction) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400858 r.recordExpanded();
859 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400860 EventLogTags.writeNotificationExpansion(key,
861 userAction ? 1 : 0, expanded ? 1 : 0,
862 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Chris Wren78403d72014-07-28 10:23:24 +0100863 }
864 }
865 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400866
867 @Override
868 public void onNotificationDirectReplied(String key) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800869 exitIdle();
Julia Reynolds503ed942017-10-04 16:04:56 -0400870 synchronized (mNotificationLock) {
871 NotificationRecord r = mNotificationsByKey.get(key);
872 if (r != null) {
873 r.recordDirectReplied();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800874 reportUserInteraction(r);
Julia Reynolds503ed942017-10-04 16:04:56 -0400875 }
876 }
877 }
878
879 @Override
Kenny Guy23991102018-04-05 21:18:38 +0100880 public void onNotificationSmartRepliesAdded(String key, int replyCount) {
881 synchronized (mNotificationLock) {
882 NotificationRecord r = mNotificationsByKey.get(key);
883 if (r != null) {
884 r.setNumSmartRepliesAdded(replyCount);
885 }
886 }
887 }
888
889 @Override
890 public void onNotificationSmartReplySent(String key, int replyIndex) {
891 synchronized (mNotificationLock) {
892 NotificationRecord r = mNotificationsByKey.get(key);
893 if (r != null) {
894 LogMaker logMaker = r.getLogMaker()
895 .setCategory(MetricsEvent.SMART_REPLY_ACTION)
896 .setSubtype(replyIndex);
897 mMetricsLogger.write(logMaker);
898 // Treat clicking on a smart reply as a user interaction.
899 reportUserInteraction(r);
900 }
901 }
902 }
903
904 @Override
Julia Reynolds503ed942017-10-04 16:04:56 -0400905 public void onNotificationSettingsViewed(String key) {
906 synchronized (mNotificationLock) {
907 NotificationRecord r = mNotificationsByKey.get(key);
908 if (r != null) {
909 r.recordViewedSettings();
910 }
911 }
912 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 };
914
Julia Reynolds88860ce2017-06-01 16:55:49 -0400915 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400916 private void clearSoundLocked() {
917 mSoundNotificationKey = null;
918 long identity = Binder.clearCallingIdentity();
919 try {
920 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
921 if (player != null) {
922 player.stopAsync();
923 }
924 } catch (RemoteException e) {
925 } finally {
926 Binder.restoreCallingIdentity(identity);
927 }
928 }
929
Julia Reynolds88860ce2017-06-01 16:55:49 -0400930 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400931 private void clearVibrateLocked() {
932 mVibrateNotificationKey = null;
933 long identity = Binder.clearCallingIdentity();
934 try {
935 mVibrator.cancel();
936 } finally {
937 Binder.restoreCallingIdentity(identity);
938 }
939 }
940
Julia Reynolds88860ce2017-06-01 16:55:49 -0400941 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400942 private void clearLightsLocked() {
943 // light
944 mLights.clear();
945 updateLightsLocked();
946 }
947
Beverlyd4f96492017-08-02 13:36:11 -0400948 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
949 @Override
950 public void onReceive(Context context, Intent intent) {
951 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
Beverly70dcd002018-03-29 17:09:16 -0400952 // update system notification channels
953 SystemNotificationChannels.createAll(context);
Beverlyd4f96492017-08-02 13:36:11 -0400954 mZenModeHelper.updateDefaultZenRules();
Julia Reynolds816797a2017-08-11 15:47:09 -0400955 mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
Beverlyd4f96492017-08-02 13:36:11 -0400956 }
957 }
958 };
959
Julia Reynoldsb852e562017-06-06 16:14:18 -0400960 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
961 @Override
962 public void onReceive(Context context, Intent intent) {
963 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
964 try {
965 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
966 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
Michal Karpinski6135a262017-08-11 10:45:58 +0100967 int restoredFromSdkInt = intent.getIntExtra(
968 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400969 mListeners.onSettingRestored(
970 element, newValue, restoredFromSdkInt, getSendingUserId());
971 mConditionProviders.onSettingRestored(
972 element, newValue, restoredFromSdkInt, getSendingUserId());
Julia Reynoldsb852e562017-06-06 16:14:18 -0400973 } catch (Exception e) {
974 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
975 }
976 }
977 }
978 };
979
Julia Reynolds2a128742016-11-28 14:29:25 -0500980 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
981 @Override
982 public void onReceive(Context context, Intent intent) {
983 String action = intent.getAction();
984 if (action == null) {
985 return;
986 }
987 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
988 final NotificationRecord record;
989 synchronized (mNotificationLock) {
990 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
991 }
992 if (record != null) {
993 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
994 record.sbn.getPackageName(), record.sbn.getTag(),
995 record.sbn.getId(), 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400996 FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
Julia Reynolds2a128742016-11-28 14:29:25 -0500997 REASON_TIMEOUT, null);
998 }
999 }
1000 }
1001 };
1002
Kenny Guy70058402014-10-28 20:45:06 +00001003 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 @Override
1005 public void onReceive(Context context, Intent intent) {
1006 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -08001007 if (action == null) {
1008 return;
1009 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001011 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -04001012 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -04001013 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -04001014 boolean cancelNotifications = true;
Beverly5a20a5e2018-03-06 15:02:44 -05001015 boolean hideNotifications = false;
1016 boolean unhideNotifications = false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001017 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -04001018
Chris Wren3da73022013-05-10 14:41:21 -04001019 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -04001020 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001021 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -04001022 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001023 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001024 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
Beverly5a20a5e2018-03-06 15:02:44 -05001025 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
1026 || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
Kenny Guy70058402014-10-28 20:45:06 +00001027 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1028 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001029 String pkgList[] = null;
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001030 int uidList[] = null;
Julia Reynolds6434eb22016-08-08 17:19:26 -04001031 boolean removingPackage = queryRemove &&
1032 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
1033 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001034 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001035 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001036 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001037 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
1038 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Beverly5a20a5e2018-03-06 15:02:44 -05001039 cancelNotifications = false;
1040 hideNotifications = true;
1041 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
1042 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1043 cancelNotifications = false;
1044 unhideNotifications = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001045 } else if (queryRestart) {
1046 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001047 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001048 } else {
1049 Uri uri = intent.getData();
1050 if (uri == null) {
1051 return;
1052 }
1053 String pkgName = uri.getSchemeSpecificPart();
1054 if (pkgName == null) {
1055 return;
1056 }
Daniel Sandler26ece572012-06-01 15:38:46 -04001057 if (packageChanged) {
1058 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -07001059 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001060 final int enabled = mPackageManager.getApplicationEnabledSetting(
1061 pkgName,
Kenny Guy70058402014-10-28 20:45:06 +00001062 changeUserId != UserHandle.USER_ALL ? changeUserId :
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001063 USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -07001064 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1065 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
1066 cancelNotifications = false;
1067 }
1068 } catch (IllegalArgumentException e) {
1069 // Package doesn't exist; probably racing with uninstall.
1070 // cancelNotifications is already true, so nothing to do here.
1071 if (DBG) {
1072 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
1073 }
Kenny Guy70058402014-10-28 20:45:06 +00001074 } catch (RemoteException e) {
1075 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -04001076 }
1077 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001078 pkgList = new String[]{pkgName};
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001079 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001081 if (pkgList != null && (pkgList.length > 0)) {
1082 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -04001083 if (cancelNotifications) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001084 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
1085 !queryRestart, changeUserId, reason, null);
Beverly5a20a5e2018-03-06 15:02:44 -05001086 } else if (hideNotifications) {
1087 hideNotificationsForPackages(pkgList);
1088 } else if (unhideNotifications) {
1089 unhideNotificationsForPackages(pkgList);
John Spurlock79f78922013-05-16 09:10:05 -04001090 }
Beverly5a20a5e2018-03-06 15:02:44 -05001091
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001092 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093 }
Beverly5a20a5e2018-03-06 15:02:44 -05001094
Julia Reynoldsb852e562017-06-06 16:14:18 -04001095 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001096 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsb852e562017-06-06 16:14:18 -04001097 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001098 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
1099 savePolicyFile();
Kenny Guy70058402014-10-28 20:45:06 +00001100 }
1101 }
1102 };
1103
1104 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1105 @Override
1106 public void onReceive(Context context, Intent intent) {
1107 String action = intent.getAction();
1108
1109 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001110 // Keep track of screen on/off state, but do not turn off the notification light
1111 // until user passes through the lock screen or views the notification.
1112 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +01001113 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001114 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1115 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +01001116 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001117 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -05001118 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
1119 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001120 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001121 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
1122 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1123 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001124 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001125 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001126 }
Rubin Xue95057a2016-04-01 16:49:25 +01001127 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001128 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +01001129 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001130 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001131 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001132 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001133 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1134 // turn off LED when user passes through lock screen
1135 mNotificationLight.turnOff();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001136 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001137 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001138 // reload per-user settings
1139 mSettingsObserver.update(null);
John Spurlockb408e8e2014-04-23 21:12:45 -04001140 mUserProfiles.updateCache(context);
Christoph Studerb53dfd42014-09-12 14:45:59 +02001141 // Refresh managed services
John Spurlock1b8b22b2015-05-20 09:47:13 -04001142 mConditionProviders.onUserSwitched(user);
1143 mListeners.onUserSwitched(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001144 mAssistants.onUserSwitched(user);
John Spurlock21258a32015-05-27 18:22:55 -04001145 mZenModeHelper.onUserSwitched(user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001146 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001147 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1148 if (userId != USER_NULL) {
1149 mUserProfiles.updateCache(context);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001150 if (!mUserProfiles.isManagedProfile(userId)) {
1151 readDefaultApprovedServices(userId);
1152 }
Julia Reynolds88a879f2017-07-26 17:06:46 -04001153 }
John Spurlock21258a32015-05-27 18:22:55 -04001154 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001155 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001156 mUserProfiles.updateCache(context);
John Spurlock21258a32015-05-27 18:22:55 -04001157 mZenModeHelper.onUserRemoved(user);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -04001158 mRankingHelper.onUserRemoved(user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001159 mListeners.onUserRemoved(user);
1160 mConditionProviders.onUserRemoved(user);
1161 mAssistants.onUserRemoved(user);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -04001162 savePolicyFile();
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001163 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001164 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001165 mConditionProviders.onUserUnlocked(user);
1166 mListeners.onUserUnlocked(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001167 mAssistants.onUserUnlocked(user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001168 mZenModeHelper.onUserUnlocked(user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 }
1170 }
1171 };
1172
John Spurlock7c74f782015-06-04 13:01:42 -04001173 private final class SettingsObserver extends ContentObserver {
Chris Wren89aa2262017-05-05 18:05:56 -04001174 private final Uri NOTIFICATION_BADGING_URI
1175 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001176 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1177 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wren763a9bb2016-05-31 17:14:12 -04001178 private final Uri NOTIFICATION_RATE_LIMIT_URI
1179 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001180
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001181 SettingsObserver(Handler handler) {
1182 super(handler);
1183 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001184
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001185 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001186 ContentResolver resolver = getContext().getContentResolver();
Chris Wren89aa2262017-05-05 18:05:56 -04001187 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1188 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001189 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -07001190 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -04001191 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1192 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001193 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001194 }
1195
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001196 @Override public void onChange(boolean selfChange, Uri uri) {
1197 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001198 }
1199
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001200 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001201 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001202 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
zhoulei7e376972017-05-17 18:41:25 +08001203 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
Julia Reynolds54369232018-07-03 10:43:35 -04001204 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT)
1205 != 0;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001206 if (mNotificationPulseEnabled != pulseEnabled) {
1207 mNotificationPulseEnabled = pulseEnabled;
1208 updateNotificationPulse();
1209 }
1210 }
Chris Wren763a9bb2016-05-31 17:14:12 -04001211 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1212 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1213 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1214 }
Chris Wren89aa2262017-05-05 18:05:56 -04001215 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
1216 mRankingHelper.updateBadgingEnabled();
1217 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001218 }
1219 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001220
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001221 private SettingsObserver mSettingsObserver;
Beverlyd4f96492017-08-02 13:36:11 -04001222 protected ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001223
Daniel Sandleredbb3802012-11-13 20:49:47 -08001224 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1225 int[] ar = r.getIntArray(resid);
1226 if (ar == null) {
1227 return def;
1228 }
1229 final int len = ar.length > maxlen ? maxlen : ar.length;
1230 long[] out = new long[len];
1231 for (int i=0; i<len; i++) {
1232 out[i] = ar[i];
1233 }
1234 return out;
1235 }
1236
Jeff Brownb880d882014-02-10 19:47:07 -08001237 public NotificationManagerService(Context context) {
1238 super(context);
Dianne Hackborn98305522017-05-05 17:53:53 -07001239 Notification.processWhitelistToken = WHITELIST_TOKEN;
Jeff Brownb880d882014-02-10 19:47:07 -08001240 }
1241
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001242 // TODO - replace these methods with a single VisibleForTesting constructor
Chris Wren93bb8b82016-03-29 14:35:05 -04001243 @VisibleForTesting
1244 void setAudioManager(AudioManager audioMananger) {
1245 mAudioManager = audioMananger;
1246 }
1247
1248 @VisibleForTesting
Julia Reynolds9aee2842019-01-03 14:35:38 -05001249 void setHints(int hints) {
1250 mListenerHints = hints;
1251 }
1252
1253 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001254 void setVibrator(Vibrator vibrator) {
1255 mVibrator = vibrator;
1256 }
1257
1258 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001259 void setLights(Light light) {
1260 mNotificationLight = light;
1261 mAttentionLight = light;
Julia Reynolds033a4122017-01-31 16:50:38 -05001262 mNotificationPulseEnabled = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001263 }
1264
1265 @VisibleForTesting
1266 void setScreenOn(boolean on) {
1267 mScreenOn = on;
1268 }
1269
1270 @VisibleForTesting
Julia Reynolds080361e2017-07-13 11:23:12 -04001271 int getNotificationRecordCount() {
1272 synchronized (mNotificationLock) {
1273 int count = mNotificationList.size() + mNotificationsByKey.size()
1274 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1275 // subtract duplicates
1276 for (NotificationRecord posted : mNotificationList) {
1277 if (mNotificationsByKey.containsKey(posted.getKey())) {
1278 count--;
1279 }
1280 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001281 count--;
Julia Reynolds080361e2017-07-13 11:23:12 -04001282 }
1283 }
1284
1285 return count;
1286 }
1287 }
1288
Julia Reynolds7380d872018-01-12 10:28:26 -05001289 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001290 void clearNotifications() {
1291 mEnqueuedNotifications.clear();
1292 mNotificationList.clear();
1293 mNotificationsByKey.clear();
1294 mSummaryByGroupKey.clear();
1295 }
1296
Julia Reynolds080361e2017-07-13 11:23:12 -04001297 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001298 void addNotification(NotificationRecord r) {
1299 mNotificationList.add(r);
1300 mNotificationsByKey.put(r.sbn.getKey(), r);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001301 if (r.sbn.isGroup()) {
1302 mSummaryByGroupKey.put(r.getGroupKey(), r);
1303 }
1304 }
1305
1306 @VisibleForTesting
1307 void addEnqueuedNotification(NotificationRecord r) {
1308 mEnqueuedNotifications.add(r);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001309 }
1310
1311 @VisibleForTesting
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001312 NotificationRecord getNotificationRecord(String key) {
1313 return mNotificationsByKey.get(key);
1314 }
1315
1316
1317 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001318 void setSystemReady(boolean systemReady) {
1319 mSystemReady = systemReady;
1320 }
1321
1322 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001323 void setHandler(WorkerHandler handler) {
Chris Wren93bb8b82016-03-29 14:35:05 -04001324 mHandler = handler;
1325 }
1326
Chris Wrend4054312016-06-24 17:07:40 -04001327 @VisibleForTesting
Julia Reynolds0c299d42016-11-15 14:37:04 -05001328 void setFallbackVibrationPattern(long[] vibrationPattern) {
1329 mFallbackVibrationPattern = vibrationPattern;
Chris Wrend4054312016-06-24 17:07:40 -04001330 }
1331
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001332 @VisibleForTesting
1333 void setPackageManager(IPackageManager packageManager) {
1334 mPackageManager = packageManager;
1335 }
1336
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001337 @VisibleForTesting
1338 void setRankingHelper(RankingHelper rankingHelper) {
1339 mRankingHelper = rankingHelper;
1340 }
1341
1342 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001343 void setRankingHandler(RankingHandler rankingHandler) {
1344 mRankingHandler = rankingHandler;
1345 }
1346
1347 @VisibleForTesting
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001348 void setIsTelevision(boolean isTelevision) {
1349 mIsTelevision = isTelevision;
1350 }
1351
Julia Reynolds76c096d2017-06-19 08:16:04 -04001352 @VisibleForTesting
1353 void setUsageStats(NotificationUsageStats us) {
1354 mUsageStats = us;
1355 }
1356
Julia Reynolds94187562017-10-10 13:58:49 -04001357 @VisibleForTesting
1358 void setAccessibilityManager(AccessibilityManager am) {
1359 mAccessibilityManager = am;
1360 }
1361
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001362 // TODO: All tests should use this init instead of the one-off setters above.
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001363 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001364 void init(Looper looper, IPackageManager packageManager,
1365 PackageManager packageManagerClient,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001366 LightsManager lightsManager, NotificationListeners notificationListeners,
Julia Reynoldsb852e562017-06-06 16:14:18 -04001367 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001368 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
Julia Reynolds68263d12017-06-21 14:21:19 -04001369 NotificationUsageStats usageStats, AtomicFile policyFile,
Julia Reynolds7217dc92018-03-07 12:12:09 -05001370 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
Jason Parks50322ff2018-03-27 10:23:33 -05001371 UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm) {
Chris Wren54bbef42014-07-09 18:37:56 -04001372 Resources resources = getContext().getResources();
Chris Wren763a9bb2016-05-31 17:14:12 -04001373 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1374 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1375 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1376
Julia Reynolds94187562017-10-10 13:58:49 -04001377 mAccessibilityManager =
1378 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001379 mAm = am;
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001380 mPackageManager = packageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001381 mPackageManagerClient = packageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001382 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1383 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Julia Reynolds7217dc92018-03-07 12:12:09 -05001384 mAppUsageStats = appUsageStats;
Julia Reynolds2a128742016-11-28 14:29:25 -05001385 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001386 mCompanionManager = companionManager;
Julia Reynolds68263d12017-06-21 14:21:19 -04001387 mActivityManager = activityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -08001388 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1389 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
Jason Parks50322ff2018-03-27 10:23:33 -05001390 mDpm = dpm;
1391
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001392 mHandler = new WorkerHandler(looper);
Chris Wrenf9536642014-04-17 10:01:54 -04001393 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -04001394 String[] extractorNames;
1395 try {
1396 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1397 } catch (Resources.NotFoundException e) {
1398 extractorNames = new String[0];
1399 }
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001400 mUsageStats = usageStats;
Kenny Guy23991102018-04-05 21:18:38 +01001401 mMetricsLogger = new MetricsLogger();
Chris Wren51017d02015-12-15 15:34:46 -05001402 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Julia Reynoldsb852e562017-06-06 16:14:18 -04001403 mConditionProviders = conditionProviders;
John Spurlockb2278d62015-04-07 12:47:12 -04001404 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -04001405 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -04001406 @Override
1407 public void onConfigChanged() {
1408 savePolicyFile();
1409 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001410
1411 @Override
1412 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001413 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -05001414 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -05001415 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1416 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -05001417 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001418 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02001419 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001420 }
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001421 mRankingHandler.requestSort();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001422 }
John Spurlock1fc476d2015-04-14 16:05:20 -04001423
1424 @Override
1425 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001426 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001427 mRankingHandler.requestSort();
John Spurlock80774932015-05-07 17:38:50 -04001428 }
John Spurlock056c5192014-04-20 21:52:01 -04001429 });
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001430 mRankingHelper = new RankingHelper(getContext(),
1431 mPackageManagerClient,
1432 mRankingHandler,
1433 mZenModeHelper,
1434 mUsageStats,
1435 extractorNames);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001436 mSnoozeHelper = snoozeHelper;
Julia Reynolds8aebf352017-06-26 11:35:33 -04001437 mGroupHelper = groupHelper;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04001438
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001439 // This is a ManagedServices object that keeps track of the listeners.
1440 mListeners = notificationListeners;
Chris Wren0efdb882016-03-01 17:17:47 -05001441
Julia Reynolds77b2cc92016-11-08 14:41:09 -05001442 // This is a MangedServices object that keeps track of the assistant.
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001443 mAssistants = notificationAssistants;
Julia Reynoldsb852e562017-06-06 16:14:18 -04001444
Kristian Monsen30f59b22018-04-09 10:27:16 +02001445 // Needs to be set before loadPolicyFile
1446 mAllowedManagedServicePackages = this::canUseManagedServices;
1447
Julia Reynoldsb852e562017-06-06 16:14:18 -04001448 mPolicyFile = policyFile;
1449 loadPolicyFile();
Chris Wren0efdb882016-03-01 17:17:47 -05001450
Adam Lesinski182f73f2013-12-05 16:48:06 -08001451 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -08001452 if (mStatusBar != null) {
1453 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1454 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001456 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1457 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001458
Daniel Sandleredbb3802012-11-13 20:49:47 -08001459 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001460 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001461 VIBRATE_PATTERN_MAXLEN,
1462 DEFAULT_VIBRATE_PATTERN);
Beverly5d463b62017-07-26 14:13:40 -04001463 mInCallNotificationUri = Uri.parse("file://" +
1464 resources.getString(R.string.config_inCallNotificationSound));
1465 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1466 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1467 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
Beverly5d463b62017-07-26 14:13:40 -04001468 .build();
1469 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1470
Chris Wren5116a822014-06-04 15:59:50 -04001471 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
Julia Reynolds54369232018-07-03 10:43:35 -04001472 mHasLight =
1473 resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
Chris Wren5116a822014-06-04 15:59:50 -04001474
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001475 // Don't start allowing notifications until the setup wizard has run once.
1476 // After that, including subsequent boots, init with notifications turned on.
1477 // This works on the first boot because the setup wizard will toggle this
1478 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001479 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001480 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001481 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001482 }
John Spurlockb2278d62015-04-07 12:47:12 -04001483 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001484 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001485
John Spurlockb408e8e2014-04-23 21:12:45 -04001486 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001487 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001488
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001489 mSettingsObserver = new SettingsObserver(mHandler);
1490
1491 mArchive = new Archive(resources.getInteger(
1492 R.integer.config_notificationServiceArchiveSize));
1493
1494 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1495 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1496 }
1497
1498 @Override
1499 public void onStart() {
1500 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1501 @Override
1502 public void repost(int userId, NotificationRecord r) {
1503 try {
1504 if (DBG) {
1505 Slog.d(TAG, "Reposting " + r.getKey());
1506 }
1507 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1508 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1509 r.sbn.getNotification(), userId);
1510 } catch (Exception e) {
1511 Slog.e(TAG, "Cannot un-snooze notification", e);
1512 }
1513 }
1514 }, mUserProfiles);
1515
1516 final File systemDir = new File(Environment.getDataDirectory(), "system");
1517
1518 init(Looper.myLooper(),
1519 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1520 getLocalService(LightsManager.class),
1521 new NotificationListeners(AppGlobals.getPackageManager()),
Julia Reynolds7380d872018-01-12 10:28:26 -05001522 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
1523 AppGlobals.getPackageManager()),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001524 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1525 null, snoozeHelper, new NotificationUsageStats(getContext()),
Dianne Hackborne17b4452018-01-10 13:15:40 -08001526 new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001527 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
Julia Reynolds7217dc92018-03-07 12:12:09 -05001528 getGroupHelper(), ActivityManager.getService(),
Jason Parks50322ff2018-03-27 10:23:33 -05001529 LocalServices.getService(UsageStatsManagerInternal.class),
1530 LocalServices.getService(DevicePolicyManagerInternal.class));
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001531
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001532 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001534 filter.addAction(Intent.ACTION_SCREEN_ON);
1535 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001536 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001537 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001538 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001539 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001540 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001541 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001542 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001543 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001544 getContext().registerReceiver(mIntentReceiver, filter);
Kenny Guy70058402014-10-28 20:45:06 +00001545
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001546 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001547 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001548 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001549 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001550 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1551 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1552 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001553 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1554 null);
1555
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001556 IntentFilter suspendedPkgFilter = new IntentFilter();
1557 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
Beverly5a20a5e2018-03-06 15:02:44 -05001558 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001559 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1560 suspendedPkgFilter, null, null);
1561
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001562 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001563 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1564 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001565
Julia Reynolds2a128742016-11-28 14:29:25 -05001566 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1567 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1568 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1569
Julia Reynoldsb852e562017-06-06 16:14:18 -04001570 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1571 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1572
Beverlyd4f96492017-08-02 13:36:11 -04001573 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1574 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1575
Vishnu Naire3e4d252018-03-01 11:26:57 -08001576 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
1577 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001578 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 }
1580
Julia Reynolds8aebf352017-06-26 11:35:33 -04001581 private GroupHelper getGroupHelper() {
1582 return new GroupHelper(new GroupHelper.Callback() {
1583 @Override
1584 public void addAutoGroup(String key) {
1585 synchronized (mNotificationLock) {
1586 addAutogroupKeyLocked(key);
1587 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001588 }
1589
1590 @Override
1591 public void removeAutoGroup(String key) {
1592 synchronized (mNotificationLock) {
1593 removeAutogroupKeyLocked(key);
1594 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001595 }
1596
1597 @Override
1598 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1599 createAutoGroupSummary(userId, pkg, triggeringKey);
1600 }
1601
1602 @Override
1603 public void removeAutoGroupSummary(int userId, String pkg) {
1604 synchronized (mNotificationLock) {
1605 clearAutogroupSummaryLocked(userId, pkg);
1606 }
1607 }
1608 });
1609 }
1610
John Spurlocke7a835b2015-05-13 10:47:05 -04001611 private void sendRegisteredOnlyBroadcast(String action) {
1612 getContext().sendBroadcastAsUser(new Intent(action)
1613 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1614 }
1615
Adam Lesinski182f73f2013-12-05 16:48:06 -08001616 @Override
1617 public void onBootPhase(int phase) {
1618 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1619 // no beeping until we're basically done booting
1620 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001621
Adam Lesinski182f73f2013-12-05 16:48:06 -08001622 // Grab our optional AudioService
1623 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001624 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001625 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001626 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001627 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1628 // This observer will force an update when observe is called, causing us to
1629 // bind to listener services.
1630 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001631 mListeners.onBootPhaseAppsCanStart();
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001632 mAssistants.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001633 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 }
1635 }
1636
Julia Reynolds88860ce2017-06-01 16:55:49 -04001637 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04001638 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001639 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001640 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001641 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001642 mListenerHints = hints;
1643 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001644 }
1645
Julia Reynolds88860ce2017-06-01 16:55:49 -04001646 @GuardedBy("mNotificationLock")
John Spurlockb4782522014-08-22 14:54:46 -04001647 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001648 final long updatedSuppressedEffects = calculateSuppressedEffects();
1649 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1650 final List<ComponentName> suppressors = getSuppressors();
1651 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1652 mEffectsSuppressors = suppressors;
1653 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001654 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001655 }
1656
Amith Yamasani396a10c2018-01-19 10:58:07 -08001657 private void exitIdle() {
1658 try {
1659 if (mDeviceIdleController != null) {
1660 mDeviceIdleController.exitIdle("notification interaction");
1661 }
1662 } catch (RemoteException e) {
1663 }
1664 }
1665
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001666 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1667 boolean fromListener) {
Julia Reynolds924eed12017-01-19 09:52:07 -05001668 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1669 // cancel
1670 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001671 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
Julia Reynolds924eed12017-01-19 09:52:07 -05001672 null);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001673 if (isUidSystemOrPhone(uid)) {
1674 int[] profileIds = mUserProfiles.getCurrentProfileIds();
1675 int N = profileIds.length;
1676 for (int i = 0; i < N; i++) {
1677 int profileId = profileIds[i];
1678 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1679 profileId, REASON_CHANNEL_BANNED,
1680 null);
1681 }
1682 }
Julia Reynolds924eed12017-01-19 09:52:07 -05001683 }
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001684 final NotificationChannel preUpdate =
1685 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
1686
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001687 mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001688 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
Julia Reynolds924eed12017-01-19 09:52:07 -05001689
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001690 if (!fromListener) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001691 final NotificationChannel modifiedChannel =
1692 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001693 mListeners.notifyNotificationChannelChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001694 pkg, UserHandle.getUserHandleForUid(uid),
1695 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001696 }
1697
Julia Reynolds924eed12017-01-19 09:52:07 -05001698 savePolicyFile();
1699 }
1700
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001701 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1702 NotificationChannel update) {
1703 try {
1704 if ((preUpdate.getImportance() == IMPORTANCE_NONE
1705 && update.getImportance() != IMPORTANCE_NONE)
1706 || (preUpdate.getImportance() != IMPORTANCE_NONE
1707 && update.getImportance() == IMPORTANCE_NONE)) {
1708 getContext().sendBroadcastAsUser(
1709 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001710 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001711 update.getId())
1712 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1713 update.getImportance() == IMPORTANCE_NONE)
1714 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1715 .setPackage(pkg),
1716 UserHandle.of(UserHandle.getUserId(uid)), null);
1717 }
1718 } catch (SecurityException e) {
1719 Slog.w(TAG, "Can't notify app about channel change", e);
1720 }
1721 }
1722
Julia Reynolds005c8b92017-08-24 10:35:53 -04001723 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
1724 boolean fromApp, boolean fromListener) {
1725 Preconditions.checkNotNull(group);
1726 Preconditions.checkNotNull(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001727
1728 final NotificationChannelGroup preUpdate =
1729 mRankingHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
Julia Reynolds005c8b92017-08-24 10:35:53 -04001730 mRankingHelper.createNotificationChannelGroup(pkg, uid, group,
1731 fromApp);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001732 if (!fromApp) {
1733 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
1734 }
Julia Reynolds005c8b92017-08-24 10:35:53 -04001735 if (!fromListener) {
1736 mListeners.notifyNotificationChannelGroupChanged(pkg,
1737 UserHandle.of(UserHandle.getCallingUserId()), group,
1738 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1739 }
1740 }
1741
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001742 private void maybeNotifyChannelGroupOwner(String pkg, int uid,
1743 NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
1744 try {
1745 if (preUpdate.isBlocked() != update.isBlocked()) {
1746 getContext().sendBroadcastAsUser(
1747 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001748 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001749 update.getId())
1750 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1751 update.isBlocked())
1752 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1753 .setPackage(pkg),
1754 UserHandle.of(UserHandle.getUserId(uid)), null);
1755 }
1756 } catch (SecurityException e) {
1757 Slog.w(TAG, "Can't notify app about group change", e);
1758 }
1759 }
1760
Bryce Lee7219ada2016-04-08 10:54:23 -07001761 private ArrayList<ComponentName> getSuppressors() {
1762 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1763 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1764 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1765
1766 for (ManagedServiceInfo info : serviceInfoList) {
1767 names.add(info.component);
1768 }
1769 }
1770
1771 return names;
1772 }
1773
1774 private boolean removeDisabledHints(ManagedServiceInfo info) {
1775 return removeDisabledHints(info, 0);
1776 }
1777
1778 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1779 boolean removed = false;
1780
1781 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1782 final int hint = mListenersDisablingEffects.keyAt(i);
1783 final ArraySet<ManagedServiceInfo> listeners =
1784 mListenersDisablingEffects.valueAt(i);
1785
1786 if (hints == 0 || (hint & hints) == hint) {
1787 removed = removed || listeners.remove(info);
1788 }
1789 }
1790
1791 return removed;
1792 }
1793
1794 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1795 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1796 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1797 }
1798
1799 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1800 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1801 }
1802
1803 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1804 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1805 }
1806 }
1807
1808 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1809 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1810 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1811 }
1812
1813 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1814 hintListeners.add(info);
1815 }
1816
1817 private int calculateHints() {
1818 int hints = 0;
1819 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1820 int hint = mListenersDisablingEffects.keyAt(i);
1821 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1822
1823 if (!serviceInfoList.isEmpty()) {
1824 hints |= hint;
1825 }
1826 }
1827
1828 return hints;
1829 }
1830
1831 private long calculateSuppressedEffects() {
1832 int hints = calculateHints();
1833 long suppressedEffects = 0;
1834
1835 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1836 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1837 }
1838
1839 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1840 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1841 }
1842
1843 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1844 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1845 }
1846
1847 return suppressedEffects;
1848 }
1849
Julia Reynolds88860ce2017-06-01 16:55:49 -04001850 @GuardedBy("mNotificationLock")
Christoph Studer85a384b2014-08-27 20:16:15 +02001851 private void updateInterruptionFilterLocked() {
1852 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1853 if (interruptionFilter == mInterruptionFilter) return;
1854 mInterruptionFilter = interruptionFilter;
1855 scheduleInterruptionFilterChanged(interruptionFilter);
1856 }
1857
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001858 @VisibleForTesting
1859 INotificationManager getBinderService() {
1860 return INotificationManager.Stub.asInterface(mService);
1861 }
1862
Amith Yamasani7ec89412018-02-07 08:48:49 -08001863 /**
1864 * Report to usage stats that the notification was seen.
1865 * @param r notification record
1866 */
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001867 @GuardedBy("mNotificationLock")
Amith Yamasani803eab692017-11-09 17:47:04 -08001868 protected void reportSeen(NotificationRecord r) {
Amith Yamasani803eab692017-11-09 17:47:04 -08001869 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001870 getRealUserId(r.sbn.getUserId()),
Amith Yamasani803eab692017-11-09 17:47:04 -08001871 UsageEvents.Event.NOTIFICATION_SEEN);
1872 }
1873
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001874 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
1875 int targetSdkVersion) {
1876 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
1877 return incomingPolicy.suppressedVisualEffects;
1878 }
1879 final int[] effectsIntroducedInP = {
1880 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
1881 SUPPRESSED_EFFECT_LIGHTS,
1882 SUPPRESSED_EFFECT_PEEK,
1883 SUPPRESSED_EFFECT_STATUS_BAR,
1884 SUPPRESSED_EFFECT_BADGE,
1885 SUPPRESSED_EFFECT_AMBIENT,
1886 SUPPRESSED_EFFECT_NOTIFICATION_LIST
1887 };
1888
1889 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06001890 if (targetSdkVersion < Build.VERSION_CODES.P) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001891 // unset higher order bits introduced in P, maintain the user's higher order bits
1892 for (int i = 0; i < effectsIntroducedInP.length ; i++) {
1893 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
1894 newSuppressedVisualEffects |=
1895 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
1896 }
1897 // set higher order bits according to lower order bits
1898 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1899 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1900 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001901 }
1902 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1903 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1904 }
1905 } else {
1906 boolean hasNewEffects = (newSuppressedVisualEffects
1907 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
1908 // if any of the new effects introduced in P are set
1909 if (hasNewEffects) {
1910 // clear out the deprecated effects
1911 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
1912 | SUPPRESSED_EFFECT_SCREEN_OFF);
1913
1914 // set the deprecated effects according to the new more specific effects
1915 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
1916 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
1917 }
1918 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
1919 && (newSuppressedVisualEffects
1920 & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
1921 && (newSuppressedVisualEffects
1922 & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
1923 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
1924 }
1925 } else {
1926 // set higher order bits according to lower order bits
1927 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1928 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1929 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
1930 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
1931 }
1932 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1933 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1934 }
1935 }
1936 }
1937
1938 return newSuppressedVisualEffects;
1939 }
1940
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001941 @GuardedBy("mNotificationLock")
1942 protected void maybeRecordInterruptionLocked(NotificationRecord r) {
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04001943 if (r.isInterruptive() && !r.hasRecordedInterruption()) {
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001944 mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
1945 r.getChannel().getId(),
1946 getRealUserId(r.sbn.getUserId()));
Julia Reynoldsad7d7132018-03-21 16:05:00 -04001947 logRecentLocked(r);
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04001948 r.setRecordedInterruption(true);
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001949 }
1950 }
1951
Amith Yamasani7ec89412018-02-07 08:48:49 -08001952 /**
1953 * Report to usage stats that the notification was clicked.
1954 * @param r notification record
1955 */
1956 protected void reportUserInteraction(NotificationRecord r) {
Amith Yamasani7ec89412018-02-07 08:48:49 -08001957 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001958 getRealUserId(r.sbn.getUserId()),
Amith Yamasani7ec89412018-02-07 08:48:49 -08001959 UsageEvents.Event.USER_INTERACTION);
1960 }
1961
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001962 private int getRealUserId(int userId) {
1963 return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
1964 }
1965
Geoffrey Pitsch415e4542017-04-10 13:12:58 -04001966 @VisibleForTesting
1967 NotificationManagerInternal getInternalService() {
1968 return mInternalService;
1969 }
1970
Adam Lesinski182f73f2013-12-05 16:48:06 -08001971 private final IBinder mService = new INotificationManager.Stub() {
1972 // Toasts
1973 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001976 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001977 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001978 if (DBG) {
1979 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1980 + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001982
1983 if (pkg == null || callback == null) {
1984 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1985 return ;
1986 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001987 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001988 final boolean isPackageSuspended =
1989 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
Adam Lesinski182f73f2013-12-05 16:48:06 -08001990
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001991 if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001992 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1993 || isPackageSuspended)) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001994 Slog.e(TAG, "Suppressing toast from package " + pkg
1995 + (isPackageSuspended
1996 ? " due to package suspended by administrator."
1997 : " by user request."));
1998 return;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001999 }
2000
2001 synchronized (mToastQueue) {
2002 int callingPid = Binder.getCallingPid();
2003 long callingId = Binder.clearCallingIdentity();
2004 try {
2005 ToastRecord record;
Beverly Tai98efc792018-06-11 14:50:36 +00002006 int index = indexOfToastLocked(pkg, callback);
2007 // If it's already in the queue, we update it in place, we don't
2008 // move it to the end of the queue.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002009 if (index >= 0) {
2010 record = mToastQueue.get(index);
2011 record.update(duration);
2012 } else {
Beverly Tai98efc792018-06-11 14:50:36 +00002013 // Limit the number of toasts that any given package except the android
2014 // package can enqueue. Prevents DOS attacks and deals with leaks.
2015 if (!isSystemToast) {
2016 int count = 0;
2017 final int N = mToastQueue.size();
2018 for (int i=0; i<N; i++) {
2019 final ToastRecord r = mToastQueue.get(i);
2020 if (r.pkg.equals(pkg)) {
2021 count++;
2022 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2023 Slog.e(TAG, "Package has already posted " + count
2024 + " toasts. Not showing more. Package=" + pkg);
2025 return;
2026 }
2027 }
2028 }
2029 }
2030
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002031 Binder token = new Binder();
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002032 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002033 record = new ToastRecord(callingPid, pkg, callback, duration, token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002034 mToastQueue.add(record);
2035 index = mToastQueue.size() - 1;
Beverly Tai98efc792018-06-11 14:50:36 +00002036 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002037 }
2038 // If it's at index 0, it's the current toast. It doesn't matter if it's
2039 // new or just been updated. Call back and tell it to show itself.
2040 // If the callback fails, this will remove it from the list, so don't
2041 // assume that it's valid after this.
2042 if (index == 0) {
2043 showNextToastLocked();
2044 }
2045 } finally {
2046 Binder.restoreCallingIdentity(callingId);
2047 }
2048 }
2049 }
2050
2051 @Override
2052 public void cancelToast(String pkg, ITransientNotification callback) {
2053 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
2054
2055 if (pkg == null || callback == null) {
2056 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
2057 return ;
2058 }
2059
2060 synchronized (mToastQueue) {
2061 long callingId = Binder.clearCallingIdentity();
2062 try {
2063 int index = indexOfToastLocked(pkg, callback);
2064 if (index >= 0) {
2065 cancelToastLocked(index);
2066 } else {
2067 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
2068 + " callback=" + callback);
2069 }
2070 } finally {
2071 Binder.restoreCallingIdentity(callingId);
2072 }
2073 }
2074 }
2075
2076 @Override
Robert Carr997427342018-02-28 18:06:10 -08002077 public void finishToken(String pkg, ITransientNotification callback) {
2078 synchronized (mToastQueue) {
2079 long callingId = Binder.clearCallingIdentity();
2080 try {
2081 int index = indexOfToastLocked(pkg, callback);
2082 if (index >= 0) {
2083 ToastRecord record = mToastQueue.get(index);
2084 finishTokenLocked(record.token);
2085 } else {
2086 Slog.w(TAG, "Toast already killed. pkg=" + pkg
2087 + " callback=" + callback);
2088 }
2089 } finally {
2090 Binder.restoreCallingIdentity(callingId);
2091 }
2092 }
2093 }
2094
2095 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002096 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002097 Notification notification, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002098 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002099 Binder.getCallingPid(), tag, id, notification, userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002100 }
2101
2102 @Override
2103 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002104 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002105 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2106 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002107 // Don't allow client applications to cancel foreground service notis or autobundled
2108 // summaries.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002109 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
Julia Reynoldse5c60452018-04-30 14:41:36 -04002110 (FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
John Spurlocke6a7d932014-03-13 12:29:00 -04002111 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002112 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002113 }
2114
2115 @Override
2116 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002117 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002118
2119 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2120 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
2121
2122 // Calling from user space, don't allow the canceling of actively
2123 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04002124 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
Julia Reynoldse5c60452018-04-30 14:41:36 -04002125 pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05002126 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002127 }
2128
2129 @Override
2130 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
Rohan Shahca0447e2018-03-30 15:18:27 -07002131 enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002132
Chris Wrenacf424a2016-03-15 12:48:55 -04002133 mRankingHelper.setEnabled(pkg, uid, enabled);
Howard Ro4db243a2018-08-07 15:44:25 -07002134 mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
2135 .setType(MetricsEvent.TYPE_ACTION)
2136 .setPackageName(pkg)
2137 .setSubtype(enabled ? 1 : 0));
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002138 // Now, cancel any outstanding notifications that are part of a just-disabled app
Julia Reynolds4da79702017-06-01 11:06:10 -04002139 if (!enabled) {
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002140 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
2141 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
2142 }
Julia Reynoldsfc9767b2018-01-22 17:45:16 -05002143
2144 try {
2145 getContext().sendBroadcastAsUser(
2146 new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
2147 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
2148 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2149 .setPackage(pkg),
2150 UserHandle.of(UserHandle.getUserId(uid)), null);
2151 } catch (SecurityException e) {
2152 Slog.w(TAG, "Can't notify app about app block change", e);
2153 }
2154
Chris Wrenacf424a2016-03-15 12:48:55 -04002155 savePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002156 }
2157
2158 /**
Rohan Shah590e1b22018-04-10 23:48:47 -04002159 * Updates the enabled state for notifications for the given package (and uid).
2160 * Additionally, this method marks the app importance as locked by the user, which means
2161 * that notifications from the app will <b>not</b> be considered for showing a
2162 * blocking helper.
2163 *
2164 * @param pkg package that owns the notifications to update
2165 * @param uid uid of the app providing notifications
2166 * @param enabled whether notifications should be enabled for the app
2167 *
2168 * @see #setNotificationsEnabledForPackage(String, int, boolean)
2169 */
2170 @Override
2171 public void setNotificationsEnabledWithImportanceLockForPackage(
2172 String pkg, int uid, boolean enabled) {
2173 setNotificationsEnabledForPackage(pkg, uid, enabled);
2174
2175 mRankingHelper.setAppImportanceLocked(pkg, uid);
2176 }
2177
2178 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002179 * Use this when you just want to know if notifications are OK for this package.
2180 */
2181 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002182 public boolean areNotificationsEnabled(String pkg) {
2183 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
2184 }
2185
2186 /**
2187 * Use this when you just want to know if notifications are OK for this package.
2188 */
2189 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002190 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002191 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002192
2193 return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002194 }
2195
Chris Wren54bbef42014-07-09 18:37:56 -04002196 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05002197 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002198 checkCallerIsSystemOrSameApp(pkg);
Julia Reynoldsef37f282016-02-12 09:11:27 -05002199 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002200 }
2201
2202 @Override
Julia Reynolds924eed12017-01-19 09:52:07 -05002203 public boolean canShowBadge(String pkg, int uid) {
2204 checkCallerIsSystem();
2205 return mRankingHelper.canShowBadge(pkg, uid);
2206 }
2207
2208 @Override
2209 public void setShowBadge(String pkg, int uid, boolean showBadge) {
2210 checkCallerIsSystem();
2211 mRankingHelper.setShowBadge(pkg, uid, showBadge);
2212 savePolicyFile();
2213 }
2214
2215 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002216 public void updateNotificationChannelGroupForPackage(String pkg, int uid,
2217 NotificationChannelGroup group) throws RemoteException {
2218 enforceSystemOrSystemUI("Caller not system or systemui");
2219 createNotificationChannelGroup(pkg, uid, group, false, false);
2220 savePolicyFile();
2221 }
2222
2223 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002224 public void createNotificationChannelGroups(String pkg,
2225 ParceledListSlice channelGroupList) throws RemoteException {
2226 checkCallerIsSystemOrSameApp(pkg);
2227 List<NotificationChannelGroup> groups = channelGroupList.getList();
2228 final int groupSize = groups.size();
2229 for (int i = 0; i < groupSize; i++) {
2230 final NotificationChannelGroup group = groups.get(i);
Julia Reynolds005c8b92017-08-24 10:35:53 -04002231 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002232 }
2233 savePolicyFile();
2234 }
2235
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002236 private void createNotificationChannelsImpl(String pkg, int uid,
2237 ParceledListSlice channelsList) {
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002238 List<NotificationChannel> channels = channelsList.getList();
2239 final int channelsSize = channels.size();
2240 for (int i = 0; i < channelsSize; i++) {
2241 final NotificationChannel channel = channels.get(i);
2242 Preconditions.checkNotNull(channel, "channel in list is null");
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002243 mRankingHelper.createNotificationChannel(pkg, uid, channel,
Julia Reynolds1fe10942018-03-28 12:46:51 -04002244 true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed(
2245 pkg, UserHandle.getUserId(uid)));
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002246 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002247 UserHandle.getUserHandleForUid(uid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002248 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
2249 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002250 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002251 savePolicyFile();
2252 }
2253
2254 @Override
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002255 public void createNotificationChannels(String pkg,
2256 ParceledListSlice channelsList) throws RemoteException {
2257 checkCallerIsSystemOrSameApp(pkg);
2258 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
2259 }
2260
2261 @Override
2262 public void createNotificationChannelsForPackage(String pkg, int uid,
2263 ParceledListSlice channelsList) throws RemoteException {
2264 checkCallerIsSystem();
2265 createNotificationChannelsImpl(pkg, uid, channelsList);
2266 }
2267
2268 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002269 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002270 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002271 return mRankingHelper.getNotificationChannel(
2272 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002273 }
2274
2275 @Override
2276 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002277 String channelId, boolean includeDeleted) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002278 checkCallerIsSystem();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002279 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002280 }
2281
2282 @Override
2283 public void deleteNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002284 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002285 final int callingUid = Binder.getCallingUid();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002286 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
2287 throw new IllegalArgumentException("Cannot delete default channel");
2288 }
2289 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002290 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
2291 mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
2292 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002293 UserHandle.getUserHandleForUid(callingUid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002294 mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
2295 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002296 savePolicyFile();
2297 }
2298
2299 @Override
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002300 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
2301 checkCallerIsSystemOrSameApp(pkg);
2302 return mRankingHelper.getNotificationChannelGroupWithChannels(
2303 pkg, Binder.getCallingUid(), groupId, false);
2304 }
2305
2306 @Override
Julia Reynolds9bfba592017-03-15 14:03:55 -04002307 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
2308 String pkg) {
2309 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds173a4822018-09-21 15:20:13 -04002310
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002311 return mRankingHelper.getNotificationChannelGroups(
Julia Reynolds173a4822018-09-21 15:20:13 -04002312 pkg, Binder.getCallingUid(), false, false, true);
Julia Reynolds9bfba592017-03-15 14:03:55 -04002313 }
2314
2315 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002316 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04002317 checkCallerIsSystemOrSameApp(pkg);
2318
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002319 final int callingUid = Binder.getCallingUid();
2320 NotificationChannelGroup groupToDelete =
2321 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
2322 if (groupToDelete != null) {
2323 List<NotificationChannel> deletedChannels =
2324 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
2325 for (int i = 0; i < deletedChannels.size(); i++) {
2326 final NotificationChannel deletedChannel = deletedChannels.get(i);
2327 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2328 true,
2329 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2330 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002331 mListeners.notifyNotificationChannelChanged(pkg,
2332 UserHandle.getUserHandleForUid(callingUid),
2333 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002334 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2335 }
2336 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002337 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2338 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002339 savePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002340 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04002341 }
2342
2343 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002344 public void updateNotificationChannelForPackage(String pkg, int uid,
2345 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002346 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05002347 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002348 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002349 }
2350
2351 @Override
2352 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002353 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002354 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002355 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002356 }
2357
2358 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002359 public int getNumNotificationChannelsForPackage(String pkg, int uid,
2360 boolean includeDeleted) {
2361 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
2362 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
2363 .getList().size();
2364 }
2365
2366 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04002367 public boolean onlyHasDefaultChannel(String pkg, int uid) {
2368 enforceSystemOrSystemUI("onlyHasDefaultChannel");
2369 return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
2370 }
2371
2372 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04002373 public int getDeletedChannelCount(String pkg, int uid) {
2374 enforceSystemOrSystemUI("getDeletedChannelCount");
2375 return mRankingHelper.getDeletedChannelCount(pkg, uid);
2376 }
2377
2378 @Override
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002379 public int getBlockedChannelCount(String pkg, int uid) {
2380 enforceSystemOrSystemUI("getBlockedChannelCount");
2381 return mRankingHelper.getBlockedChannelCount(pkg, uid);
2382 }
2383
2384 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002385 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2386 String pkg, int uid, boolean includeDeleted) {
2387 checkCallerIsSystem();
Julia Reynolds173a4822018-09-21 15:20:13 -04002388
2389 return mRankingHelper.getNotificationChannelGroups(
2390 pkg, uid, includeDeleted, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002391 }
2392
2393 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002394 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2395 String pkg, int uid, String groupId, boolean includeDeleted) {
2396 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
2397 return mRankingHelper.getNotificationChannelGroupWithChannels(
2398 pkg, uid, groupId, includeDeleted);
2399 }
2400
2401 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002402 public NotificationChannelGroup getNotificationChannelGroupForPackage(
2403 String groupId, String pkg, int uid) {
2404 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
2405 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
2406 }
2407
2408 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002409 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
2410 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002411 return mRankingHelper.getNotificationChannels(
2412 pkg, Binder.getCallingUid(), false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002413 }
2414
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002415 @Override
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05002416 public ParceledListSlice<NotifyingApp> getRecentNotifyingAppsForUser(int userId) {
2417 checkCallerIsSystem();
2418 synchronized (mNotificationLock) {
2419 List<NotifyingApp> apps = new ArrayList<>(
2420 mRecentApps.getOrDefault(userId, new ArrayList<>()));
2421 return new ParceledListSlice<>(apps);
2422 }
2423 }
2424
2425 @Override
Julia Reynoldse273f082018-04-12 13:48:49 -04002426 public int getBlockedAppCount(int userId) {
2427 checkCallerIsSystem();
2428 return mRankingHelper.getBlockedAppCount(userId);
2429 }
2430
2431 @Override
Beverly86d076f2018-04-17 14:44:52 -04002432 public boolean areChannelsBypassingDnd() {
2433 return mRankingHelper.areChannelsBypassingDnd();
2434 }
2435
2436 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05002437 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002438 checkCallerIsSystem();
2439
2440 // Cancel posted notifications
2441 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2442 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2443
Julia Reynoldsb852e562017-06-06 16:14:18 -04002444 final String[] packages = new String[] {packageName};
2445 final int[] uids = new int[] {uid};
2446
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002447 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04002448 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002449 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002450
2451 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04002452 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002453
2454 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05002455 if (!fromApp) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002456 mRankingHelper.onPackagesChanged(
2457 true, UserHandle.getCallingUserId(), packages, uids);
Julia Reynolds5355e852017-02-07 14:54:13 -05002458 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002459
2460 savePolicyFile();
2461 }
2462
2463
Adam Lesinski182f73f2013-12-05 16:48:06 -08002464 /**
2465 * System-only API for getting a list of current (i.e. not cleared) notifications.
2466 *
2467 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04002468 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002469 */
2470 @Override
2471 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2472 // enforce() will ensure the calling uid has the correct permission
2473 getContext().enforceCallingOrSelfPermission(
2474 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2475 "NotificationManagerService.getActiveNotifications");
2476
2477 StatusBarNotification[] tmp = null;
2478 int uid = Binder.getCallingUid();
2479
2480 // noteOp will check to make sure the callingPkg matches the uid
2481 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2482 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002483 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002484 tmp = new StatusBarNotification[mNotificationList.size()];
2485 final int N = mNotificationList.size();
2486 for (int i=0; i<N; i++) {
2487 tmp[i] = mNotificationList.get(i).sbn;
2488 }
2489 }
2490 }
2491 return tmp;
2492 }
2493
2494 /**
Dan Sandler994349c2015-04-15 11:02:54 -04002495 * Public API for getting a list of current notifications for the calling package/uid.
2496 *
Julia Reynolds573c6532017-01-24 17:44:38 -05002497 * Note that since notification posting is done asynchronously, this will not return
2498 * notifications that are in the process of being posted.
2499 *
Dan Sandler994349c2015-04-15 11:02:54 -04002500 * @returns A list of all the package's notifications, in natural order.
2501 */
2502 @Override
2503 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2504 int incomingUserId) {
2505 checkCallerIsSystemOrSameApp(pkg);
2506 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2507 Binder.getCallingUid(), incomingUserId, true, false,
2508 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002509 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002510 final ArrayMap<String, StatusBarNotification> map
2511 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002512 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002513 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002514 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2515 mNotificationList.get(i).sbn);
2516 if (sbn != null) {
2517 map.put(sbn.getKey(), sbn);
2518 }
2519 }
2520 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2521 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2522 if (sbn != null) {
2523 map.put(sbn.getKey(), sbn);
2524 }
2525 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002526 final int M = mEnqueuedNotifications.size();
2527 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002528 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2529 mEnqueuedNotifications.get(i).sbn);
2530 if (sbn != null) {
2531 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04002532 }
2533 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002534 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2535 list.addAll(map.values());
2536 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04002537 }
Dan Sandler994349c2015-04-15 11:02:54 -04002538 }
2539
Chris Wren6676dab2016-12-21 18:26:27 -05002540 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2541 StatusBarNotification sbn) {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04002542 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
Chris Wren6676dab2016-12-21 18:26:27 -05002543 // We could pass back a cloneLight() but clients might get confused and
2544 // try to send this thing back to notify() again, which would not work
2545 // very well.
2546 return new StatusBarNotification(
2547 sbn.getPackageName(),
2548 sbn.getOpPkg(),
Chris Wren6676dab2016-12-21 18:26:27 -05002549 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2550 sbn.getNotification().clone(),
2551 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2552 }
2553 return null;
2554 }
2555
Dan Sandler994349c2015-04-15 11:02:54 -04002556 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002557 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2558 *
2559 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2560 */
2561 @Override
2562 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2563 // enforce() will ensure the calling uid has the correct permission
2564 getContext().enforceCallingOrSelfPermission(
2565 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2566 "NotificationManagerService.getHistoricalNotifications");
2567
2568 StatusBarNotification[] tmp = null;
2569 int uid = Binder.getCallingUid();
2570
2571 // noteOp will check to make sure the callingPkg matches the uid
2572 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2573 == AppOpsManager.MODE_ALLOWED) {
2574 synchronized (mArchive) {
2575 tmp = mArchive.getArray(count);
2576 }
2577 }
2578 return tmp;
2579 }
2580
2581 /**
2582 * Register a listener binder directly with the notification manager.
2583 *
2584 * Only works with system callers. Apps should extend
2585 * {@link android.service.notification.NotificationListenerService}.
2586 */
2587 @Override
2588 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05002589 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02002590 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05002591 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002592 }
2593
2594 /**
2595 * Remove a listener binder directly
2596 */
2597 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002598 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05002599 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002600 }
2601
2602 /**
2603 * Allow an INotificationListener to simulate a "clear all" operation.
2604 *
2605 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2606 *
2607 * @param token The binder for the listener, to check that the caller is allowed
2608 */
2609 @Override
John Spurlocka4294292014-03-24 18:02:32 -04002610 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002611 final int callingUid = Binder.getCallingUid();
2612 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002613 long identity = Binder.clearCallingIdentity();
2614 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002615 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002616 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Beverly5a20a5e2018-03-06 15:02:44 -05002617
John Spurlocka4294292014-03-24 18:02:32 -04002618 if (keys != null) {
2619 final int N = keys.length;
2620 for (int i = 0; i < N; i++) {
2621 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07002622 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00002623 final int userId = r.sbn.getUserId();
2624 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04002625 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00002626 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04002627 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00002628 }
Griff Hazen335e1f02014-09-11 14:49:31 -07002629 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2630 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2631 userId);
John Spurlocka4294292014-03-24 18:02:32 -04002632 }
2633 } else {
2634 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00002635 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04002636 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002637 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002638 } finally {
2639 Binder.restoreCallingIdentity(identity);
2640 }
2641 }
2642
Chris Wrenab41eec2016-01-04 18:01:27 -05002643 /**
2644 * Handle request from an approved listener to re-enable itself.
2645 *
2646 * @param component The componenet to be re-enabled, caller must match package.
2647 */
2648 @Override
2649 public void requestBindListener(ComponentName component) {
2650 checkCallerIsSystemOrSameApp(component.getPackageName());
2651 long identity = Binder.clearCallingIdentity();
2652 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002653 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002654 mAssistants.isComponentEnabledForCurrentProfiles(component)
2655 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05002656 : mListeners;
2657 manager.setComponentState(component, true);
2658 } finally {
2659 Binder.restoreCallingIdentity(identity);
2660 }
2661 }
2662
2663 @Override
2664 public void requestUnbindListener(INotificationListener token) {
2665 long identity = Binder.clearCallingIdentity();
2666 try {
2667 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002668 synchronized (mNotificationLock) {
2669 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2670 info.getOwner().setComponentState(info.component, false);
2671 }
Chris Wrenab41eec2016-01-04 18:01:27 -05002672 } finally {
2673 Binder.restoreCallingIdentity(identity);
2674 }
2675 }
2676
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002677 @Override
2678 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002679 long identity = Binder.clearCallingIdentity();
2680 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002681 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002682 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2683 if (keys != null) {
2684 final int N = keys.length;
2685 for (int i = 0; i < N; i++) {
2686 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2687 if (r == null) continue;
2688 final int userId = r.sbn.getUserId();
2689 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2690 !mUserProfiles.isCurrentProfile(userId)) {
2691 throw new SecurityException("Disallowed call from listener: "
2692 + info.service);
2693 }
2694 if (!r.isSeen()) {
2695 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
Amith Yamasani803eab692017-11-09 17:47:04 -08002696 reportSeen(r);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002697 r.setSeen();
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04002698 maybeRecordInterruptionLocked(r);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002699 }
2700 }
2701 }
2702 }
2703 } finally {
2704 Binder.restoreCallingIdentity(identity);
2705 }
2706 }
2707
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002708 /**
2709 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2710 *
2711 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2712 *
Julia Reynolds79672302017-01-12 08:30:16 -05002713 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002714 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04002715 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04002716 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00002717 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04002718 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -04002719 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
John Spurlocka4294292014-03-24 18:02:32 -04002720 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00002721 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04002722 }
2723
Adam Lesinski182f73f2013-12-05 16:48:06 -08002724 /**
Julia Reynolds79672302017-01-12 08:30:16 -05002725 * Allow an INotificationListener to snooze a single notification until a context.
2726 *
2727 * @param token The binder for the listener, to check that the caller is allowed
2728 */
2729 @Override
2730 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2731 String key, String snoozeCriterionId) {
2732 long identity = Binder.clearCallingIdentity();
2733 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002734 synchronized (mNotificationLock) {
2735 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2736 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2737 }
Julia Reynolds79672302017-01-12 08:30:16 -05002738 } finally {
2739 Binder.restoreCallingIdentity(identity);
2740 }
2741 }
2742
2743 /**
2744 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002745 *
2746 * @param token The binder for the listener, to check that the caller is allowed
2747 */
2748 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002749 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05002750 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002751 long identity = Binder.clearCallingIdentity();
2752 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002753 synchronized (mNotificationLock) {
2754 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2755 snoozeNotificationInt(key, duration, null, info);
2756 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002757 } finally {
2758 Binder.restoreCallingIdentity(identity);
2759 }
2760 }
2761
2762 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002763 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002764 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002765 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002766 */
2767 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002768 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002769 long identity = Binder.clearCallingIdentity();
2770 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002771 synchronized (mNotificationLock) {
2772 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002773 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002774 unsnoozeNotificationInt(key, info);
2775 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002776 } finally {
2777 Binder.restoreCallingIdentity(identity);
2778 }
2779 }
2780
2781 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002782 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2783 *
2784 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2785 *
2786 * @param token The binder for the listener, to check that the caller is allowed
2787 */
2788 @Override
2789 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2790 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002791 final int callingUid = Binder.getCallingUid();
2792 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002793 long identity = Binder.clearCallingIdentity();
2794 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002795 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002796 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00002797 if (info.supportsProfiles()) {
2798 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2799 + "from " + info.component
2800 + " use cancelNotification(key) instead.");
2801 } else {
2802 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2803 pkg, tag, id, info.userid);
2804 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002805 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002806 } finally {
2807 Binder.restoreCallingIdentity(identity);
2808 }
2809 }
2810
2811 /**
2812 * Allow an INotificationListener to request the list of outstanding notifications seen by
2813 * the current user. Useful when starting up, after which point the listener callbacks
2814 * should be used.
2815 *
2816 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002817 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04002818 * @returns The return value will contain the notifications specified in keys, in that
2819 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002820 */
2821 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02002822 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02002823 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002824 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002825 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002826 final boolean getKeys = keys != null;
2827 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02002828 final ArrayList<StatusBarNotification> list
2829 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02002830 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002831 final NotificationRecord r = getKeys
2832 ? mNotificationsByKey.get(keys[i])
2833 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02002834 if (r == null) continue;
2835 StatusBarNotification sbn = r.sbn;
2836 if (!isVisibleToListener(sbn, info)) continue;
2837 StatusBarNotification sbnToSend =
2838 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2839 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002840 }
Christoph Studercee44ba2014-05-20 18:36:43 +02002841 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002842 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002843 }
2844
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002845 /**
2846 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2847 * seen by the current user. Useful when starting up, after which point the listener
2848 * callbacks should be used.
2849 *
2850 * @param token The binder for the listener, to check that the caller is allowed
2851 * @returns The return value will contain the notifications specified in keys, in that
2852 * order, or if keys is null, all the notifications, in natural order.
2853 */
2854 @Override
2855 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2856 INotificationListener token, int trim) {
2857 synchronized (mNotificationLock) {
2858 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2859 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2860 final int N = snoozedRecords.size();
2861 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2862 for (int i=0; i < N; i++) {
2863 final NotificationRecord r = snoozedRecords.get(i);
2864 if (r == null) continue;
2865 StatusBarNotification sbn = r.sbn;
2866 if (!isVisibleToListener(sbn, info)) continue;
2867 StatusBarNotification sbnToSend =
2868 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2869 list.add(sbnToSend);
2870 }
2871 return new ParceledListSlice<>(list);
2872 }
2873 }
2874
Adam Lesinski182f73f2013-12-05 16:48:06 -08002875 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002876 public void requestHintsFromListener(INotificationListener token, int hints) {
2877 final long identity = Binder.clearCallingIdentity();
2878 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002879 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002880 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07002881 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2882 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2883 | HINT_HOST_DISABLE_CALL_EFFECTS;
2884 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04002885 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07002886 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002887 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07002888 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002889 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002890 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04002891 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04002892 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002893 } finally {
2894 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04002895 }
2896 }
2897
2898 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002899 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002900 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002901 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04002902 }
2903 }
2904
2905 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02002906 public void requestInterruptionFilterFromListener(INotificationListener token,
2907 int interruptionFilter) throws RemoteException {
2908 final long identity = Binder.clearCallingIdentity();
2909 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002910 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002911 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2912 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02002913 updateInterruptionFilterLocked();
2914 }
2915 } finally {
2916 Binder.restoreCallingIdentity(identity);
2917 }
2918 }
2919
2920 @Override
2921 public int getInterruptionFilterFromListener(INotificationListener token)
2922 throws RemoteException {
2923 synchronized (mNotificationLight) {
2924 return mInterruptionFilter;
2925 }
2926 }
2927
2928 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02002929 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2930 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002931 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02002932 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2933 if (info == null) return;
2934 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2935 }
2936 }
2937
2938 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002939 public int getZenMode() {
2940 return mZenModeHelper.getZenMode();
2941 }
2942
2943 @Override
John Spurlock056c5192014-04-20 21:52:01 -04002944 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002945 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04002946 return mZenModeHelper.getConfig();
2947 }
2948
2949 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002950 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002951 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05002952 final long identity = Binder.clearCallingIdentity();
2953 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002954 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05002955 } finally {
2956 Binder.restoreCallingIdentity(identity);
2957 }
2958 }
2959
2960 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002961 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002962 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05002963 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002964 }
2965
2966 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002967 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2968 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002969 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002970 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002971 }
2972
2973 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002974 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002975 throws RemoteException {
2976 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2977 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2978 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2979 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002980 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002981
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002982 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2983 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002984 }
2985
2986 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002987 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002988 throws RemoteException {
2989 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2990 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2991 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2992 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2993 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002994
Julia Reynolds361e82d32016-02-26 18:19:49 -05002995 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002996 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002997 }
2998
2999 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003000 public boolean removeAutomaticZenRule(String id) throws RemoteException {
3001 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003002 // Verify that they can modify zen rules.
3003 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
3004
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003005 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003006 }
3007
3008 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05003009 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
3010 Preconditions.checkNotNull(packageName, "Package name is null");
3011 enforceSystemOrSystemUI("removeAutomaticZenRules");
3012
3013 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
3014 }
3015
3016 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05003017 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
3018 Preconditions.checkNotNull(owner, "Owner is null");
3019 enforceSystemOrSystemUI("getRuleInstanceCount");
3020
3021 return mZenModeHelper.getCurrentInstanceCount(owner);
3022 }
3023
3024 @Override
John Spurlock80774932015-05-07 17:38:50 -04003025 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
3026 enforcePolicyAccess(pkg, "setInterruptionFilter");
3027 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
3028 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
3029 final long identity = Binder.clearCallingIdentity();
3030 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04003031 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04003032 } finally {
3033 Binder.restoreCallingIdentity(identity);
3034 }
3035 }
3036
3037 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04003038 public void notifyConditions(final String pkg, IConditionProvider provider,
3039 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04003040 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3041 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04003042 mHandler.post(new Runnable() {
3043 @Override
3044 public void run() {
3045 mConditionProviders.notifyConditions(pkg, info, conditions);
3046 }
3047 });
John Spurlocke77bb362014-04-26 10:24:59 -04003048 }
3049
Julia Reynolds38e6ca42016-08-08 08:38:09 -04003050 @Override
3051 public void requestUnbindProvider(IConditionProvider provider) {
3052 long identity = Binder.clearCallingIdentity();
3053 try {
3054 // allow bound services to disable themselves
3055 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3056 info.getOwner().setComponentState(info.component, false);
3057 } finally {
3058 Binder.restoreCallingIdentity(identity);
3059 }
3060 }
3061
3062 @Override
3063 public void requestBindProvider(ComponentName component) {
3064 checkCallerIsSystemOrSameApp(component.getPackageName());
3065 long identity = Binder.clearCallingIdentity();
3066 try {
3067 mConditionProviders.setComponentState(component, true);
3068 } finally {
3069 Binder.restoreCallingIdentity(identity);
3070 }
3071 }
3072
John Spurlocke77bb362014-04-26 10:24:59 -04003073 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003074 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04003075 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
3076 message);
John Spurlock7340fc82014-04-24 18:50:12 -04003077 }
3078
Julia Reynolds48034f82016-03-09 10:15:16 -05003079 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
3080 try {
3081 checkCallerIsSystemOrSameApp(pkg);
3082 } catch (SecurityException e) {
3083 getContext().enforceCallingPermission(
3084 android.Manifest.permission.STATUS_BAR_SERVICE,
3085 message);
3086 }
3087 }
3088
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003089 private void enforcePolicyAccess(int uid, String method) {
3090 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3091 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3092 return;
3093 }
3094 boolean accessAllowed = false;
3095 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
3096 final int packageCount = packages.length;
3097 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003098 if (mConditionProviders.isPackageOrComponentAllowed(
3099 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003100 accessAllowed = true;
3101 }
3102 }
3103 if (!accessAllowed) {
3104 Slog.w(TAG, "Notification policy access denied calling " + method);
3105 throw new SecurityException("Notification policy access denied");
3106 }
3107 }
3108
John Spurlock80774932015-05-07 17:38:50 -04003109 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04003110 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3111 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3112 return;
3113 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04003114 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003115 if (!checkPolicyAccess(pkg)) {
3116 Slog.w(TAG, "Notification policy access denied calling " + method);
3117 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04003118 }
3119 }
3120
John Spurlock80774932015-05-07 17:38:50 -04003121 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003122 return mConditionProviders.isPackageOrComponentAllowed(
3123 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04003124 }
3125
3126 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003127 try {
Jason Parks50322ff2018-03-27 10:23:33 -05003128 int uid = getContext().getPackageManager().getPackageUidAsUser(pkg,
3129 UserHandle.getCallingUserId());
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003130 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
3131 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
3132 -1, true)) {
3133 return true;
3134 }
3135 } catch (NameNotFoundException e) {
3136 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003137 }
Jason Parks50322ff2018-03-27 10:23:33 -05003138 return checkPackagePolicyAccess(pkg)
3139 || mListeners.isComponentEnabledForPackage(pkg)
3140 || (mDpm != null &&
3141 mDpm.isActiveAdminWithPolicy(Binder.getCallingUid(),
3142 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER));
John Spurlock1fc476d2015-04-14 16:05:20 -04003143 }
3144
John Spurlock7340fc82014-04-24 18:50:12 -04003145 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08003146 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003147 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04003148 final DumpFilter filter = DumpFilter.parseFromArguments(args);
Kweku Adams887f09c2017-11-13 17:12:20 -08003149 if (filter.stats) {
Chris Wrene4b38802015-07-07 15:54:19 -04003150 dumpJson(pw, filter);
Kweku Adams887f09c2017-11-13 17:12:20 -08003151 } else if (filter.proto) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003152 dumpProto(fd, filter);
Vishnu Naire3e4d252018-03-01 11:26:57 -08003153 } else if (filter.criticalPriority) {
3154 dumpNotificationRecords(pw, filter);
Chris Wrene4b38802015-07-07 15:54:19 -04003155 } else {
3156 dumpImpl(pw, filter);
3157 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003158 }
John Spurlockb4782522014-08-22 14:54:46 -04003159
3160 @Override
3161 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07003162 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04003163 }
John Spurlock2b122f42014-08-27 16:29:47 -04003164
3165 @Override
3166 public boolean matchesCallFilter(Bundle extras) {
3167 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02003168 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003169 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02003170 extras,
3171 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
3172 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
3173 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04003174 }
John Spurlock530052a2014-11-30 16:26:19 -05003175
3176 @Override
3177 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003178 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04003179 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05003180 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003181
Christopher Tatef9767d62015-04-08 14:35:43 -07003182 // Backup/restore interface
3183 @Override
3184 public byte[] getBackupPayload(int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003185 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003186 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003187 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003188 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003189 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
3190 return null;
3191 }
songjinshi9bf22712017-02-04 10:47:45 +08003192 synchronized(mPolicyFile) {
3193 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
3194 try {
3195 writePolicyXml(baos, true /*forBackup*/);
3196 return baos.toByteArray();
3197 } catch (IOException e) {
3198 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
3199 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003200 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003201 return null;
3202 }
3203
3204 @Override
3205 public void applyRestore(byte[] payload, int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003206 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003207 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
3208 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
3209 if (payload == null) {
3210 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
3211 return;
3212 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003213 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003214 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003215 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
3216 return;
3217 }
songjinshi9bf22712017-02-04 10:47:45 +08003218 synchronized(mPolicyFile) {
3219 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
3220 try {
3221 readPolicyXml(bais, true /*forRestore*/);
3222 savePolicyFile();
3223 } catch (NumberFormatException | XmlPullParserException | IOException e) {
3224 Slog.w(TAG, "applyRestore: error reading payload", e);
3225 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003226 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003227 }
3228
John Spurlock1fc476d2015-04-14 16:05:20 -04003229 @Override
John Spurlock80774932015-05-07 17:38:50 -04003230 public boolean isNotificationPolicyAccessGranted(String pkg) {
3231 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04003232 }
3233
3234 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05003235 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
3236 enforceSystemOrSystemUIOrSamePackage(pkg,
3237 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003238 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003239 }
3240
3241 @Override
John Spurlock80774932015-05-07 17:38:50 -04003242 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
3243 throws RemoteException {
Julia Reynolds92febc32017-10-26 11:30:31 -04003244 setNotificationPolicyAccessGrantedForUser(
3245 pkg, getCallingUserHandle().getIdentifier(), granted);
3246 }
3247
3248 @Override
3249 public void setNotificationPolicyAccessGrantedForUser(
3250 String pkg, int userId, boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003251 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003252 final long identity = Binder.clearCallingIdentity();
3253 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003254 if (mAllowedManagedServicePackages.test(pkg)) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003255 mConditionProviders.setPackageOrComponentEnabled(
Julia Reynolds92febc32017-10-26 11:30:31 -04003256 pkg, userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003257
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003258 getContext().sendBroadcastAsUser(new Intent(
3259 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3260 .setPackage(pkg)
3261 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003262 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003263 savePolicyFile();
3264 }
3265 } finally {
3266 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003267 }
John Spurlock80774932015-05-07 17:38:50 -04003268 }
3269
3270 @Override
3271 public Policy getNotificationPolicy(String pkg) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003272 final long identity = Binder.clearCallingIdentity();
3273 try {
3274 return mZenModeHelper.getNotificationPolicy();
3275 } finally {
3276 Binder.restoreCallingIdentity(identity);
3277 }
3278 }
3279
Beverly6697eff2017-12-14 15:00:27 -05003280 /**
3281 * Sets the notification policy. Apps that target API levels below
Beverly98ef61b2018-02-15 10:36:28 -05003282 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
Beverlyd6964762018-02-16 14:07:03 -05003283 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3284 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3285 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
Beverly6697eff2017-12-14 15:00:27 -05003286 */
John Spurlock1fc476d2015-04-14 16:05:20 -04003287 @Override
John Spurlock80774932015-05-07 17:38:50 -04003288 public void setNotificationPolicy(String pkg, Policy policy) {
3289 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04003290 final long identity = Binder.clearCallingIdentity();
3291 try {
Beverly6697eff2017-12-14 15:00:27 -05003292 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3293 0, UserHandle.getUserId(MY_UID));
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003294 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
Beverly6697eff2017-12-14 15:00:27 -05003295
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06003296 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
Beverly98ef61b2018-02-15 10:36:28 -05003297 int priorityCategories = policy.priorityCategories;
3298 // ignore alarm and media values from new policy
3299 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
Beverlyd6964762018-02-16 14:07:03 -05003300 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3301 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003302 // use user-designated values
Beverlyd6964762018-02-16 14:07:03 -05003303 priorityCategories |= currPolicy.priorityCategories
3304 & Policy.PRIORITY_CATEGORY_ALARMS;
3305 priorityCategories |= currPolicy.priorityCategories
3306 & Policy.PRIORITY_CATEGORY_MEDIA;
3307 priorityCategories |= currPolicy.priorityCategories
3308 & Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003309
Beverly6697eff2017-12-14 15:00:27 -05003310 policy = new Policy(priorityCategories,
3311 policy.priorityCallSenders, policy.priorityMessageSenders,
3312 policy.suppressedVisualEffects);
3313 }
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003314 int newVisualEffects = calculateSuppressedVisualEffects(
3315 policy, currPolicy, applicationInfo.targetSdkVersion);
3316 policy = new Policy(policy.priorityCategories,
3317 policy.priorityCallSenders, policy.priorityMessageSenders,
3318 newVisualEffects);
Beverly5e073222018-03-08 10:36:25 -05003319 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
John Spurlock1fc476d2015-04-14 16:05:20 -04003320 mZenModeHelper.setNotificationPolicy(policy);
Beverly6697eff2017-12-14 15:00:27 -05003321 } catch (RemoteException e) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003322 } finally {
3323 Binder.restoreCallingIdentity(identity);
3324 }
3325 }
Chris Wren51017d02015-12-15 15:34:46 -05003326
3327 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003328 public List<String> getEnabledNotificationListenerPackages() {
3329 checkCallerIsSystem();
3330 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3331 }
3332
3333 @Override
3334 public List<ComponentName> getEnabledNotificationListeners(int userId) {
3335 checkCallerIsSystem();
3336 return mListeners.getAllowedComponents(userId);
3337 }
3338
3339 @Override
3340 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3341 Preconditions.checkNotNull(listener);
3342 checkCallerIsSystemOrSameApp(listener.getPackageName());
3343 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3344 getCallingUserHandle().getIdentifier());
3345 }
3346
3347 @Override
3348 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3349 int userId) {
3350 Preconditions.checkNotNull(listener);
3351 checkCallerIsSystem();
3352 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3353 userId);
3354 }
3355
3356 @Override
3357 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3358 Preconditions.checkNotNull(assistant);
3359 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003360 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04003361 getCallingUserHandle().getIdentifier());
3362 }
3363
3364 @Override
3365 public void setNotificationListenerAccessGranted(ComponentName listener,
3366 boolean granted) throws RemoteException {
3367 setNotificationListenerAccessGrantedForUser(
3368 listener, getCallingUserHandle().getIdentifier(), granted);
3369 }
3370
3371 @Override
3372 public void setNotificationAssistantAccessGranted(ComponentName assistant,
3373 boolean granted) throws RemoteException {
3374 setNotificationAssistantAccessGrantedForUser(
3375 assistant, getCallingUserHandle().getIdentifier(), granted);
3376 }
3377
3378 @Override
3379 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3380 boolean granted) throws RemoteException {
3381 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04003382 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003383 final long identity = Binder.clearCallingIdentity();
3384 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003385 if (mAllowedManagedServicePackages.test(listener.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003386 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3387 userId, false, granted);
3388 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3389 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003390
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003391 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds92febc32017-10-26 11:30:31 -04003392 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003393 .setPackage(listener.getPackageName())
3394 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003395 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003396
3397 savePolicyFile();
3398 }
3399 } finally {
3400 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003401 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003402 }
3403
3404 @Override
3405 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3406 int userId, boolean granted) throws RemoteException {
3407 Preconditions.checkNotNull(assistant);
Julia Reynolds0d217642017-08-11 11:26:04 -04003408 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003409 final long identity = Binder.clearCallingIdentity();
3410 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003411 if (mAllowedManagedServicePackages.test(assistant.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003412 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
3413 userId, false, granted);
3414 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
3415 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003416
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003417 getContext().sendBroadcastAsUser(new Intent(
3418 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3419 .setPackage(assistant.getPackageName())
3420 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003421 UserHandle.of(userId), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003422
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003423 savePolicyFile();
3424 }
3425 } finally {
3426 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003427 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003428 }
3429
3430 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003431 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
3432 Adjustment adjustment) throws RemoteException {
3433 final long identity = Binder.clearCallingIdentity();
3434 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003435 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003436 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003437 int N = mEnqueuedNotifications.size();
3438 for (int i = 0; i < N; i++) {
3439 final NotificationRecord n = mEnqueuedNotifications.get(i);
3440 if (Objects.equals(adjustment.getKey(), n.getKey())
3441 && Objects.equals(adjustment.getUser(), n.getUserId())) {
3442 applyAdjustment(n, adjustment);
3443 break;
3444 }
3445 }
3446 }
3447 } finally {
3448 Binder.restoreCallingIdentity(identity);
3449 }
3450 }
3451
3452 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003453 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003454 Adjustment adjustment) throws RemoteException {
Chris Wren51017d02015-12-15 15:34:46 -05003455 final long identity = Binder.clearCallingIdentity();
3456 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003457 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003458 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003459 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3460 applyAdjustment(n, adjustment);
Chris Wren51017d02015-12-15 15:34:46 -05003461 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003462 mRankingHandler.requestSort();
Julia Reynoldse46bb372016-03-17 11:05:58 -04003463 } finally {
3464 Binder.restoreCallingIdentity(identity);
3465 }
3466 }
3467
3468 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003469 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003470 List<Adjustment> adjustments) throws RemoteException {
3471
3472 final long identity = Binder.clearCallingIdentity();
3473 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003474 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003475 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003476 for (Adjustment adjustment : adjustments) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003477 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3478 applyAdjustment(n, adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003479 }
3480 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003481 mRankingHandler.requestSort();
Chris Wren51017d02015-12-15 15:34:46 -05003482 } finally {
3483 Binder.restoreCallingIdentity(identity);
3484 }
3485 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003486
3487 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04003488 public void updateNotificationChannelGroupFromPrivilegedListener(
3489 INotificationListener token, String pkg, UserHandle user,
3490 NotificationChannelGroup group) throws RemoteException {
3491 Preconditions.checkNotNull(user);
3492 verifyPrivilegedListener(token, user);
3493 createNotificationChannelGroup(
3494 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
3495 savePolicyFile();
3496 }
3497
3498 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003499 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003500 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003501 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003502 Preconditions.checkNotNull(pkg);
3503 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003504
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003505 verifyPrivilegedListener(token, user);
3506 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003507 }
3508
3509 @Override
3510 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003511 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3512 Preconditions.checkNotNull(pkg);
3513 Preconditions.checkNotNull(user);
3514 verifyPrivilegedListener(token, user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003515
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003516 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
3517 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003518 }
3519
3520 @Override
3521 public ParceledListSlice<NotificationChannelGroup>
3522 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003523 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3524 Preconditions.checkNotNull(pkg);
3525 Preconditions.checkNotNull(user);
3526 verifyPrivilegedListener(token, user);
3527
3528 List<NotificationChannelGroup> groups = new ArrayList<>();
3529 groups.addAll(mRankingHelper.getNotificationChannelGroups(
3530 pkg, getUidForPackageAndUser(pkg, user)));
3531 return new ParceledListSlice<>(groups);
3532 }
3533
3534 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003535 ManagedServiceInfo info;
3536 synchronized (mNotificationLock) {
3537 info = mListeners.checkServiceTokenLocked(token);
3538 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003539 if (!hasCompanionDevice(info)) {
3540 throw new SecurityException(info + " does not have access");
3541 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003542 if (!info.enabledAndUserMatches(user.getIdentifier())) {
3543 throw new SecurityException(info + " does not have access");
3544 }
3545 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003546
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003547 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3548 int uid = 0;
3549 long identity = Binder.clearCallingIdentity();
3550 try {
3551 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3552 } finally {
3553 Binder.restoreCallingIdentity(identity);
3554 }
3555 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003556 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003557
3558 @Override
3559 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3560 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3561 throws RemoteException {
3562 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3563 }
John Spurlock1fc476d2015-04-14 16:05:20 -04003564 };
John Spurlocka4294292014-03-24 18:02:32 -04003565
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003566 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3567 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003568 return;
3569 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003570 if (adjustment.getSignals() != null) {
3571 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003572 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003573 }
3574 }
3575
Julia Reynolds88860ce2017-06-01 16:55:49 -04003576 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003577 void addAutogroupKeyLocked(String key) {
3578 NotificationRecord r = mNotificationsByKey.get(key);
3579 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003580 return;
3581 }
Julia Reynolds51710712017-07-19 13:48:07 -04003582 if (r.sbn.getOverrideGroupKey() == null) {
3583 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3584 EventLogTags.writeNotificationAutogrouped(key);
3585 mRankingHandler.requestSort();
3586 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003587 }
3588
Julia Reynolds88860ce2017-06-01 16:55:49 -04003589 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003590 void removeAutogroupKeyLocked(String key) {
3591 NotificationRecord r = mNotificationsByKey.get(key);
3592 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003593 return;
3594 }
Julia Reynolds51710712017-07-19 13:48:07 -04003595 if (r.sbn.getOverrideGroupKey() != null) {
3596 addAutoGroupAdjustment(r, null);
3597 EventLogTags.writeNotificationUnautogrouped(key);
3598 mRankingHandler.requestSort();
3599 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003600 }
3601
3602 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3603 Bundle signals = new Bundle();
3604 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3605 Adjustment adjustment =
3606 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3607 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003608 }
3609
3610 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04003611 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04003612 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3613 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3614 if (summaries != null && summaries.containsKey(pkg)) {
3615 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003616 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04003617 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04003618 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003619 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003620 }
3621 }
3622 }
3623
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003624 @GuardedBy("mNotificationLock")
3625 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3626 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3627 return summaries != null && summaries.containsKey(sbn.getPackageName());
3628 }
3629
Julia Reynoldse46bb372016-03-17 11:05:58 -04003630 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04003631 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3632 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003633 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003634 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3635 if (notificationRecord == null) {
3636 // The notification could have been cancelled again already. A successive
3637 // adjustment will post a summary if needed.
3638 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003639 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003640 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3641 userId = adjustedSbn.getUser().getIdentifier();
3642 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3643 if (summaries == null) {
3644 summaries = new ArrayMap<>();
3645 }
3646 mAutobundledSummaries.put(userId, summaries);
3647 if (!summaries.containsKey(pkg)) {
3648 // Add summary
3649 final ApplicationInfo appInfo =
3650 adjustedSbn.getNotification().extras.getParcelable(
3651 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3652 final Bundle extras = new Bundle();
3653 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003654 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04003655 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003656 new Notification.Builder(getContext(), channelId)
3657 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04003658 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04003659 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04003660 .setGroup(GroupHelper.AUTOGROUP_KEY)
3661 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3662 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3663 .setColor(adjustedSbn.getNotification().color)
3664 .setLocalOnly(true)
3665 .build();
3666 summaryNotification.extras.putAll(extras);
3667 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3668 if (appIntent != null) {
3669 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3670 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3671 }
3672 final StatusBarNotification summarySbn =
3673 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003674 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003675 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04003676 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3677 adjustedSbn.getInitialPid(), summaryNotification,
3678 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3679 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05003680 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003681 notificationRecord.getChannel());
Rohan Shah590e1b22018-04-10 23:48:47 -04003682 summaryRecord.setIsAppImportanceLocked(
3683 notificationRecord.getIsAppImportanceLocked());
Julia Reynolds8f488d32016-10-14 10:59:01 -04003684 summaries.put(pkg, summarySbn.getKey());
3685 }
3686 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003687 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04003688 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003689 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04003690 }
3691 }
3692
John Spurlock32fe4c62014-10-02 12:16:02 -04003693 private String disableNotificationEffects(NotificationRecord record) {
3694 if (mDisableNotificationEffects) {
3695 return "booleanState";
3696 }
3697 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3698 return "listenerHints";
3699 }
Julia Reynolds9aee2842019-01-03 14:35:38 -05003700 if (record != null && record.getAudioAttributes() != null) {
3701 if ((mListenerHints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
3702 if (record.getAudioAttributes().getUsage()
3703 != AudioAttributes.USAGE_VOICE_COMMUNICATION) {
3704 return "listenerNoti";
3705 }
3706 }
3707 if ((mListenerHints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
3708 if (record.getAudioAttributes().getUsage()
3709 == AudioAttributes.USAGE_VOICE_COMMUNICATION) {
3710 return "listenerCall";
3711 }
3712 }
3713 }
John Spurlock32fe4c62014-10-02 12:16:02 -04003714 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3715 return "callState";
3716 }
3717 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04003718 };
3719
Kweku Adams887f09c2017-11-13 17:12:20 -08003720 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
Chris Wrene4b38802015-07-07 15:54:19 -04003721 JSONObject dump = new JSONObject();
3722 try {
3723 dump.put("service", "Notification Manager");
Chris Wrenacf424a2016-03-15 12:48:55 -04003724 dump.put("bans", mRankingHelper.dumpBansJson(filter));
3725 dump.put("ranking", mRankingHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003726 dump.put("stats", mUsageStats.dumpJson(filter));
Julia Reynoldsd373d782017-03-03 13:32:57 -05003727 dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003728 } catch (JSONException e) {
3729 e.printStackTrace();
3730 }
3731 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04003732 }
3733
Kweku Adams887f09c2017-11-13 17:12:20 -08003734 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003735 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3736 synchronized (mNotificationLock) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003737 int N = mNotificationList.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003738 for (int i = 0; i < N; i++) {
3739 final NotificationRecord nr = mNotificationList.get(i);
3740 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3741 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3742 NotificationRecordProto.POSTED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003743 }
3744 N = mEnqueuedNotifications.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003745 for (int i = 0; i < N; i++) {
3746 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3747 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3748 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3749 NotificationRecordProto.ENQUEUED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003750 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003751 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3752 N = snoozed.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003753 for (int i = 0; i < N; i++) {
3754 final NotificationRecord nr = snoozed.get(i);
3755 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3756 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3757 NotificationRecordProto.SNOOZED);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003758 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003759
Kweku Adams93304b62017-09-20 17:03:00 -07003760 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3761 mZenModeHelper.dump(proto);
3762 for (ComponentName suppressor : mEffectsSuppressors) {
Kweku Adams99546332018-01-24 17:03:50 -08003763 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
Kweku Adams93304b62017-09-20 17:03:00 -07003764 }
3765 proto.end(zenLog);
3766
3767 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
3768 mListeners.dump(proto, filter);
3769 proto.end(listenersToken);
3770
3771 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
3772
3773 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
3774 long effectsToken = proto.start(
3775 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
3776
3777 proto.write(
3778 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
3779 final ArraySet<ManagedServiceInfo> listeners =
3780 mListenersDisablingEffects.valueAt(i);
3781 for (int j = 0; j < listeners.size(); j++) {
3782 final ManagedServiceInfo listener = listeners.valueAt(i);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08003783 listener.writeToProto(proto, ListenersDisablingEffectsProto.LISTENERS, null);
Kweku Adams93304b62017-09-20 17:03:00 -07003784 }
3785
3786 proto.end(effectsToken);
3787 }
3788
3789 long assistantsToken = proto.start(
3790 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
3791 mAssistants.dump(proto, filter);
3792 proto.end(assistantsToken);
3793
3794 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
3795 mConditionProviders.dump(proto, filter);
3796 proto.end(conditionsToken);
Kweku Adams62b42242017-09-25 12:54:02 -07003797
3798 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
3799 mRankingHelper.dump(proto, filter);
3800 proto.end(rankingToken);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003801 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003802
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003803 proto.flush();
3804 }
3805
Vishnu Naire3e4d252018-03-01 11:26:57 -08003806 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
3807 synchronized (mNotificationLock) {
3808 int N;
3809 N = mNotificationList.size();
3810 if (N > 0) {
3811 pw.println(" Notification List:");
3812 for (int i = 0; i < N; i++) {
3813 final NotificationRecord nr = mNotificationList.get(i);
3814 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3815 nr.dump(pw, " ", getContext(), filter.redact);
3816 }
3817 pw.println(" ");
3818 }
3819 }
3820 }
3821
Kweku Adams887f09c2017-11-13 17:12:20 -08003822 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
John Spurlock25e2d242014-06-27 13:58:23 -04003823 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04003824 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003825 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04003826 }
3827 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08003828 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003829 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003830
John Spurlock50806fc2014-07-15 10:22:02 -04003831 if (!zenOnly) {
3832 synchronized (mToastQueue) {
3833 N = mToastQueue.size();
3834 if (N > 0) {
3835 pw.println(" Toast Queue:");
3836 for (int i=0; i<N; i++) {
3837 mToastQueue.get(i).dump(pw, " ", filter);
3838 }
3839 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003840 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003841 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003842 }
3843
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003844 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04003845 if (!zenOnly) {
Vishnu Naire3e4d252018-03-01 11:26:57 -08003846 // Priority filters are only set when called via bugreport. If set
3847 // skip sections that are part of the critical section.
3848 if (!filter.normalPriority) {
3849 dumpNotificationRecords(pw, filter);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003850 }
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003851 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003852 N = mLights.size();
3853 if (N > 0) {
3854 pw.println(" Lights List:");
3855 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05003856 if (i == N - 1) {
3857 pw.print(" > ");
3858 } else {
3859 pw.print(" ");
3860 }
3861 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04003862 }
3863 pw.println(" ");
3864 }
John Spurlockcb566aa2014-08-03 22:58:28 -04003865 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
Julia Reynolds54369232018-07-03 10:43:35 -04003866 pw.println(" mHasLight=" + mHasLight);
John Spurlockcb566aa2014-08-03 22:58:28 -04003867 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05003868 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3869 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003870 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04003871 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04003872 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04003873 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04003874 }
3875 pw.println(" mArchive=" + mArchive.toString());
3876 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003877 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04003878 while (iter.hasNext()) {
3879 final StatusBarNotification sbn = iter.next();
3880 if (filter != null && !filter.matches(sbn)) continue;
3881 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003882 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04003883 if (iter.hasNext()) pw.println(" ...");
3884 break;
3885 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003886 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003887
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003888 if (!zenOnly) {
3889 N = mEnqueuedNotifications.size();
3890 if (N > 0) {
3891 pw.println(" Enqueued Notification List:");
3892 for (int i = 0; i < N; i++) {
3893 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3894 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3895 nr.dump(pw, " ", getContext(), filter.redact);
3896 }
3897 pw.println(" ");
3898 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003899
3900 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003901 }
3902 }
3903
John Spurlock50806fc2014-07-15 10:22:02 -04003904 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04003905 pw.println("\n Ranking Config:");
3906 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04003907
John Spurlock50806fc2014-07-15 10:22:02 -04003908 pw.println("\n Notification listeners:");
3909 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003910 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3911 pw.print(" mListenersDisablingEffects: (");
3912 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04003913 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003914 final int hint = mListenersDisablingEffects.keyAt(i);
3915 if (i > 0) pw.print(';');
3916 pw.print("hint[" + hint + "]:");
3917
3918 final ArraySet<ManagedServiceInfo> listeners =
3919 mListenersDisablingEffects.valueAt(i);
3920 final int listenerSize = listeners.size();
3921
3922 for (int j = 0; j < listenerSize; j++) {
3923 if (i > 0) pw.print(',');
3924 final ManagedServiceInfo listener = listeners.valueAt(i);
Julia Reynolds1f580572018-04-27 14:48:36 -04003925 if (listener != null) {
3926 pw.print(listener.component);
3927 }
Bryce Lee7219ada2016-04-08 10:54:23 -07003928 }
John Spurlock1fa865f2014-07-21 14:56:39 -04003929 }
3930 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05003931 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003932 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04003933 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003934
Julia Reynolds520df6e2017-02-13 09:05:10 -05003935 if (!filter.filtered || zenOnly) {
3936 pw.println("\n Zen Mode:");
3937 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3938 mZenModeHelper.dump(pw, " ");
3939
3940 pw.println("\n Zen Log:");
3941 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003942 }
3943
John Spurlocke77bb362014-04-26 10:24:59 -04003944 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04003945 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02003946
3947 pw.println("\n Group summaries:");
3948 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3949 NotificationRecord r = entry.getValue();
3950 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3951 if (mNotificationsByKey.get(r.getKey()) != r) {
3952 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04003953 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02003954 }
3955 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003956
3957 if (!zenOnly) {
3958 pw.println("\n Usage Stats:");
3959 mUsageStats.dump(pw, " ", filter);
3960 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003961 }
3962 }
3963
Adam Lesinski182f73f2013-12-05 16:48:06 -08003964 /**
3965 * The private API only accessible to the system process.
3966 */
3967 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3968 @Override
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04003969 public NotificationChannel getNotificationChannel(String pkg, int uid, String
3970 channelId) {
3971 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
3972 }
3973
3974 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003975 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003976 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003977 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003978 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003979 }
Christoph Studer365e4c32014-09-18 20:35:36 +02003980
3981 @Override
3982 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3983 int userId) {
3984 checkCallerIsSystem();
Julia Reynoldsac3f14e2018-09-13 15:53:11 -04003985 mHandler.post(() -> {
3986 synchronized (mNotificationLock) {
3987 // strip flag from all enqueued notifications. listeners will be informed
3988 // in post runnable.
3989 List<NotificationRecord> enqueued = findNotificationsByListLocked(
3990 mEnqueuedNotifications, pkg, null, notificationId, userId);
3991 for (int i = 0; i < enqueued.size(); i++) {
3992 removeForegroundServiceFlagLocked(enqueued.get(i));
3993 }
3994
3995 // if posted notification exists, strip its flag and tell listeners
3996 NotificationRecord r = findNotificationByListLocked(
3997 mNotificationList, pkg, null, notificationId, userId);
3998 if (r != null) {
3999 removeForegroundServiceFlagLocked(r);
4000 mRankingHelper.sort(mNotificationList);
4001 mListeners.notifyPostedLocked(r, r);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004002 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004003 }
4004 });
4005 }
4006
Julia Reynolds88860ce2017-06-01 16:55:49 -04004007 @GuardedBy("mNotificationLock")
Julia Reynoldsac3f14e2018-09-13 15:53:11 -04004008 private void removeForegroundServiceFlagLocked(NotificationRecord r) {
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004009 if (r == null) {
4010 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02004011 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004012 StatusBarNotification sbn = r.sbn;
4013 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
4014 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
4015 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
4016 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
4017 sbn.getNotification().flags =
Julia Reynoldse5c60452018-04-30 14:41:36 -04004018 (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
Christoph Studer365e4c32014-09-18 20:35:36 +02004019 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004020 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004021
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004022 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04004023 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004024 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04004025 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08004026 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
4027 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04004028 }
John Spurlock7340fc82014-04-24 18:50:12 -04004029 checkCallerIsSystemOrSameApp(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004030
Scott Greenwald9b05c612013-06-25 23:44:05 -04004031 final int userId = ActivityManager.handleIncomingUser(callingPid,
4032 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
Jeff Sharkey65c4a2b2012-09-25 17:22:27 -07004033 final UserHandle user = new UserHandle(userId);
Dianne Hackborn41203752012-08-31 14:05:51 -07004034
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004035 if (pkg == null || notification == null) {
4036 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
4037 + " id=" + id + " notification=" + notification);
4038 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004039
4040 // The system can post notifications for any package, let us resolve that.
4041 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
4042
Julia Reynoldse46bb372016-03-17 11:05:58 -04004043 // Fix the notification as best we can.
4044 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004045 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06004046 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
Julia Reynoldse0d711f2017-09-01 08:50:47 -04004047 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
Julia Reynoldse071abd2017-03-22 10:52:11 -04004048 Notification.addFieldsFromContext(ai, notification);
Julia Reynolds4db59552017-06-30 13:34:01 -04004049
4050 int canColorize = mPackageManagerClient.checkPermission(
4051 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
4052 if (canColorize == PERMISSION_GRANTED) {
4053 notification.flags |= Notification.FLAG_CAN_COLORIZE;
4054 } else {
4055 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
4056 }
4057
Julia Reynoldse46bb372016-03-17 11:05:58 -04004058 } catch (NameNotFoundException e) {
4059 Slog.e(TAG, "Cannot create a context for sending app", e);
4060 return;
4061 }
4062
Chris Wren888b7a82016-06-17 15:47:19 -04004063 mUsageStats.registerEnqueuedByApp(pkg);
4064
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004065 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04004066 String channelId = notification.getChannelId();
4067 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
4068 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05004069 }
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004070 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004071 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004072 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004073 final String noChannelStr = "No Channel found for "
4074 + "pkg=" + pkg
4075 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04004076 + ", id=" + id
4077 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004078 + ", opPkg=" + opPkg
4079 + ", callingUid=" + callingUid
4080 + ", userId=" + userId
4081 + ", incomingUserId=" + incomingUserId
4082 + ", notificationUid=" + notificationUid
4083 + ", notification=" + notification;
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004084 Log.e(TAG, noChannelStr);
Beverly5d4564b2018-04-10 20:09:23 -04004085 boolean appNotificationsOff = mRankingHelper.getImportance(pkg, notificationUid)
4086 == NotificationManager.IMPORTANCE_NONE;
4087
4088 if (!appNotificationsOff) {
4089 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
4090 "Failed to post notification on channel \"" + channelId + "\"\n" +
4091 "See log for more details");
4092 }
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004093 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004094 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004095
Chris Wrena61f1792016-08-04 11:24:42 -04004096 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004097 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004098 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004099 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Rohan Shah590e1b22018-04-10 23:48:47 -04004100 r.setIsAppImportanceLocked(mRankingHelper.getIsAppImportanceLocked(pkg, callingUid));
Chris Wrena61f1792016-08-04 11:24:42 -04004101
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004102 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4103 final boolean fgServiceShown = channel.isFgServiceShown();
4104 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
4105 || !fgServiceShown)
4106 && (r.getImportance() == IMPORTANCE_MIN
4107 || r.getImportance() == IMPORTANCE_NONE)) {
4108 // Increase the importance of foreground service notifications unless the user had
4109 // an opinion otherwise (and the channel hasn't yet shown a fg service).
4110 if (TextUtils.isEmpty(channelId)
4111 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4112 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
4113 } else {
4114 channel.setImportance(IMPORTANCE_LOW);
4115 if (!fgServiceShown) {
4116 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
4117 channel.setFgServiceShown(true);
4118 }
4119 mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
4120 r.updateNotificationChannel(channel);
4121 }
4122 } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
4123 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4124 channel.setFgServiceShown(true);
Julia Reynolds8617e4e2017-09-18 16:52:37 -04004125 r.updateNotificationChannel(channel);
4126 }
4127 }
4128
Julia Reynolds5e702192017-08-18 09:22:40 -04004129 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
4130 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004131 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07004132 }
4133
Felipe Lemedd85da62016-06-28 11:29:54 -07004134 // Whitelist pending intents.
4135 if (notification.allPendingIntents != null) {
4136 final int intentCount = notification.allPendingIntents.size();
4137 if (intentCount > 0) {
4138 final ActivityManagerInternal am = LocalServices
4139 .getService(ActivityManagerInternal.class);
4140 final long duration = LocalServices.getService(
4141 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
4142 for (int i = 0; i < intentCount; i++) {
4143 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4144 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07004145 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4146 WHITELIST_TOKEN, duration);
Felipe Lemedd85da62016-06-28 11:29:54 -07004147 }
4148 }
4149 }
4150 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07004151
Chris Wren47633422016-01-22 09:56:59 -05004152 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004153 }
4154
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04004155 private void doChannelWarningToast(CharSequence toastText) {
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04004156 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04004157 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04004158 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4159 if (warningEnabled) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04004160 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
Geoffrey Pitsch5bdddbd2017-05-26 10:50:05 -04004161 Toast.LENGTH_SHORT);
Geoffrey Pitschd34c1872017-05-04 16:02:15 -04004162 toast.show();
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004163 }
4164 }
4165
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004166 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
4167 // The system can post notifications on behalf of any package it wants
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004168 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004169 try {
4170 return getContext().getPackageManager()
4171 .getPackageUidAsUser(opPackageName, userId);
4172 } catch (NameNotFoundException e) {
4173 /* ignore */
4174 }
4175 }
4176 return callingUid;
4177 }
4178
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004179 /**
4180 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4181 *
4182 * Has side effects.
4183 */
4184 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04004185 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004186 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004187 final boolean isSystemNotification =
4188 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004189 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
4190
4191 // Limit the number of notifications that any given package except the android
4192 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
4193 if (!isSystemNotification && !isNotificationFromListener) {
4194 synchronized (mNotificationLock) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004195 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
4196 // Ephemeral apps have some special constraints for notifications.
4197 // They are not allowed to create new notifications however they are allowed to
4198 // update notifications created by the system (e.g. a foreground service
4199 // notification).
4200 throw new SecurityException("Instant app " + pkg
4201 + " cannot create notifications");
4202 }
4203
4204 // rate limit updates that aren't completed progress notifications
4205 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04004206 && !r.getNotification().hasCompletedProgress()
4207 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004208
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004209 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
4210 if (appEnqueueRate > mMaxPackageEnqueueRate) {
4211 mUsageStats.registerOverRateQuota(pkg);
4212 final long now = SystemClock.elapsedRealtime();
4213 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
4214 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04004215 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004216 mLastOverRateLogTime = now;
4217 }
4218 return false;
4219 }
4220 }
4221
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004222 // limit the number of outstanding notificationrecords an app can have
4223 int count = getNotificationCountLocked(pkg, userId, id, tag);
4224 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
4225 mUsageStats.registerOverCountQuota(pkg);
4226 Slog.e(TAG, "Package has already posted or enqueued " + count
4227 + " notifications. Not showing more. package=" + pkg);
4228 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004229 }
4230 }
4231 }
4232
4233 // snoozed apps
4234 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05004235 MetricsLogger.action(r.getLogMaker()
4236 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
4237 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004238 if (DBG) {
4239 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
4240 }
4241 mSnoozeHelper.update(userId, r);
4242 savePolicyFile();
4243 return false;
4244 }
4245
4246
4247 // blocked apps
4248 if (isBlocked(r, mUsageStats)) {
4249 return false;
4250 }
4251
4252 return true;
4253 }
4254
Andreas Gampea36dc622018-02-05 17:19:22 -08004255 @GuardedBy("mNotificationLock")
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004256 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
4257 String excludedTag) {
4258 int count = 0;
4259 final int N = mNotificationList.size();
4260 for (int i = 0; i < N; i++) {
4261 final NotificationRecord existing = mNotificationList.get(i);
4262 if (existing.sbn.getPackageName().equals(pkg)
4263 && existing.sbn.getUserId() == userId) {
4264 if (existing.sbn.getId() == excludedId
4265 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
4266 continue;
4267 }
4268 count++;
4269 }
4270 }
4271 final int M = mEnqueuedNotifications.size();
4272 for (int i = 0; i < M; i++) {
4273 final NotificationRecord existing = mEnqueuedNotifications.get(i);
4274 if (existing.sbn.getPackageName().equals(pkg)
4275 && existing.sbn.getUserId() == userId) {
4276 count++;
4277 }
4278 }
4279 return count;
4280 }
4281
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004282 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
4283 final String pkg = r.sbn.getPackageName();
4284 final int callingUid = r.sbn.getUid();
4285
Julia Reynolds4da79702017-06-01 11:06:10 -04004286 final boolean isBlocked =
Julia Reynolds005c8b92017-08-24 10:35:53 -04004287 mRankingHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
4288 || mRankingHelper.getImportance(pkg, callingUid)
4289 == NotificationManager.IMPORTANCE_NONE
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04004290 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004291 if (isBlocked) {
4292 Slog.e(TAG, "Suppressing notification from package by user request.");
4293 usageStats.registerBlocked(r);
Beverlyc7858552018-09-14 09:49:07 -04004294 return true;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004295 }
Beverlyc7858552018-09-14 09:49:07 -04004296 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004297 }
4298
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004299 protected class SnoozeNotificationRunnable implements Runnable {
4300 private final String mKey;
4301 private final long mDuration;
4302 private final String mSnoozeCriterionId;
4303
4304 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
4305 mKey = key;
4306 mDuration = duration;
4307 mSnoozeCriterionId = snoozeCriterionId;
4308 }
4309
4310 @Override
4311 public void run() {
4312 synchronized (mNotificationLock) {
4313 final NotificationRecord r = findNotificationByKeyLocked(mKey);
4314 if (r != null) {
4315 snoozeLocked(r);
4316 }
4317 }
4318 }
4319
Julia Reynolds88860ce2017-06-01 16:55:49 -04004320 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004321 void snoozeLocked(NotificationRecord r) {
4322 if (r.sbn.isGroup()) {
4323 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
4324 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
4325 if (r.getNotification().isGroupSummary()) {
4326 // snooze summary and all children
4327 for (int i = 0; i < groupNotifications.size(); i++) {
4328 snoozeNotificationLocked(groupNotifications.get(i));
4329 }
4330 } else {
4331 // if there is a valid summary for this group, and we are snoozing the only
4332 // child, also snooze the summary
4333 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
4334 if (groupNotifications.size() != 2) {
4335 snoozeNotificationLocked(r);
4336 } else {
4337 // snooze summary and the one child
4338 for (int i = 0; i < groupNotifications.size(); i++) {
4339 snoozeNotificationLocked(groupNotifications.get(i));
4340 }
4341 }
4342 } else {
4343 snoozeNotificationLocked(r);
4344 }
4345 }
4346 } else {
4347 // just snooze the one notification
4348 snoozeNotificationLocked(r);
4349 }
4350 }
4351
Julia Reynolds88860ce2017-06-01 16:55:49 -04004352 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004353 void snoozeNotificationLocked(NotificationRecord r) {
4354 MetricsLogger.action(r.getLogMaker()
4355 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4356 .setType(MetricsEvent.TYPE_CLOSE)
Chris Wren21a2e722017-10-02 17:44:53 -04004357 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
4358 mDuration)
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004359 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4360 mSnoozeCriterionId == null ? 0 : 1));
Julia Reynolds0839c022017-06-15 15:24:01 -04004361 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004362 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004363 updateLightsLocked();
4364 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004365 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004366 mSnoozeHelper.snooze(r);
4367 } else {
4368 mSnoozeHelper.snooze(r, mDuration);
4369 }
Julia Reynolds503ed942017-10-04 16:04:56 -04004370 r.recordSnoozed();
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004371 savePolicyFile();
4372 }
4373 }
4374
Julia Reynoldsbaff4002016-12-15 11:34:26 -05004375 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05004376 private final NotificationRecord r;
4377 private final int userId;
4378
4379 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
4380 this.userId = userId;
4381 this.r = r;
4382 };
4383
4384 @Override
4385 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004386 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05004387 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05004388 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05004389
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004390 final StatusBarNotification n = r.sbn;
4391 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
4392 NotificationRecord old = mNotificationsByKey.get(n.getKey());
4393 if (old != null) {
4394 // Retain ranking information from previous record
4395 r.copyRankingInformation(old);
4396 }
4397
4398 final int callingUid = n.getUid();
4399 final int callingPid = n.getInitialPid();
4400 final Notification notification = n.getNotification();
4401 final String pkg = n.getPackageName();
4402 final int id = n.getId();
4403 final String tag = n.getTag();
4404
4405 // Handle grouped notifications and bail out early if we
4406 // can to avoid extracting signals.
4407 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
4408
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004409 // if this is a group child, unsnooze parent summary
4410 if (n.isGroup() && notification.isGroupChild()) {
4411 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
4412 }
4413
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004414 // This conditional is a dirty hack to limit the logging done on
4415 // behalf of the download manager without affecting other apps.
4416 if (!pkg.equals("com.android.providers.downloads")
4417 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
4418 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05004419 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004420 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05004421 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004422 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
4423 pkg, id, tag, userId, notification.toString(),
4424 enqueueStatus);
4425 }
Chris Wren6676dab2016-12-21 18:26:27 -05004426
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004427 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05004428
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004429 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004430 if (mAssistants.isEnabled()) {
4431 mAssistants.onNotificationEnqueued(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004432 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004433 DELAY_FOR_ASSISTANT_TIME);
4434 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004435 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004436 }
4437 }
4438 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004439 }
4440
Beverly5a20a5e2018-03-06 15:02:44 -05004441 @GuardedBy("mNotificationLock")
4442 private boolean isPackageSuspendedLocked(NotificationRecord r) {
4443 final String pkg = r.sbn.getPackageName();
4444 final int callingUid = r.sbn.getUid();
4445
4446 return isPackageSuspendedForUser(pkg, callingUid);
4447 }
4448
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004449 protected class PostNotificationRunnable implements Runnable {
4450 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004451
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004452 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004453 this.key = key;
4454 }
4455
4456 @Override
4457 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004458 synchronized (mNotificationLock) {
4459 try {
4460 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004461 int N = mEnqueuedNotifications.size();
4462 for (int i = 0; i < N; i++) {
4463 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4464 if (Objects.equals(key, enqueued.getKey())) {
4465 r = enqueued;
4466 break;
Chris Wren6676dab2016-12-21 18:26:27 -05004467 }
Chris Wren6676dab2016-12-21 18:26:27 -05004468 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004469 if (r == null) {
4470 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
4471 return;
4472 }
Beverly5a20a5e2018-03-06 15:02:44 -05004473
Beverlyc7858552018-09-14 09:49:07 -04004474 final boolean isPackageSuspended = isPackageSuspendedLocked(r);
4475 r.setHidden(isPackageSuspended);
4476 if (isPackageSuspended) {
4477 mUsageStats.registerSuspendedByAdmin(r);
4478 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004479 NotificationRecord old = mNotificationsByKey.get(key);
4480 final StatusBarNotification n = r.sbn;
4481 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05004482 int index = indexOfNotificationLocked(n.getKey());
4483 if (index < 0) {
4484 mNotificationList.add(r);
4485 mUsageStats.registerPostedByApp(r);
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004486 r.setInterruptive(isVisuallyInterruptive(null, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004487 } else {
4488 old = mNotificationList.get(index);
4489 mNotificationList.set(index, r);
4490 mUsageStats.registerUpdatedByApp(r, old);
4491 // Make sure we don't lose the foreground service state.
4492 notification.flags |=
Julia Reynoldse5c60452018-04-30 14:41:36 -04004493 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
Chris Wren6676dab2016-12-21 18:26:27 -05004494 r.isUpdate = true;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04004495 r.setTextChanged(isVisuallyInterruptive(old, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004496 }
4497
4498 mNotificationsByKey.put(n.getKey(), r);
4499
4500 // Ensure if this is a foreground service that the proper additional
4501 // flags are set.
Julia Reynoldse5c60452018-04-30 14:41:36 -04004502 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
Chris Wren6676dab2016-12-21 18:26:27 -05004503 notification.flags |= Notification.FLAG_ONGOING_EVENT
4504 | Notification.FLAG_NO_CLEAR;
4505 }
4506
4507 applyZenModeLocked(r);
4508 mRankingHelper.sort(mNotificationList);
4509
4510 if (notification.getSmallIcon() != null) {
4511 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06004512 mListeners.notifyPostedLocked(r, old);
Julia Reynolds8aebf352017-06-26 11:35:33 -04004513 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
4514 mHandler.post(new Runnable() {
4515 @Override
4516 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04004517 mGroupHelper.onNotificationPosted(
4518 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04004519 }
4520 });
4521 }
Chris Wren6676dab2016-12-21 18:26:27 -05004522 } else {
4523 Slog.e(TAG, "Not posting notification without small icon: " + notification);
4524 if (old != null && !old.isCanceled) {
Beverly5a20a5e2018-03-06 15:02:44 -05004525 mListeners.notifyRemovedLocked(r,
Julia Reynolds503ed942017-10-04 16:04:56 -04004526 NotificationListenerService.REASON_ERROR, null);
Chris Wren6676dab2016-12-21 18:26:27 -05004527 mHandler.post(new Runnable() {
4528 @Override
4529 public void run() {
4530 mGroupHelper.onNotificationRemoved(n);
4531 }
4532 });
4533 }
4534 // ATTENTION: in a future release we will bail out here
4535 // so that we do not play sounds, show lights, etc. for invalid
4536 // notifications
4537 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
4538 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05004539 }
Chris Wren47633422016-01-22 09:56:59 -05004540
Beverly5a20a5e2018-03-06 15:02:44 -05004541 if (!r.isHidden()) {
4542 buzzBeepBlinkLocked(r);
4543 }
Julia Reynolds1fac86e2018-03-07 08:30:37 -05004544 maybeRecordInterruptionLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004545 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004546 int N = mEnqueuedNotifications.size();
4547 for (int i = 0; i < N; i++) {
4548 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4549 if (Objects.equals(key, enqueued.getKey())) {
4550 mEnqueuedNotifications.remove(i);
4551 break;
4552 }
4553 }
Chris Wren6676dab2016-12-21 18:26:27 -05004554 }
Chris Wren47633422016-01-22 09:56:59 -05004555 }
4556 }
4557 }
4558
Christoph Studer265c1052014-07-23 17:14:33 +02004559 /**
Julia Reynolds7217dc92018-03-07 12:12:09 -05004560 * If the notification differs enough visually, consider it a new interruptive notification.
4561 */
4562 @GuardedBy("mNotificationLock")
4563 @VisibleForTesting
4564 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
Julia Reynolds6b302d02018-06-19 15:39:23 -04004565 // Ignore summary updates because we don't display most of the information.
4566 if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
4567 if (DEBUG_INTERRUPTIVENESS) {
4568 Log.v(TAG, "INTERRUPTIVENESS: "
4569 + r.getKey() + " is not interruptive: summary");
4570 }
4571 return false;
4572 }
4573
Dan Sandler7d67bd42018-05-15 14:06:38 -04004574 if (old == null) {
4575 if (DEBUG_INTERRUPTIVENESS) {
4576 Log.v(TAG, "INTERRUPTIVENESS: "
4577 + r.getKey() + " is interruptive: new notification");
4578 }
4579 return true;
4580 }
4581
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004582 if (r == null) {
4583 if (DEBUG_INTERRUPTIVENESS) {
4584 Log.v(TAG, "INTERRUPTIVENESS: "
4585 + r.getKey() + " is not interruptive: null");
4586 }
4587 return false;
4588 }
4589
Julia Reynolds7217dc92018-03-07 12:12:09 -05004590 Notification oldN = old.sbn.getNotification();
4591 Notification newN = r.sbn.getNotification();
Dan Sandler7d67bd42018-05-15 14:06:38 -04004592
Julia Reynolds7217dc92018-03-07 12:12:09 -05004593 if (oldN.extras == null || newN.extras == null) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004594 if (DEBUG_INTERRUPTIVENESS) {
4595 Log.v(TAG, "INTERRUPTIVENESS: "
4596 + r.getKey() + " is not interruptive: no extras");
4597 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004598 return false;
4599 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004600
4601 // Ignore visual interruptions from foreground services because users
4602 // consider them one 'session'. Count them for everything else.
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004603 if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004604 if (DEBUG_INTERRUPTIVENESS) {
4605 Log.v(TAG, "INTERRUPTIVENESS: "
4606 + r.getKey() + " is not interruptive: foreground service");
4607 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004608 return false;
4609 }
4610
Dan Sandler7d67bd42018-05-15 14:06:38 -04004611 final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
4612 final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
4613 if (!Objects.equals(oldTitle, newTitle)) {
4614 if (DEBUG_INTERRUPTIVENESS) {
4615 Log.v(TAG, "INTERRUPTIVENESS: "
4616 + r.getKey() + " is interruptive: changed title");
4617 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)",
4618 oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
4619 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)",
4620 newTitle, newTitle.getClass(), newTitle.hashCode()));
4621 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004622 return true;
4623 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004624 // Do not compare Spannables (will always return false); compare unstyled Strings
4625 final String oldText = String.valueOf(oldN.extras.get(Notification.EXTRA_TEXT));
4626 final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT));
4627 if (!Objects.equals(oldText, newText)) {
4628 if (DEBUG_INTERRUPTIVENESS) {
4629 Log.v(TAG, "INTERRUPTIVENESS: "
4630 + r.getKey() + " is interruptive: changed text");
4631 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)",
4632 oldText, oldText.getClass(), oldText.hashCode()));
4633 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)",
4634 newText, newText.getClass(), newText.hashCode()));
4635 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004636 return true;
4637 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004638 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
4639 if (DEBUG_INTERRUPTIVENESS) {
4640 Log.v(TAG, "INTERRUPTIVENESS: "
4641 + r.getKey() + " is interruptive: completed progress");
4642 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004643 return true;
4644 }
4645 // Actions
4646 if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004647 if (DEBUG_INTERRUPTIVENESS) {
4648 Log.v(TAG, "INTERRUPTIVENESS: "
4649 + r.getKey() + " is interruptive: changed actions");
4650 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004651 return true;
4652 }
4653
4654 try {
4655 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
4656 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
4657
4658 // Style based comparisons
4659 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004660 if (DEBUG_INTERRUPTIVENESS) {
4661 Log.v(TAG, "INTERRUPTIVENESS: "
4662 + r.getKey() + " is interruptive: styles differ");
4663 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004664 return true;
4665 }
4666
4667 // Remote views
4668 if (Notification.areRemoteViewsChanged(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004669 if (DEBUG_INTERRUPTIVENESS) {
4670 Log.v(TAG, "INTERRUPTIVENESS: "
4671 + r.getKey() + " is interruptive: remoteviews differ");
4672 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004673 return true;
4674 }
4675 } catch (Exception e) {
4676 Slog.w(TAG, "error recovering builder", e);
4677 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004678
Julia Reynolds7217dc92018-03-07 12:12:09 -05004679 return false;
4680 }
4681
4682 /**
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05004683 * Keeps the last 5 packages that have notified, by user.
4684 */
4685 @GuardedBy("mNotificationLock")
4686 @VisibleForTesting
4687 protected void logRecentLocked(NotificationRecord r) {
4688 if (r.isUpdate) {
4689 return;
4690 }
4691 ArrayList<NotifyingApp> recentAppsForUser =
4692 mRecentApps.getOrDefault(r.getUser().getIdentifier(), new ArrayList<>(6));
4693 NotifyingApp na = new NotifyingApp()
4694 .setPackage(r.sbn.getPackageName())
4695 .setUid(r.sbn.getUid())
4696 .setLastNotified(r.sbn.getPostTime());
4697 // A new notification gets an app moved to the front of the list
4698 for (int i = recentAppsForUser.size() - 1; i >= 0; i--) {
4699 NotifyingApp naExisting = recentAppsForUser.get(i);
4700 if (na.getPackage().equals(naExisting.getPackage())
4701 && na.getUid() == naExisting.getUid()) {
4702 recentAppsForUser.remove(i);
4703 break;
4704 }
4705 }
4706 // time is always increasing, so always add to the front of the list
4707 recentAppsForUser.add(0, na);
4708 if (recentAppsForUser.size() > 5) {
4709 recentAppsForUser.remove(recentAppsForUser.size() -1);
4710 }
4711 mRecentApps.put(r.getUser().getIdentifier(), recentAppsForUser);
4712 }
4713
4714 /**
Christoph Studer265c1052014-07-23 17:14:33 +02004715 * Ensures that grouped notification receive their special treatment.
4716 *
4717 * <p>Cancels group children if the new notification causes a group to lose
4718 * its summary.</p>
4719 *
4720 * <p>Updates mSummaryByGroupKey.</p>
4721 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004722 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02004723 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
4724 int callingUid, int callingPid) {
4725 StatusBarNotification sbn = r.sbn;
4726 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07004727 if (n.isGroupSummary() && !sbn.isAppGroup()) {
4728 // notifications without a group shouldn't be a summary, otherwise autobundling can
4729 // lead to bugs
4730 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
4731 }
4732
Christoph Studer265c1052014-07-23 17:14:33 +02004733 String group = sbn.getGroupKey();
4734 boolean isSummary = n.isGroupSummary();
4735
4736 Notification oldN = old != null ? old.sbn.getNotification() : null;
4737 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
4738 boolean oldIsSummary = old != null && oldN.isGroupSummary();
4739
4740 if (oldIsSummary) {
4741 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
4742 if (removedSummary != old) {
4743 String removedKey =
4744 removedSummary != null ? removedSummary.getKey() : "<null>";
4745 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
4746 ", removed=" + removedKey);
4747 }
4748 }
4749 if (isSummary) {
4750 mSummaryByGroupKey.put(group, r);
4751 }
4752
4753 // Clear out group children of the old notification if the update
4754 // causes the group summary to go away. This happens when the old
4755 // notification was a summary and the new one isn't, or when the old
4756 // notification was a summary and its group key changed.
4757 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04004758 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
4759 null);
Christoph Studer265c1052014-07-23 17:14:33 +02004760 }
4761 }
4762
Chris Wren93bb8b82016-03-29 14:35:05 -04004763 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004764 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05004765 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04004766 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05004767 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4768 REQUEST_CODE_TIMEOUT,
4769 new Intent(ACTION_NOTIFICATION_TIMEOUT)
4770 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4771 .appendPath(record.getKey()).build())
4772 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4773 .putExtra(EXTRA_KEY, record.getKey()),
4774 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05004775 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04004776 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05004777 }
4778 }
4779
4780 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004781 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04004782 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04004783 boolean buzz = false;
4784 boolean beep = false;
4785 boolean blink = false;
4786
Chris Wrena3446562014-06-03 18:11:47 -04004787 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04004788 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04004789
4790 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04004791 final boolean aboveThreshold =
4792 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04004793
4794 // Remember if this notification already owns the notification channels.
4795 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4796 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04004797 // These are set inside the conditional if the notification is allowed to make noise.
4798 boolean hasValidVibrate = false;
4799 boolean hasValidSound = false;
Julia Reynolds94187562017-10-10 13:58:49 -04004800 boolean sentAccessibilityEvent = false;
4801 // If the notification will appear in the status bar, it should send an accessibility
4802 // event
4803 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4804 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4805 sentAccessibilityEvent = true;
4806 }
Chris Wrena3446562014-06-03 18:11:47 -04004807
Julia Reynolds76c096d2017-06-19 08:16:04 -04004808 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004809
Julia Reynolds76c096d2017-06-19 08:16:04 -04004810 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004811 Uri soundUri = record.getSound();
4812 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4813 long[] vibration = record.getVibration();
4814 // Demote sound to vibration if vibration missing & phone in vibration mode.
4815 if (vibration == null
4816 && hasValidSound
4817 && (mAudioManager.getRingerModeInternal()
Julia Reynolds85896572017-09-20 12:54:52 -04004818 == AudioManager.RINGER_MODE_VIBRATE)
4819 && mAudioManager.getStreamVolume(
4820 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004821 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04004822 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004823 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01004824
Julia Reynolds76c096d2017-06-19 08:16:04 -04004825 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
Julia Reynolds76c096d2017-06-19 08:16:04 -04004826 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004827 if (!sentAccessibilityEvent) {
4828 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4829 sentAccessibilityEvent = true;
4830 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004831 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04004832 if (hasValidSound) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004833 if (mInCall) {
4834 playInCallNotification();
4835 beep = true;
4836 } else {
4837 beep = playSound(record, soundUri);
4838 }
Seungho Lee2ca1aec2018-12-09 19:27:36 +09004839 if(beep) {
4840 mSoundNotificationKey = key;
4841 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004842 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004843
Julia Reynolds7c96b582017-05-25 12:35:36 -04004844 final boolean ringerModeSilent =
4845 mAudioManager.getRingerModeInternal()
4846 == AudioManager.RINGER_MODE_SILENT;
4847 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004848 buzz = playVibration(record, vibration, hasValidSound);
Seungho Lee2ca1aec2018-12-09 19:27:36 +09004849 if(buzz) {
4850 mVibrateNotificationKey = key;
4851 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004852 }
Chris Wrena3446562014-06-03 18:11:47 -04004853 }
4854 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004855 }
4856 // If a notification is updated to remove the actively playing sound or vibrate,
4857 // cancel that feedback now
4858 if (wasBeep && !hasValidSound) {
4859 clearSoundLocked();
4860 }
4861 if (wasBuzz && !hasValidVibrate) {
4862 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04004863 }
4864
4865 // light
4866 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04004867 boolean wasShowLights = mLights.remove(key);
Julia Reynolds54369232018-07-03 10:43:35 -04004868 if (canShowLightsLocked(record, aboveThreshold)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04004869 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04004870 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04004871 if (mUseAttentionLight) {
4872 mAttentionLight.pulse();
4873 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004874 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04004875 } else if (wasShowLights) {
4876 updateLightsLocked();
4877 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004878 if (buzz || beep || blink) {
Julia Reynolds54369232018-07-03 10:43:35 -04004879 // Ignore summary updates because we don't display most of the information.
4880 if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) {
4881 if (DEBUG_INTERRUPTIVENESS) {
4882 Log.v(TAG, "INTERRUPTIVENESS: "
4883 + record.getKey() + " is not interruptive: summary");
4884 }
4885 } else {
4886 if (DEBUG_INTERRUPTIVENESS) {
4887 Log.v(TAG, "INTERRUPTIVENESS: "
4888 + record.getKey() + " is interruptive: alerted");
4889 }
4890 record.setInterruptive(true);
4891 }
Julia Reynolds445cfa82017-05-08 15:41:45 -04004892 MetricsLogger.action(record.getLogMaker()
4893 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4894 .setType(MetricsEvent.TYPE_OPEN)
4895 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4896 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04004897 }
Chris Wrena3446562014-06-03 18:11:47 -04004898 }
4899
Julia Reynolds88860ce2017-06-01 16:55:49 -04004900 @GuardedBy("mNotificationLock")
Julia Reynolds54369232018-07-03 10:43:35 -04004901 boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
4902 // device lacks light
4903 if (!mHasLight) {
4904 return false;
4905 }
4906 // user turned lights off globally
4907 if (!mNotificationPulseEnabled) {
4908 return false;
4909 }
4910 // the notification/channel has no light
4911 if (record.getLight() == null) {
4912 return false;
4913 }
4914 // unimportant notification
4915 if (!aboveThreshold) {
4916 return false;
4917 }
4918 // suppressed due to DND
4919 if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
4920 return false;
4921 }
4922 // Suppressed because it's a silent update
4923 final Notification notification = record.getNotification();
4924 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4925 return false;
4926 }
4927 // Suppressed because another notification in its group handles alerting
4928 if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
4929 return false;
4930 }
4931 // not if in call or the screen's on
4932 if (mInCall || mScreenOn) {
4933 return false;
4934 }
4935
4936 return true;
4937 }
4938
4939 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004940 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04004941 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004942 final Notification notification = record.getNotification();
Julia Reynolds54369232018-07-03 10:43:35 -04004943 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004944 return true;
4945 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004946
Julia Reynolds76c096d2017-06-19 08:16:04 -04004947 // muted by listener
4948 final String disableEffects = disableNotificationEffects(record);
4949 if (disableEffects != null) {
4950 ZenLog.traceDisableEffects(record, disableEffects);
4951 return true;
4952 }
4953
4954 // suppressed due to DND
4955 if (record.isIntercepted()) {
4956 return true;
4957 }
4958
4959 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004960 if (record.sbn.isGroup()) {
Julia Reynolds79dfdd62018-04-17 15:36:33 -04004961 if (notification.suppressAlertingDueToGrouping()) {
4962 return true;
4963 }
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004964 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004965
Julia Reynolds65b85cf2017-07-20 09:19:20 -04004966 // Suppressed for being too recently noisy
4967 final String pkg = record.sbn.getPackageName();
4968 if (mUsageStats.isAlertRateLimited(pkg)) {
4969 Slog.e(TAG, "Muting recently noisy " + record.getKey());
4970 return true;
4971 }
4972
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004973 return false;
4974 }
4975
Julia Reynolds0c299d42016-11-15 14:37:04 -05004976 private boolean playSound(final NotificationRecord record, Uri soundUri) {
4977 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
Jean-Michel Triviec2bb182018-03-23 18:04:00 -07004978 // play notifications if there is no user of exclusive audio focus
4979 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
4980 // VIBRATE ringer mode)
4981 if (!mAudioManager.isAudioFocusExclusive()
4982 && (mAudioManager.getStreamVolume(
4983 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05004984 final long identity = Binder.clearCallingIdentity();
4985 try {
4986 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4987 if (player != null) {
4988 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4989 + " with attributes " + record.getAudioAttributes());
4990 player.playAsync(soundUri, record.sbn.getUser(), looping,
4991 record.getAudioAttributes());
4992 return true;
4993 }
4994 } catch (RemoteException e) {
4995 } finally {
4996 Binder.restoreCallingIdentity(identity);
4997 }
4998 }
4999 return false;
5000 }
5001
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005002 private boolean playVibration(final NotificationRecord record, long[] vibration,
5003 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005004 // Escalate privileges so we can use the vibrator even if the
5005 // notifying app does not have the VIBRATE permission.
5006 long identity = Binder.clearCallingIdentity();
5007 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005008 final VibrationEffect effect;
5009 try {
5010 final boolean insistent =
5011 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
5012 effect = VibrationEffect.createWaveform(
5013 vibration, insistent ? 0 : -1 /*repeatIndex*/);
5014 } catch (IllegalArgumentException e) {
5015 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
5016 Arrays.toString(vibration));
5017 return false;
5018 }
5019 if (delayVibForSound) {
5020 new Thread(() -> {
5021 // delay the vibration by the same amount as the notification sound
5022 final int waitMs = mAudioManager.getFocusRampTimeMs(
5023 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
5024 record.getAudioAttributes());
5025 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
5026 try {
5027 Thread.sleep(waitMs);
5028 } catch (InterruptedException e) { }
Seungho Lee0e97ae62018-10-31 21:49:09 +09005029
5030 // Notifications might be canceled before it actually vibrates due to waitMs,
5031 // so need to check the notification still valide for vibrate.
5032 synchronized (mNotificationLock) {
5033 if (mNotificationsByKey.get(record.getKey()) != null) {
5034 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
5035 effect, record.getAudioAttributes());
5036 } else {
5037 Slog.e(TAG, "No vibration for canceled notification : " + record.getKey());
5038 }
5039 }
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005040 }).start();
5041 } else {
5042 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
5043 effect, record.getAudioAttributes());
5044 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005045 return true;
5046 } finally{
5047 Binder.restoreCallingIdentity(identity);
5048 }
5049 }
5050
Julia Reynolds7c96b582017-05-25 12:35:36 -04005051 private boolean isNotificationForCurrentUser(NotificationRecord record) {
5052 final int currentUser;
5053 final long token = Binder.clearCallingIdentity();
5054 try {
5055 currentUser = ActivityManager.getCurrentUser();
5056 } finally {
5057 Binder.restoreCallingIdentity(token);
5058 }
5059 return (record.getUserId() == UserHandle.USER_ALL ||
5060 record.getUserId() == currentUser ||
5061 mUserProfiles.isCurrentProfile(record.getUserId()));
5062 }
5063
Beverly5d463b62017-07-26 14:13:40 -04005064 protected void playInCallNotification() {
Marta Białka39c992f2011-03-10 10:27:24 +01005065 new Thread() {
5066 @Override
5067 public void run() {
Beverly5d463b62017-07-26 14:13:40 -04005068 final long identity = Binder.clearCallingIdentity();
Marta Białka39c992f2011-03-10 10:27:24 +01005069 try {
Beverly5d463b62017-07-26 14:13:40 -04005070 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5071 if (player != null) {
luochaojiang50e5273c2018-04-16 16:55:03 +08005072 if (mCallNotificationToken != null) {
5073 player.stop(mCallNotificationToken);
5074 }
5075 mCallNotificationToken = new Binder();
5076 player.play(mCallNotificationToken, mInCallNotificationUri,
Beverly5d463b62017-07-26 14:13:40 -04005077 mInCallNotificationAudioAttributes,
5078 mInCallNotificationVolume, false);
Marta Białka39c992f2011-03-10 10:27:24 +01005079 }
Beverly5d463b62017-07-26 14:13:40 -04005080 } catch (RemoteException e) {
5081 } finally {
5082 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01005083 }
5084 }
5085 }.start();
5086 }
5087
Julia Reynolds88860ce2017-06-01 16:55:49 -04005088 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005089 void showNextToastLocked() {
5090 ToastRecord record = mToastQueue.get(0);
5091 while (record != null) {
5092 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
5093 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005094 record.callback.show(record.token);
Robert Carr997427342018-02-28 18:06:10 -08005095 scheduleDurationReachedLocked(record);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005096 return;
5097 } catch (RemoteException e) {
5098 Slog.w(TAG, "Object died trying to show notification " + record.callback
5099 + " in package " + record.pkg);
5100 // remove it from the list and let the process die
5101 int index = mToastQueue.indexOf(record);
5102 if (index >= 0) {
5103 mToastQueue.remove(index);
5104 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005105 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005106 if (mToastQueue.size() > 0) {
5107 record = mToastQueue.get(0);
5108 } else {
5109 record = null;
5110 }
5111 }
5112 }
5113 }
5114
Julia Reynolds88860ce2017-06-01 16:55:49 -04005115 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005116 void cancelToastLocked(int index) {
5117 ToastRecord record = mToastQueue.get(index);
5118 try {
5119 record.callback.hide();
5120 } catch (RemoteException e) {
5121 Slog.w(TAG, "Object died trying to hide notification " + record.callback
5122 + " in package " + record.pkg);
5123 // don't worry about this, we're about to remove it from
5124 // the list anyway
5125 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005126
5127 ToastRecord lastToast = mToastQueue.remove(index);
Robert Carr997427342018-02-28 18:06:10 -08005128
5129 mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
5130 DEFAULT_DISPLAY);
5131 // We passed 'false' for 'removeWindows' so that the client has time to stop
5132 // rendering (as hide above is a one-way message), otherwise we could crash
5133 // a client which was actively using a surface made from the token. However
5134 // we need to schedule a timeout to make sure the token is eventually killed
5135 // one way or another.
5136 scheduleKillTokenTimeout(lastToast.token);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005137
5138 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005139 if (mToastQueue.size() > 0) {
5140 // Show the next one. If the callback fails, this will remove
5141 // it from the list, so don't assume that the list hasn't changed
5142 // after this point.
5143 showNextToastLocked();
5144 }
5145 }
5146
Robert Carr997427342018-02-28 18:06:10 -08005147 void finishTokenLocked(IBinder t) {
5148 mHandler.removeCallbacksAndMessages(t);
5149 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
5150 // remaining surfaces as either the client has called finishToken indicating
5151 // it has successfully removed the views, or the client has timed out
5152 // at which point anything goes.
5153 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */,
5154 DEFAULT_DISPLAY);
5155 }
5156
Julia Reynolds88860ce2017-06-01 16:55:49 -04005157 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08005158 private void scheduleDurationReachedLocked(ToastRecord r)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005159 {
5160 mHandler.removeCallbacksAndMessages(r);
Robert Carr997427342018-02-28 18:06:10 -08005161 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005162 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
5163 mHandler.sendMessageDelayed(m, delay);
5164 }
5165
Robert Carr997427342018-02-28 18:06:10 -08005166 private void handleDurationReached(ToastRecord record)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005167 {
5168 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
5169 synchronized (mToastQueue) {
5170 int index = indexOfToastLocked(record.pkg, record.callback);
5171 if (index >= 0) {
5172 cancelToastLocked(index);
5173 }
5174 }
5175 }
5176
Julia Reynolds88860ce2017-06-01 16:55:49 -04005177 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08005178 private void scheduleKillTokenTimeout(IBinder token)
5179 {
5180 mHandler.removeCallbacksAndMessages(token);
5181 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, token);
Robert Carr3406d462018-03-15 16:19:07 -07005182 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
Robert Carr997427342018-02-28 18:06:10 -08005183 }
5184
5185 private void handleKillTokenTimeout(IBinder token)
5186 {
5187 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + token);
5188 synchronized (mToastQueue) {
5189 finishTokenLocked(token);
5190 }
5191 }
5192
5193 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005194 int indexOfToastLocked(String pkg, ITransientNotification callback)
5195 {
5196 IBinder cbak = callback.asBinder();
5197 ArrayList<ToastRecord> list = mToastQueue;
5198 int len = list.size();
5199 for (int i=0; i<len; i++) {
5200 ToastRecord r = list.get(i);
Beverly Tai98efc792018-06-11 14:50:36 +00005201 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08005202 return i;
5203 }
5204 }
5205 return -1;
5206 }
5207
Julia Reynolds88860ce2017-06-01 16:55:49 -04005208 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005209 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005210 {
5211 int toastCount = 0; // toasts from this pid
5212 ArrayList<ToastRecord> list = mToastQueue;
5213 int N = list.size();
5214 for (int i=0; i<N; i++) {
5215 ToastRecord r = list.get(i);
5216 if (r.pid == pid) {
5217 toastCount++;
5218 }
5219 }
5220 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07005221 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08005222 } catch (RemoteException e) {
5223 // Shouldn't happen.
5224 }
5225 }
5226
Chris Wrenf9536642014-04-17 10:01:54 -04005227 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005228 if (!(message.obj instanceof RankingReconsideration)) return;
5229 RankingReconsideration recon = (RankingReconsideration) message.obj;
5230 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04005231 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005232 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005233 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
5234 if (record == null) {
5235 return;
Chris Wrenf9536642014-04-17 10:01:54 -04005236 }
Chris Wren333a61c2014-05-28 16:40:57 -04005237 int indexBefore = findNotificationRecordIndexLocked(record);
5238 boolean interceptBefore = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005239 float contactAffinityBefore = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005240 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04005241 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04005242 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04005243 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04005244 int indexAfter = findNotificationRecordIndexLocked(record);
5245 boolean interceptAfter = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005246 float contactAffinityAfter = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005247 int visibilityAfter = record.getPackageVisibilityOverride();
5248 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
5249 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005250 if (interceptBefore && !interceptAfter
5251 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
Chris Wrena3446562014-06-03 18:11:47 -04005252 buzzBeepBlinkLocked(record);
5253 }
Chris Wrenf9536642014-04-17 10:01:54 -04005254 }
Chris Wren333a61c2014-05-28 16:40:57 -04005255 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005256 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04005257 }
5258 }
5259
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005260 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04005261 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005262 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04005263 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005264 // Any field that can change via one of the extractors needs to be added here.
5265 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005266 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05005267 boolean[] showBadges = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005268 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
5269 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
5270 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
5271 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Julia Reynolds503ed942017-10-04 16:04:56 -04005272 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005273 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
Chris Wren54bbef42014-07-09 18:37:56 -04005274 for (int i = 0; i < N; i++) {
5275 final NotificationRecord r = mNotificationList.get(i);
5276 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005277 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05005278 showBadges[i] = r.canShowBadge();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005279 channelBefore.add(r.getChannel());
5280 groupKeyBefore.add(r.getGroupKey());
5281 overridePeopleBefore.add(r.getPeopleOverride());
5282 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Julia Reynolds503ed942017-10-04 16:04:56 -04005283 userSentimentBefore.add(r.getUserSentiment());
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005284 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
Chris Wren54bbef42014-07-09 18:37:56 -04005285 mRankingHelper.extractSignals(r);
5286 }
Chris Wren19a02b02015-12-22 10:34:22 -05005287 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04005288 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005289 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005290 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05005291 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005292 || showBadges[i] != r.canShowBadge()
5293 || !Objects.equals(channelBefore.get(i), r.getChannel())
5294 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
5295 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
Julia Reynolds503ed942017-10-04 16:04:56 -04005296 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005297 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
5298 || !Objects.equals(suppressVisuallyBefore.get(i),
5299 r.getSuppressedVisualEffects())) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005300 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04005301 return;
5302 }
5303 }
5304 }
5305 }
5306
Julia Reynolds88860ce2017-06-01 16:55:49 -04005307 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005308 private void recordCallerLocked(NotificationRecord record) {
5309 if (mZenModeHelper.isCall(record)) {
5310 mZenModeHelper.recordCaller(record);
5311 }
5312 }
5313
Christoph Studerd5092bc2014-07-03 17:47:58 +02005314 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04005315 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005316 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02005317 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005318 if (record.isIntercepted()) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05005319 record.setSuppressedVisualEffects(
5320 mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
Julia Reynolds445cfa82017-05-08 15:41:45 -04005321 } else {
5322 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005323 }
Chris Wren333a61c2014-05-28 16:40:57 -04005324 }
5325
Julia Reynolds88860ce2017-06-01 16:55:49 -04005326 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04005327 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04005328 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04005329 }
5330
Chris Wrenf9536642014-04-17 10:01:54 -04005331 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005332 synchronized (mNotificationLock) {
Beverly5a20a5e2018-03-06 15:02:44 -05005333 mListeners.notifyRankingUpdateLocked(null);
Chris Wrenf9536642014-04-17 10:01:54 -04005334 }
5335 }
5336
John Spurlockd8afe3c2014-08-01 14:04:07 -04005337 private void scheduleListenerHintsChanged(int state) {
5338 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
5339 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04005340 }
5341
Christoph Studer85a384b2014-08-27 20:16:15 +02005342 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
5343 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
5344 mHandler.obtainMessage(
5345 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
5346 listenerInterruptionFilter,
5347 0).sendToTarget();
5348 }
5349
John Spurlockd8afe3c2014-08-01 14:04:07 -04005350 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005351 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005352 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005353 }
5354 }
5355
Christoph Studer85a384b2014-08-27 20:16:15 +02005356 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005357 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02005358 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
5359 }
5360 }
5361
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005362 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08005363 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005364 public WorkerHandler(Looper looper) {
5365 super(looper);
5366 }
5367
Adam Lesinski182f73f2013-12-05 16:48:06 -08005368 @Override
5369 public void handleMessage(Message msg)
5370 {
5371 switch (msg.what)
5372 {
Robert Carr997427342018-02-28 18:06:10 -08005373 case MESSAGE_DURATION_REACHED:
5374 handleDurationReached((ToastRecord)msg.obj);
5375 break;
5376 case MESSAGE_FINISH_TOKEN_TIMEOUT:
5377 handleKillTokenTimeout((IBinder)msg.obj);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005378 break;
John Spurlock056c5192014-04-20 21:52:01 -04005379 case MESSAGE_SAVE_POLICY_FILE:
5380 handleSavePolicyFile();
5381 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005382 case MESSAGE_SEND_RANKING_UPDATE:
5383 handleSendRankingUpdate();
5384 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04005385 case MESSAGE_LISTENER_HINTS_CHANGED:
5386 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04005387 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02005388 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
5389 handleListenerInterruptionFilterChanged(msg.arg1);
5390 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005391 }
5392 }
5393
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005394 protected void scheduleSendRankingUpdate() {
5395 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
5396 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
5397 sendMessage(m);
5398 }
5399 }
5400
Chris Wrenf9536642014-04-17 10:01:54 -04005401 }
5402
Chris Wren51017d02015-12-15 15:34:46 -05005403 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04005404 {
Chris Wren51017d02015-12-15 15:34:46 -05005405 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04005406 super(looper);
5407 }
5408
5409 @Override
5410 public void handleMessage(Message msg) {
5411 switch (msg.what) {
5412 case MESSAGE_RECONSIDER_RANKING:
5413 handleRankingReconsideration(msg);
5414 break;
Chris Wren51017d02015-12-15 15:34:46 -05005415 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005416 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04005417 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08005418 }
5419 }
Chris Wren51017d02015-12-15 15:34:46 -05005420
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005421 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05005422 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05005423 Message msg = Message.obtain();
5424 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05005425 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05005426 }
5427
5428 public void requestReconsideration(RankingReconsideration recon) {
5429 Message m = Message.obtain(this,
5430 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
5431 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
5432 sendMessageDelayed(m, delay);
5433 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08005434 }
5435
Adam Lesinski182f73f2013-12-05 16:48:06 -08005436 // Notifications
5437 // ============================================================================
5438 static int clamp(int x, int low, int high) {
5439 return (x < low) ? low : ((x > high) ? high : x);
5440 }
5441
5442 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
Eugene Suslad4128ec2017-12-04 19:48:41 +00005443 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07005444 return;
5445 }
5446
5447 AccessibilityEvent event =
5448 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
5449 event.setPackageName(packageName);
5450 event.setClassName(Notification.class.getName());
5451 event.setParcelableData(notification);
5452 CharSequence tickerText = notification.tickerText;
5453 if (!TextUtils.isEmpty(tickerText)) {
5454 event.getText().add(tickerText);
5455 }
5456
Julia Reynolds94187562017-10-10 13:58:49 -04005457 mAccessibilityManager.sendAccessibilityEvent(event);
svetoslavganov75986cf2009-05-14 22:28:01 -07005458 }
5459
Julia Reynolds0839c022017-06-15 15:24:01 -04005460 /**
5461 * Removes all NotificationsRecords with the same key as the given notification record
5462 * from both lists. Do not call this method while iterating over either list.
5463 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005464 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04005465 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
5466 // Remove from both lists, either list could have a separate Record for what is
5467 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005468 boolean wasPosted = false;
5469 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04005470 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
5471 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005472 mNotificationList.remove(recordInList);
5473 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005474 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005475 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005476 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005477 != null) {
5478 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005479 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005480 return wasPosted;
5481 }
5482
5483 @GuardedBy("mNotificationLock")
5484 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04005485 boolean wasPosted, String listenerName) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005486 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName);
5487 }
5488
5489 @GuardedBy("mNotificationLock")
5490 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
5491 int rank, int count, boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04005492 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005493
5494 // Record caller.
5495 recordCallerLocked(r);
5496
Julia Reynolds503ed942017-10-04 16:04:56 -04005497 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
5498 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
5499 }
5500
Joe Onorato46439ce2010-11-19 13:56:21 -08005501 // tell the app
5502 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005503 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08005504 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005505 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08005506 } catch (PendingIntent.CanceledException ex) {
5507 // do nothing - there's no relevant way to recover, and
5508 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04005509 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08005510 }
5511 }
5512 }
5513
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005514 // Only cancel these if this notification actually got to be posted.
5515 if (wasPosted) {
5516 // status bar
5517 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005518 if (reason != REASON_SNOOZED) {
5519 r.isCanceled = true;
5520 }
Beverly5a20a5e2018-03-06 15:02:44 -05005521 mListeners.notifyRemovedLocked(r, reason, r.getStats());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005522 mHandler.post(new Runnable() {
5523 @Override
5524 public void run() {
5525 mGroupHelper.onNotificationRemoved(r.sbn);
5526 }
5527 });
5528 }
5529
5530 // sound
5531 if (canceledKey.equals(mSoundNotificationKey)) {
5532 mSoundNotificationKey = null;
5533 final long identity = Binder.clearCallingIdentity();
5534 try {
5535 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5536 if (player != null) {
5537 player.stopAsync();
5538 }
5539 } catch (RemoteException e) {
5540 } finally {
5541 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04005542 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005544
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005545 // vibrate
5546 if (canceledKey.equals(mVibrateNotificationKey)) {
5547 mVibrateNotificationKey = null;
5548 long identity = Binder.clearCallingIdentity();
5549 try {
5550 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005551 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005552 finally {
5553 Binder.restoreCallingIdentity(identity);
5554 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005555 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005556
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005557 // light
5558 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005559 }
5560
Christoph Studer546bec82014-03-14 12:17:12 +01005561 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04005562 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01005563 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005564 case REASON_CANCEL:
5565 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005566 case REASON_LISTENER_CANCEL:
5567 case REASON_LISTENER_CANCEL_ALL:
5568 mUsageStats.registerDismissedByUser(r);
5569 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05005570 case REASON_APP_CANCEL:
5571 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005572 mUsageStats.registerRemovedByApp(r);
5573 break;
Christoph Studer546bec82014-03-14 12:17:12 +01005574 }
5575
Christoph Studer265c1052014-07-23 17:14:33 +02005576 String groupKey = r.getGroupKey();
5577 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005578 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02005579 mSummaryByGroupKey.remove(groupKey);
5580 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04005581 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
5582 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
5583 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04005584 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005585
Daniel Sandler23d7c702013-03-07 16:32:06 -05005586 // Save it for users of getHistoricalNotifications()
5587 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02005588
Chris Wren6650e572015-05-15 17:19:25 -04005589 final long now = System.currentTimeMillis();
Dieter Hsud39f0d52018-04-14 02:08:30 +08005590 final LogMaker logMaker = r.getLogMaker(now)
Chris Wren9eb5e102017-01-26 13:15:06 -05005591 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
5592 .setType(MetricsEvent.TYPE_DISMISS)
Dieter Hsud39f0d52018-04-14 02:08:30 +08005593 .setSubtype(reason);
5594 if (rank != -1 && count != -1) {
5595 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
5596 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
5597 }
5598 MetricsLogger.action(logMaker);
Chris Wrene6ddb8a2015-05-27 15:21:00 -04005599 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Dieter Hsud39f0d52018-04-14 02:08:30 +08005600 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
5601 rank, count, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005602 }
5603
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005604 @VisibleForTesting
5605 void updateUriPermissions(@Nullable NotificationRecord newRecord,
5606 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) {
5607 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey();
5608 if (DBG) Slog.d(TAG, key + ": updating permissions");
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005609
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005610 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null;
5611 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null;
5612
5613 // Shortcut when no Uris involved
5614 if (newUris == null && oldUris == null) {
5615 return;
5616 }
5617
5618 // Inherit any existing owner
5619 IBinder permissionOwner = null;
5620 if (newRecord != null && permissionOwner == null) {
5621 permissionOwner = newRecord.permissionOwner;
5622 }
5623 if (oldRecord != null && permissionOwner == null) {
5624 permissionOwner = oldRecord.permissionOwner;
5625 }
5626
5627 // If we have Uris to grant, but no owner yet, go create one
5628 if (newUris != null && permissionOwner == null) {
5629 try {
5630 if (DBG) Slog.d(TAG, key + ": creating owner");
5631 permissionOwner = mAm.newUriPermissionOwner("NOTIF:" + key);
5632 } catch (RemoteException ignored) {
5633 // Ignored because we're in same process
5634 }
5635 }
5636
5637 // If we have no Uris to grant, but an existing owner, go destroy it
5638 if (newUris == null && permissionOwner != null) {
5639 final long ident = Binder.clearCallingIdentity();
5640 try {
5641 if (DBG) Slog.d(TAG, key + ": destroying owner");
5642 mAm.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
5643 UserHandle.getUserId(oldRecord.getUid()));
5644 permissionOwner = null;
5645 } catch (RemoteException ignored) {
5646 // Ignored because we're in same process
5647 } finally {
5648 Binder.restoreCallingIdentity(ident);
5649 }
5650 }
5651
5652 // Grant access to new Uris
5653 if (newUris != null && permissionOwner != null) {
5654 for (int i = 0; i < newUris.size(); i++) {
5655 final Uri uri = newUris.valueAt(i);
5656 if (oldUris == null || !oldUris.contains(uri)) {
5657 if (DBG) Slog.d(TAG, key + ": granting " + uri);
5658 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
5659 targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005660 }
5661 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005662 }
5663
5664 // Revoke access to old Uris
5665 if (oldUris != null && permissionOwner != null) {
5666 for (int i = 0; i < oldUris.size(); i++) {
5667 final Uri uri = oldUris.valueAt(i);
5668 if (newUris == null || !newUris.contains(uri)) {
5669 if (DBG) Slog.d(TAG, key + ": revoking " + uri);
5670 revokeUriPermission(permissionOwner, uri, oldRecord.getUid());
5671 }
5672 }
5673 }
5674
5675 if (newRecord != null) {
5676 newRecord.permissionOwner = permissionOwner;
5677 }
5678 }
5679
5680 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg,
5681 int targetUserId) {
5682 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5683
5684 final long ident = Binder.clearCallingIdentity();
5685 try {
5686 mAm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
5687 ContentProvider.getUriWithoutUserId(uri),
5688 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5689 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
5690 targetUserId);
5691 } catch (RemoteException ignored) {
5692 // Ignored because we're in same process
5693 } finally {
5694 Binder.restoreCallingIdentity(ident);
5695 }
5696 }
5697
5698 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUid) {
5699 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5700
5701 final long ident = Binder.clearCallingIdentity();
5702 try {
5703 mAm.revokeUriPermissionFromOwner(owner,
5704 ContentProvider.getUriWithoutUserId(uri),
5705 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5706 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
5707 } catch (RemoteException ignored) {
5708 // Ignored because we're in same process
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005709 } finally {
5710 Binder.restoreCallingIdentity(ident);
5711 }
5712 }
5713
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005714 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07005715 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005716 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005717 */
John Spurlocke6a7d932014-03-13 12:29:00 -04005718 void cancelNotification(final int callingUid, final int callingPid,
5719 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005720 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04005721 final int userId, final int reason, final ManagedServiceInfo listener) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005722 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
5723 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
5724 }
5725
5726 /**
5727 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
5728 * and none of the {@code mustNotHaveFlags}.
5729 */
5730 void cancelNotification(final int callingUid, final int callingPid,
5731 final String pkg, final String tag, final int id,
5732 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
5733 final int userId, final int reason, int rank, int count, final ManagedServiceInfo listener) {
Beverly5a20a5e2018-03-06 15:02:44 -05005734
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005735 // In enqueueNotificationInternal notifications are added by scheduling the
5736 // work on the worker handler. Hence, we also schedule the cancel on this
5737 // handler to avoid a scenario where an add notification call followed by a
5738 // remove notification call ends up in not removing the notification.
5739 mHandler.post(new Runnable() {
5740 @Override
5741 public void run() {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005742 String listenerName = listener == null ? null : listener.component.toShortString();
Chris Wrenbddb5bc2015-03-04 08:47:46 -08005743 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
5744 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005745
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005746 synchronized (mNotificationLock) {
5747 // Look for the notification, searching both the posted and enqueued lists.
5748 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
5749 if (r != null) {
5750 // The notification was found, check if it should be removed.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005751
Christoph Studer546bec82014-03-14 12:17:12 +01005752 // Ideally we'd do this in the caller of this method. However, that would
5753 // require the caller to also find the notification.
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005754 if (reason == REASON_CLICK) {
Christoph Studer546bec82014-03-14 12:17:12 +01005755 mUsageStats.registerClickedByUser(r);
5756 }
5757
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005758 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
5759 return;
5760 }
5761 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
5762 return;
5763 }
5764
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005765 // Cancel the notification.
Julia Reynolds0839c022017-06-15 15:24:01 -04005766 boolean wasPosted = removeFromNotificationListsLocked(r);
Dieter Hsud39f0d52018-04-14 02:08:30 +08005767 cancelNotificationLocked(r, sendDelete, reason, rank, count, wasPosted, listenerName);
Christoph Studer265c1052014-07-23 17:14:33 +02005768 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005769 sendDelete, null);
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005770 updateLightsLocked();
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005771 } else {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005772 // No notification was found, assume that it is snoozed and cancel it.
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005773 if (reason != REASON_SNOOZED) {
5774 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
5775 if (wasSnoozed) {
5776 savePolicyFile();
5777 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005778 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005779 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005780 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005781 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005782 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005783 }
5784
5785 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07005786 * Determine whether the userId applies to the notification in question, either because
5787 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
5788 */
5789 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
5790 return
5791 // looking for USER_ALL notifications? match everything
5792 userId == UserHandle.USER_ALL
5793 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005794 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07005795 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005796 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07005797 }
5798
5799 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005800 * Determine whether the userId applies to the notification in question, either because
5801 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01005802 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005803 */
Kenny Guy2a764942014-04-02 13:29:20 +01005804 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00005805 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04005806 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005807 }
5808
5809 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05005810 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005811 * {@code mustHaveFlags}.
5812 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005813 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005814 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005815 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005816 mHandler.post(new Runnable() {
5817 @Override
5818 public void run() {
5819 String listenerName = listener == null ? null : listener.component.toShortString();
5820 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5821 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
5822 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005823
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005824 // Why does this parameter exist? Do we actually want to execute the above if doit
5825 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005826 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005827 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005828 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005829
5830 synchronized (mNotificationLock) {
5831 FlagChecker flagChecker = (int flags) -> {
5832 if ((flags & mustHaveFlags) != mustHaveFlags) {
5833 return false;
5834 }
5835 if ((flags & mustNotHaveFlags) != 0) {
5836 return false;
5837 }
5838 return true;
5839 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005840 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5841 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
5842 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005843 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005844 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5845 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
5846 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005847 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005848 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005849 }
5850 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005851 });
5852 }
5853
5854 private interface FlagChecker {
5855 // Returns false if these flags do not pass the defined flag test.
5856 public boolean apply(int flags);
5857 }
5858
Julia Reynolds88860ce2017-06-01 16:55:49 -04005859 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005860 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
5861 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
5862 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005863 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005864 ArrayList<NotificationRecord> canceledNotifications = null;
5865 for (int i = notificationList.size() - 1; i >= 0; --i) {
5866 NotificationRecord r = notificationList.get(i);
5867 if (includeCurrentProfiles) {
5868 if (!notificationMatchesCurrentProfiles(r, userId)) {
5869 continue;
5870 }
5871 } else if (!notificationMatchesUserId(r, userId)) {
5872 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005873 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005874 // Don't remove notifications to all, if there's no package name specified
5875 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
5876 continue;
5877 }
5878 if (!flagChecker.apply(r.getFlags())) {
5879 continue;
5880 }
5881 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
5882 continue;
5883 }
5884 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
5885 continue;
5886 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005887 if (canceledNotifications == null) {
5888 canceledNotifications = new ArrayList<>();
5889 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005890 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005891 mNotificationsByKey.remove(r.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005892 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04005893 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005894 }
5895 if (canceledNotifications != null) {
5896 final int M = canceledNotifications.size();
5897 for (int i = 0; i < M; i++) {
5898 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005899 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005900 }
5901 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005902 }
5903 }
5904
Julia Reynolds50989772017-02-23 14:32:16 -05005905 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005906 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05005907 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005908 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05005909 return;
5910 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05005911
Julia Reynolds79672302017-01-12 08:30:16 -05005912 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05005913 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
5914 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05005915 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005916 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005917 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005918 }
5919
5920 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
5921 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005922 if (DBG) {
5923 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
5924 }
Julia Reynolds79672302017-01-12 08:30:16 -05005925 mSnoozeHelper.repost(key);
5926 savePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005927 }
5928
Julia Reynolds88860ce2017-06-01 16:55:49 -04005929 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07005930 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005931 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005932 mHandler.post(new Runnable() {
5933 @Override
5934 public void run() {
5935 synchronized (mNotificationLock) {
5936 String listenerName =
5937 listener == null ? null : listener.component.toShortString();
5938 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5939 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01005940
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005941 FlagChecker flagChecker = (int flags) -> {
5942 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
5943 != 0) {
5944 return false;
5945 }
5946 return true;
5947 };
5948
5949 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5950 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
5951 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005952 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005953 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5954 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
5955 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04005956 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005957 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00005958 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005959 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005960 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005961 }
5962
Christoph Studere4ef156b2014-07-04 18:41:57 +02005963 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04005964 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02005965 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005966 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005967 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02005968 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005969 return;
5970 }
5971
5972 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02005973
5974 if (pkg == null) {
5975 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
5976 return;
5977 }
5978
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005979 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005980 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005981 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005982 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005983 }
5984
Julia Reynolds88860ce2017-06-01 16:55:49 -04005985 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005986 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
5987 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005988 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005989 final String pkg = parentNotification.sbn.getPackageName();
5990 final int userId = parentNotification.getUserId();
5991 final int reason = REASON_GROUP_SUMMARY_CANCELED;
5992 for (int i = notificationList.size() - 1; i >= 0; i--) {
5993 final NotificationRecord childR = notificationList.get(i);
5994 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04005995 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005996 childR.getGroupKey().equals(parentNotification.getGroupKey())
Julia Reynoldse5c60452018-04-30 14:41:36 -04005997 && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
Beverly40239d92017-07-07 10:20:41 -04005998 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02005999 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
6000 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04006001 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04006002 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04006003 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02006004 }
6005 }
6006 }
6007
Julia Reynolds88860ce2017-06-01 16:55:49 -04006008 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08006009 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006010 {
The Android Open Source Project10592532009-03-18 17:39:46 -07006011 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05006012 NotificationRecord ledNotification = null;
6013 while (ledNotification == null && !mLights.isEmpty()) {
6014 final String owner = mLights.get(mLights.size() - 1);
6015 ledNotification = mNotificationsByKey.get(owner);
6016 if (ledNotification == null) {
6017 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
6018 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006019 }
6020 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006021
Mike Lockwood63b5ad92011-08-30 09:55:30 -04006022 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05006023 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05006024 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07006025 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006026 NotificationRecord.Light light = ledNotification.getLight();
6027 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05006028 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006029 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
6030 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05006031 }
The Android Open Source Project10592532009-03-18 17:39:46 -07006032 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006033 }
6034
Julia Reynolds88860ce2017-06-01 16:55:49 -04006035 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006036 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
6037 String groupKey, int userId) {
6038 List<NotificationRecord> records = new ArrayList<>();
6039 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
6040 records.addAll(
6041 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
6042 return records;
6043 }
6044
6045
Julia Reynolds88860ce2017-06-01 16:55:49 -04006046 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006047 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
6048 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
6049 List<NotificationRecord> records = new ArrayList<>();
6050 final int len = list.size();
6051 for (int i = 0; i < len; i++) {
6052 NotificationRecord r = list.get(i);
6053 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
6054 && r.sbn.getPackageName().equals(pkg)) {
6055 records.add(r);
6056 }
6057 }
6058 return records;
6059 }
6060
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006061 // Searches both enqueued and posted notifications by key.
6062 // TODO: need to combine a bunch of these getters with slightly different behavior.
6063 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04006064 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006065 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006066 NotificationRecord r;
6067 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
6068 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006069 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006070 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
6071 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006072 }
6073 return null;
6074 }
6075
Julia Reynolds88860ce2017-06-01 16:55:49 -04006076 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006077 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006078 NotificationRecord r;
6079 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
6080 return r;
6081 }
6082 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
6083 != null) {
6084 return r;
6085 }
6086 return null;
6087 }
6088
Julia Reynolds88860ce2017-06-01 16:55:49 -04006089 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006090 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006091 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006092 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006093 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006094 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01006095 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
6096 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006097 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006098 }
6099 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006100 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006101 }
6102
Julia Reynolds88860ce2017-06-01 16:55:49 -04006103 @GuardedBy("mNotificationLock")
Julia Reynoldsac3f14e2018-09-13 15:53:11 -04006104 private List<NotificationRecord> findNotificationsByListLocked(
6105 ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) {
6106 List<NotificationRecord> matching = new ArrayList<>();
6107 final int len = list.size();
6108 for (int i = 0; i < len; i++) {
6109 NotificationRecord r = list.get(i);
6110 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
6111 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
6112 matching.add(r);
6113 }
6114 }
6115 return matching;
6116 }
6117
6118 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006119 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04006120 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006121 final int N = list.size();
6122 for (int i = 0; i < N; i++) {
6123 if (key.equals(list.get(i).getKey())) {
6124 return list.get(i);
6125 }
6126 }
6127 return null;
6128 }
6129
Julia Reynolds88860ce2017-06-01 16:55:49 -04006130 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02006131 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02006132 final int N = mNotificationList.size();
6133 for (int i = 0; i < N; i++) {
6134 if (key.equals(mNotificationList.get(i).getKey())) {
6135 return i;
6136 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02006137 }
Christoph Studerc5115552014-06-12 20:22:31 +02006138 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02006139 }
6140
Beverly5a20a5e2018-03-06 15:02:44 -05006141 @VisibleForTesting
6142 protected void hideNotificationsForPackages(String[] pkgs) {
6143 synchronized (mNotificationLock) {
6144 List<String> pkgList = Arrays.asList(pkgs);
6145 List<NotificationRecord> changedNotifications = new ArrayList<>();
6146 int numNotifications = mNotificationList.size();
6147 for (int i = 0; i < numNotifications; i++) {
6148 NotificationRecord rec = mNotificationList.get(i);
6149 if (pkgList.contains(rec.sbn.getPackageName())) {
6150 rec.setHidden(true);
6151 changedNotifications.add(rec);
6152 }
6153 }
6154
6155 mListeners.notifyHiddenLocked(changedNotifications);
6156 }
6157 }
6158
6159 @VisibleForTesting
6160 protected void unhideNotificationsForPackages(String[] pkgs) {
6161 synchronized (mNotificationLock) {
6162 List<String> pkgList = Arrays.asList(pkgs);
6163 List<NotificationRecord> changedNotifications = new ArrayList<>();
6164 int numNotifications = mNotificationList.size();
6165 for (int i = 0; i < numNotifications; i++) {
6166 NotificationRecord rec = mNotificationList.get(i);
6167 if (pkgList.contains(rec.sbn.getPackageName())) {
6168 rec.setHidden(false);
6169 changedNotifications.add(rec);
6170 }
6171 }
6172
6173 mListeners.notifyUnhiddenLocked(changedNotifications);
6174 }
6175 }
6176
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006177 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006178 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006179 updateLightsLocked();
6180 }
6181 }
John Spurlocke677d712014-02-13 12:52:19 -05006182
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006183 protected boolean isCallingUidSystem() {
6184 final int uid = Binder.getCallingUid();
6185 return uid == Process.SYSTEM_UID;
6186 }
6187
6188 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04006189 final int appid = UserHandle.getAppId(uid);
6190 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
6191 }
John Spurlockb408e8e2014-04-23 21:12:45 -04006192
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006193 // TODO: Most calls should probably move to isCallerSystem.
6194 protected boolean isCallerSystemOrPhone() {
6195 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04006196 }
6197
Julia Reynoldsb852e562017-06-06 16:14:18 -04006198 private void checkCallerIsSystemOrShell() {
6199 if (Binder.getCallingUid() == Process.SHELL_UID) {
6200 return;
6201 }
6202 checkCallerIsSystem();
6203 }
6204
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006205 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006206 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006207 return;
6208 }
6209 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
6210 }
6211
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006212 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006213 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006214 return;
6215 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04006216 checkCallerIsSameApp(pkg);
6217 }
6218
Chad Brubaker6b68f102017-01-27 13:39:00 -08006219 private boolean isCallerInstantApp(String pkg) {
6220 // System is always allowed to act for ephemeral apps.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006221 if (isCallerSystemOrPhone()) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08006222 return false;
6223 }
6224
6225 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
6226
6227 try {
6228 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
6229 UserHandle.getCallingUserId());
6230 if (ai == null) {
6231 throw new SecurityException("Unknown package " + pkg);
6232 }
6233 return ai.isInstantApp();
6234 } catch (RemoteException re) {
6235 throw new SecurityException("Unknown package " + pkg, re);
6236 }
6237
6238 }
6239
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006240 private void checkCallerIsSameApp(String pkg) {
John Spurlock7340fc82014-04-24 18:50:12 -04006241 final int uid = Binder.getCallingUid();
6242 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006243 ApplicationInfo ai = mPackageManager.getApplicationInfo(
John Spurlock7340fc82014-04-24 18:50:12 -04006244 pkg, 0, UserHandle.getCallingUserId());
Dan Sandler09afc2e2014-07-18 14:29:20 -04006245 if (ai == null) {
6246 throw new SecurityException("Unknown package " + pkg);
6247 }
John Spurlock7340fc82014-04-24 18:50:12 -04006248 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006249 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04006250 + pkg + " which is owned by uid " + ai.uid);
6251 }
6252 } catch (RemoteException re) {
6253 throw new SecurityException("Unknown package " + pkg + "\n" + re);
6254 }
6255 }
6256
John Spurlock32fe4c62014-10-02 12:16:02 -04006257 private static String callStateToString(int state) {
6258 switch (state) {
6259 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
6260 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
6261 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
6262 default: return "CALL_STATE_UNKNOWN_" + state;
6263 }
6264 }
6265
6266 private void listenForCallState() {
6267 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
6268 @Override
6269 public void onCallStateChanged(int state, String incomingNumber) {
6270 if (mCallState == state) return;
6271 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
6272 mCallState = state;
6273 }
6274 }, PhoneStateListener.LISTEN_CALL_STATE);
6275 }
6276
Christoph Studer05ad4822014-05-16 14:16:03 +02006277 /**
6278 * Generates a NotificationRankingUpdate from 'sbns', considering only
6279 * notifications visible to the given listener.
6280 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006281 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04006282 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04006283 final int N = mNotificationList.size();
6284 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02006285 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05006286 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04006287 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006288 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006289 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05006290 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006291 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05006292 Bundle overridePeople = new Bundle();
6293 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006294 Bundle showBadge = new Bundle();
Julia Reynolds503ed942017-10-04 16:04:56 -04006295 Bundle userSentiment = new Bundle();
Beverly5a20a5e2018-03-06 15:02:44 -05006296 Bundle hidden = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04006297 for (int i = 0; i < N; i++) {
6298 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02006299 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006300 continue;
6301 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006302 final String key = record.sbn.getKey();
6303 keys.add(key);
6304 importance.add(record.getImportance());
6305 if (record.getImportanceExplanation() != null) {
6306 explanation.putCharSequence(key, record.getImportanceExplanation());
6307 }
Chris Wren333a61c2014-05-28 16:40:57 -04006308 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006309 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006310
Christoph Studer05ad4822014-05-16 14:16:03 +02006311 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006312 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006313 if (record.getPackageVisibilityOverride()
6314 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006315 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006316 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04006317 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05006318 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05006319 overridePeople.putStringArrayList(key, record.getPeopleOverride());
6320 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05006321 showBadge.putBoolean(key, record.canShowBadge());
Julia Reynolds503ed942017-10-04 16:04:56 -04006322 userSentiment.putInt(key, record.getUserSentiment());
Beverly5a20a5e2018-03-06 15:02:44 -05006323 hidden.putBoolean(key, record.isHidden());
Christoph Studer05ad4822014-05-16 14:16:03 +02006324 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006325 final int M = keys.size();
6326 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02006327 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05006328 int[] importanceAr = new int[M];
6329 for (int i = 0; i < M; i++) {
6330 importanceAr[i] = importance.get(i);
6331 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006332 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05006333 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Beverly5a20a5e2018-03-06 15:02:44 -05006334 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden);
Christoph Studer05ad4822014-05-16 14:16:03 +02006335 }
6336
Julia Reynoldsda781472017-04-12 09:41:16 -04006337 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006338 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04006339 mCompanionManager = getCompanionManager();
6340 }
6341 // Companion mgr doesn't exist on all device types
6342 if (mCompanionManager == null) {
6343 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006344 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006345 long identity = Binder.clearCallingIdentity();
6346 try {
6347 List<String> associations = mCompanionManager.getAssociations(
6348 info.component.getPackageName(), info.userid);
6349 if (!ArrayUtils.isEmpty(associations)) {
6350 return true;
6351 }
6352 } catch (SecurityException se) {
6353 // Not a privileged listener
6354 } catch (RemoteException re) {
6355 Slog.e(TAG, "Cannot reach companion device service", re);
6356 } catch (Exception e) {
6357 Slog.e(TAG, "Cannot verify listener " + info, e);
6358 } finally {
6359 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006360 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006361 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006362 }
6363
Julia Reynolds727a7282017-04-13 10:54:01 -04006364 protected ICompanionDeviceManager getCompanionManager() {
6365 return ICompanionDeviceManager.Stub.asInterface(
6366 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
6367 }
6368
Christoph Studercef37cf2014-07-25 14:18:17 +02006369 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
6370 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
6371 return false;
6372 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07006373 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02006374 return true;
6375 }
6376
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00006377 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Beverly2be7a052018-03-27 11:37:58 -04006378 final long identity = Binder.clearCallingIdentity();
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006379 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006380 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006381 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006382 } catch (RemoteException re) {
6383 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00006384 } catch (IllegalArgumentException ex) {
6385 // Package not found.
6386 return false;
Beverly2be7a052018-03-27 11:37:58 -04006387 } finally {
6388 Binder.restoreCallingIdentity(identity);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006389 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006390 }
6391
Kristian Monsen30f59b22018-04-09 10:27:16 +02006392 @VisibleForTesting
6393 boolean canUseManagedServices(String pkg) {
6394 boolean canUseManagedServices = !mActivityManager.isLowRamDevice()
Julia Reynoldse1816412017-10-24 10:39:11 -04006395 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
Kristian Monsen30f59b22018-04-09 10:27:16 +02006396
6397 for (String whitelisted : getContext().getResources().getStringArray(
6398 R.array.config_allowedManagedServicesOnLowRamDevices)) {
6399 if (whitelisted.equals(pkg)) {
6400 canUseManagedServices = true;
6401 }
6402 }
6403
6404 return canUseManagedServices;
Julia Reynoldse1816412017-10-24 10:39:11 -04006405 }
6406
Chris Wren47633422016-01-22 09:56:59 -05006407 private class TrimCache {
6408 StatusBarNotification heavy;
6409 StatusBarNotification sbnClone;
6410 StatusBarNotification sbnCloneLight;
6411
6412 TrimCache(StatusBarNotification sbn) {
6413 heavy = sbn;
6414 }
6415
6416 StatusBarNotification ForListener(ManagedServiceInfo info) {
6417 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
6418 if (sbnCloneLight == null) {
6419 sbnCloneLight = heavy.cloneLight();
6420 }
6421 return sbnCloneLight;
6422 } else {
6423 if (sbnClone == null) {
6424 sbnClone = heavy.clone();
6425 }
6426 return sbnClone;
6427 }
6428 }
6429 }
6430
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006431 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006432 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05006433
Julia Reynolds7380d872018-01-12 10:28:26 -05006434 public NotificationAssistants(Context context, Object lock, UserProfiles up,
6435 IPackageManager pm) {
6436 super(context, lock, up, pm);
Chris Wren51017d02015-12-15 15:34:46 -05006437 }
6438
6439 @Override
6440 protected Config getConfig() {
6441 Config c = new Config();
Julia Reynolds503ed942017-10-04 16:04:56 -04006442 c.caption = "notification assistant";
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006443 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006444 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006445 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
6446 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05006447 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006448 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05006449 return c;
6450 }
6451
6452 @Override
6453 protected IInterface asInterface(IBinder binder) {
6454 return INotificationListener.Stub.asInterface(binder);
6455 }
6456
6457 @Override
6458 protected boolean checkType(IInterface service) {
6459 return service instanceof INotificationListener;
6460 }
6461
6462 @Override
6463 protected void onServiceAdded(ManagedServiceInfo info) {
6464 mListeners.registerGuestService(info);
6465 }
6466
6467 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006468 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05006469 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
6470 mListeners.unregisterService(removed.service, removed.userid);
6471 }
Chris Wren47633422016-01-22 09:56:59 -05006472
Julia Reynoldsef934fd2018-02-01 14:39:17 -05006473 @Override
6474 public void onUserUnlocked(int user) {
6475 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
6476 rebindServices(true);
6477 }
6478
Chris Wren47633422016-01-22 09:56:59 -05006479 public void onNotificationEnqueued(final NotificationRecord r) {
6480 final StatusBarNotification sbn = r.sbn;
6481 TrimCache trimCache = new TrimCache(sbn);
6482
Chris Wren47633422016-01-22 09:56:59 -05006483 // There should be only one, but it's a list, so while we enforce
6484 // singularity elsewhere, we keep it general here, to avoid surprises.
Julia Reynolds00314d92017-04-14 10:01:24 -04006485 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
Chris Wren47633422016-01-22 09:56:59 -05006486 boolean sbnVisible = isVisibleToListener(sbn, info);
6487 if (!sbnVisible) {
6488 continue;
6489 }
6490
Chris Wren47633422016-01-22 09:56:59 -05006491 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006492 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05006493 @Override
6494 public void run() {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006495 notifyEnqueued(info, sbnToPost);
Chris Wren47633422016-01-22 09:56:59 -05006496 }
6497 });
6498 }
6499 }
6500
6501 private void notifyEnqueued(final ManagedServiceInfo info,
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006502 final StatusBarNotification sbn) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006503 final INotificationListener assistant = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05006504 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6505 try {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006506 assistant.onNotificationEnqueued(sbnHolder);
Chris Wren47633422016-01-22 09:56:59 -05006507 } catch (RemoteException ex) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006508 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Chris Wren47633422016-01-22 09:56:59 -05006509 }
6510 }
6511
Julia Reynolds79672302017-01-12 08:30:16 -05006512 /**
6513 * asynchronously notify the assistant that a notification has been snoozed until a
6514 * context
6515 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006516 @GuardedBy("mNotificationLock")
Julia Reynolds79672302017-01-12 08:30:16 -05006517 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
6518 final String snoozeCriterionId) {
6519 TrimCache trimCache = new TrimCache(sbn);
Julia Reynolds00314d92017-04-14 10:01:24 -04006520 for (final ManagedServiceInfo info : getServices()) {
Julia Reynolds503ed942017-10-04 16:04:56 -04006521 boolean sbnVisible = isVisibleToListener(sbn, info);
6522 if (!sbnVisible) {
6523 continue;
6524 }
Julia Reynolds79672302017-01-12 08:30:16 -05006525 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
6526 mHandler.post(new Runnable() {
6527 @Override
6528 public void run() {
6529 final INotificationListener assistant =
6530 (INotificationListener) info.service;
6531 StatusBarNotificationHolder sbnHolder
6532 = new StatusBarNotificationHolder(sbnToPost);
6533 try {
6534 assistant.onNotificationSnoozedUntilContext(
6535 sbnHolder, snoozeCriterionId);
6536 } catch (RemoteException ex) {
6537 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
6538 }
6539 }
6540 });
6541 }
6542 }
6543
Chris Wren47633422016-01-22 09:56:59 -05006544 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04006545 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05006546 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006547
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04006548 protected void ensureAssistant() {
6549 final List<UserInfo> activeUsers = mUm.getUsers(true);
6550 for (UserInfo userInfo : activeUsers) {
6551 int userId = userInfo.getUserHandle().getIdentifier();
6552 if (getAllowedPackages(userId).isEmpty()) {
6553 Slog.d(TAG, "Approving default notification assistant for user " + userId);
6554 readDefaultAssistant(userId);
6555 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006556 }
6557 }
Chris Wren51017d02015-12-15 15:34:46 -05006558 }
6559
John Spurlock7340fc82014-04-24 18:50:12 -04006560 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006561 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04006562
Christoph Studerb82bc782014-08-20 14:29:43 +02006563 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
6564
Julia Reynoldsb852e562017-06-06 16:14:18 -04006565 public NotificationListeners(IPackageManager pm) {
6566 super(getContext(), mNotificationLock, mUserProfiles, pm);
6567
John Spurlock7340fc82014-04-24 18:50:12 -04006568 }
6569
6570 @Override
Amith Yamasanib7358302018-09-05 18:52:35 -07006571 protected int getBindFlags() {
6572 // Most of the same flags as the base, but also add BIND_ADJUST_BELOW_PERCEPTIBLE
6573 // because too many 3P apps could be kept in memory as notification listeners and
6574 // cause extreme memory pressure.
6575 // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation.
6576 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
6577 | BIND_ADJUST_BELOW_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
6578 }
6579
6580 @Override
John Spurlock7340fc82014-04-24 18:50:12 -04006581 protected Config getConfig() {
6582 Config c = new Config();
6583 c.caption = "notification listener";
6584 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006585 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04006586 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
6587 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
6588 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
6589 c.clientLabel = R.string.notification_listener_binding_label;
6590 return c;
6591 }
6592
6593 @Override
6594 protected IInterface asInterface(IBinder binder) {
6595 return INotificationListener.Stub.asInterface(binder);
6596 }
6597
6598 @Override
Chris Wren51017d02015-12-15 15:34:46 -05006599 protected boolean checkType(IInterface service) {
6600 return service instanceof INotificationListener;
6601 }
6602
6603 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04006604 public void onServiceAdded(ManagedServiceInfo info) {
6605 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04006606 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006607 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04006608 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006609 }
John Spurlock7340fc82014-04-24 18:50:12 -04006610 try {
Chris Wren333a61c2014-05-28 16:40:57 -04006611 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04006612 } catch (RemoteException e) {
6613 // we tried
6614 }
6615 }
6616
John Spurlock1fa865f2014-07-21 14:56:39 -04006617 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006618 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04006619 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07006620 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006621 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01006622 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04006623 }
Christoph Studerb82bc782014-08-20 14:29:43 +02006624 mLightTrimListeners.remove(removed);
6625 }
6626
Julia Reynolds88860ce2017-06-01 16:55:49 -04006627 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02006628 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
6629 if (trim == TRIM_LIGHT) {
6630 mLightTrimListeners.add(info);
6631 } else {
6632 mLightTrimListeners.remove(info);
6633 }
6634 }
6635
6636 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
6637 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04006638 }
6639
John Spurlock7340fc82014-04-24 18:50:12 -04006640 /**
6641 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02006642 *
6643 * <p>
6644 * Also takes care of removing a notification that has been visible to a listener before,
6645 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04006646 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006647 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006648 public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
6649 notifyPostedLocked(r, old, true);
Beverly5a20a5e2018-03-06 15:02:44 -05006650 }
6651
6652 /**
6653 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
6654 * targetting <= O_MR1
6655 */
6656 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006657 private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
Beverly5a20a5e2018-03-06 15:02:44 -05006658 boolean notifyAllListeners) {
Christoph Studerb82bc782014-08-20 14:29:43 +02006659 // Lazily initialized snapshots of the notification.
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006660 StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006661 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Chris Wren47633422016-01-22 09:56:59 -05006662 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02006663
Julia Reynolds00314d92017-04-14 10:01:24 -04006664 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02006665 boolean sbnVisible = isVisibleToListener(sbn, info);
6666 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
6667 // This notification hasn't been and still isn't visible -> ignore.
6668 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006669 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04006670 }
Beverly5a20a5e2018-03-06 15:02:44 -05006671 // If the notification is hidden, don't notifyPosted listeners targeting < P.
6672 // Instead, those listeners will receive notifyPosted when the notification is
6673 // unhidden.
6674 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
6675 continue;
6676 }
6677
6678 // If we shouldn't notify all listeners, this means the hidden state of
6679 // a notification was changed. Don't notifyPosted listeners targeting >= P.
6680 // Instead, those listeners will receive notifyRankingUpdate.
6681 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6682 continue;
6683 }
6684
Chris Wren333a61c2014-05-28 16:40:57 -04006685 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02006686
6687 // This notification became invisible -> remove the old one.
6688 if (oldSbnVisible && !sbnVisible) {
6689 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
6690 mHandler.post(new Runnable() {
6691 @Override
6692 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04006693 notifyRemoved(
6694 info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02006695 }
6696 });
Christoph Studer05ad4822014-05-16 14:16:03 +02006697 continue;
6698 }
Christoph Studercef37cf2014-07-25 14:18:17 +02006699
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006700 // Grant access before listener is notified
6701 final int targetUserId = (info.userid == UserHandle.USER_ALL)
6702 ? UserHandle.USER_SYSTEM : info.userid;
6703 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006704
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006705 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006706 mHandler.post(new Runnable() {
6707 @Override
6708 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02006709 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02006710 }
6711 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006712 }
6713 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006714
John Spurlock7340fc82014-04-24 18:50:12 -04006715 /**
6716 * asynchronously notify all listeners about a removed notification
6717 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006718 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05006719 public void notifyRemovedLocked(NotificationRecord r, int reason,
Julia Reynolds503ed942017-10-04 16:04:56 -04006720 NotificationStats notificationStats) {
Beverly5a20a5e2018-03-06 15:02:44 -05006721 final StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006722
John Spurlock7340fc82014-04-24 18:50:12 -04006723 // make a copy in case changes are made to the underlying Notification object
6724 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
6725 // notification
6726 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04006727 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02006728 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006729 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04006730 }
Beverly5a20a5e2018-03-06 15:02:44 -05006731
6732 // don't notifyRemoved for listeners targeting < P
6733 // if not for reason package suspended
6734 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
6735 && info.targetSdkVersion < Build.VERSION_CODES.P) {
6736 continue;
6737 }
6738
6739 // don't notifyRemoved for listeners targeting >= P
6740 // if the reason is package suspended
6741 if (reason == REASON_PACKAGE_SUSPENDED
6742 && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6743 continue;
6744 }
6745
Julia Reynolds503ed942017-10-04 16:04:56 -04006746 // Only assistants can get stats
6747 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
6748 ? notificationStats : null;
Chris Wren333a61c2014-05-28 16:40:57 -04006749 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006750 mHandler.post(new Runnable() {
6751 @Override
6752 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04006753 notifyRemoved(info, sbnLight, update, stats, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02006754 }
6755 });
Chris Wrenf9536642014-04-17 10:01:54 -04006756 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006757
6758 // Revoke access after all listeners have been updated
6759 mHandler.post(() -> {
6760 updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM);
6761 });
Chris Wrenf9536642014-04-17 10:01:54 -04006762 }
6763
6764 /**
Beverly5a20a5e2018-03-06 15:02:44 -05006765 * Asynchronously notify all listeners about a reordering of notifications
6766 * unless changedHiddenNotifications is populated.
6767 * If changedHiddenNotifications is populated, there was a change in the hidden state
6768 * of the notifications. In this case, we only send updates to listeners that
6769 * target >= P.
Chris Wrenf9536642014-04-17 10:01:54 -04006770 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006771 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05006772 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
6773 boolean isHiddenRankingUpdate = changedHiddenNotifications != null
6774 && changedHiddenNotifications.size() > 0;
6775
Julia Reynolds00314d92017-04-14 10:01:24 -04006776 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006777 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6778 continue;
6779 }
Beverly5a20a5e2018-03-06 15:02:44 -05006780
6781 boolean notifyThisListener = false;
6782 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
6783 Build.VERSION_CODES.P) {
6784 for (NotificationRecord rec : changedHiddenNotifications) {
6785 if (isVisibleToListener(rec.sbn, serviceInfo)) {
6786 notifyThisListener = true;
6787 break;
6788 }
John Spurlock7340fc82014-04-24 18:50:12 -04006789 }
Beverly5a20a5e2018-03-06 15:02:44 -05006790 }
6791
6792 if (notifyThisListener || !isHiddenRankingUpdate) {
6793 final NotificationRankingUpdate update = makeRankingUpdateLocked(
6794 serviceInfo);
6795
6796 mHandler.post(new Runnable() {
6797 @Override
6798 public void run() {
6799 notifyRankingUpdate(serviceInfo, update);
6800 }
6801 });
6802 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006803 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006804 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006805
Julia Reynolds88860ce2017-06-01 16:55:49 -04006806 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04006807 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006808 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04006809 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6810 continue;
6811 }
6812 mHandler.post(new Runnable() {
6813 @Override
6814 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006815 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006816 }
6817 });
6818 }
6819 }
6820
Beverly5a20a5e2018-03-06 15:02:44 -05006821 /**
6822 * asynchronously notify relevant listeners their notification is hidden
6823 * NotificationListenerServices that target P+:
6824 * NotificationListenerService#notifyRankingUpdateLocked()
6825 * NotificationListenerServices that target <= P:
6826 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
6827 */
6828 @GuardedBy("mNotificationLock")
6829 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
6830 if (changedNotifications == null || changedNotifications.size() == 0) {
6831 return;
6832 }
6833
6834 notifyRankingUpdateLocked(changedNotifications);
6835
6836 // for listeners that target < P, notifyRemoveLocked
6837 int numChangedNotifications = changedNotifications.size();
6838 for (int i = 0; i < numChangedNotifications; i++) {
6839 NotificationRecord rec = changedNotifications.get(i);
6840 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
6841 }
6842 }
6843
6844 /**
6845 * asynchronously notify relevant listeners their notification is unhidden
6846 * NotificationListenerServices that target P+:
6847 * NotificationListenerService#notifyRankingUpdateLocked()
6848 * NotificationListenerServices that target <= P:
6849 * NotificationListeners#notifyPostedLocked()
6850 */
6851 @GuardedBy("mNotificationLock")
6852 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
6853 if (changedNotifications == null || changedNotifications.size() == 0) {
6854 return;
6855 }
6856
6857 notifyRankingUpdateLocked(changedNotifications);
6858
6859 // for listeners that target < P, notifyPostedLocked
6860 int numChangedNotifications = changedNotifications.size();
6861 for (int i = 0; i < numChangedNotifications; i++) {
6862 NotificationRecord rec = changedNotifications.get(i);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006863 mListeners.notifyPostedLocked(rec, rec, false);
Beverly5a20a5e2018-03-06 15:02:44 -05006864 }
6865 }
6866
Christoph Studer85a384b2014-08-27 20:16:15 +02006867 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006868 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02006869 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6870 continue;
6871 }
6872 mHandler.post(new Runnable() {
6873 @Override
6874 public void run() {
6875 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
6876 }
6877 });
6878 }
6879 }
6880
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006881 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006882 final NotificationChannel channel, final int modificationType) {
6883 if (channel == null) {
6884 return;
6885 }
6886 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04006887 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006888 continue;
6889 }
Julia Reynolds018aa622017-04-20 11:31:30 -04006890
Eugene Suslaa25d17f2017-08-24 11:28:08 -07006891 BackgroundThread.getHandler().post(() -> {
6892 if (hasCompanionDevice(serviceInfo)) {
6893 notifyNotificationChannelChanged(
6894 serviceInfo, pkg, user, channel, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04006895 }
6896 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006897 }
6898 }
6899
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006900 protected void notifyNotificationChannelGroupChanged(
6901 final String pkg, final UserHandle user, final NotificationChannelGroup group,
6902 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006903 if (group == null) {
6904 return;
6905 }
6906 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04006907 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006908 continue;
6909 }
Julia Reynolds018aa622017-04-20 11:31:30 -04006910
Eugene Suslaa25d17f2017-08-24 11:28:08 -07006911 BackgroundThread.getHandler().post(() -> {
6912 if (hasCompanionDevice(serviceInfo)) {
6913 notifyNotificationChannelGroupChanged(
6914 serviceInfo, pkg, user, group, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04006915 }
6916 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006917 }
6918 }
6919
Christoph Studercef37cf2014-07-25 14:18:17 +02006920 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02006921 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04006922 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006923 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04006924 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07006925 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04006926 } catch (RemoteException ex) {
6927 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
6928 }
6929 }
6930
Christoph Studercef37cf2014-07-25 14:18:17 +02006931 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds503ed942017-10-04 16:04:56 -04006932 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04006933 if (!info.enabledAndUserMatches(sbn.getUserId())) {
6934 return;
6935 }
Christoph Studer05ad4822014-05-16 14:16:03 +02006936 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006937 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04006938 try {
Julia Reynolds503ed942017-10-04 16:04:56 -04006939 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04006940 } catch (RemoteException ex) {
6941 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04006942 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006943 }
Chris Wrenf9536642014-04-17 10:01:54 -04006944
Christoph Studer05ad4822014-05-16 14:16:03 +02006945 private void notifyRankingUpdate(ManagedServiceInfo info,
6946 NotificationRankingUpdate rankingUpdate) {
6947 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04006948 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02006949 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04006950 } catch (RemoteException ex) {
6951 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
6952 }
6953 }
John Spurlock1fa865f2014-07-21 14:56:39 -04006954
John Spurlockd8afe3c2014-08-01 14:04:07 -04006955 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04006956 final INotificationListener listener = (INotificationListener) info.service;
6957 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006958 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006959 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006960 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04006961 }
6962 }
Justin Koh38156c52014-06-04 13:57:49 -07006963
Christoph Studer85a384b2014-08-27 20:16:15 +02006964 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
6965 int interruptionFilter) {
6966 final INotificationListener listener = (INotificationListener) info.service;
6967 try {
6968 listener.onInterruptionFilterChanged(interruptionFilter);
6969 } catch (RemoteException ex) {
6970 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
6971 }
6972 }
6973
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006974 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006975 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006976 final int modificationType) {
6977 final INotificationListener listener = (INotificationListener) info.service;
6978 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006979 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006980 } catch (RemoteException ex) {
6981 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
6982 }
6983 }
6984
6985 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006986 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006987 final int modificationType) {
6988 final INotificationListener listener = (INotificationListener) info.service;
6989 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006990 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006991 } catch (RemoteException ex) {
6992 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
6993 }
6994 }
6995
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006996 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07006997 if (packageName == null) {
6998 return false;
6999 }
7000 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007001 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04007002 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07007003 if (packageName.equals(serviceInfo.component.getPackageName())) {
7004 return true;
7005 }
7006 }
7007 }
7008 return false;
7009 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007010 }
John Spurlock25e2d242014-06-27 13:58:23 -04007011
7012 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04007013 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04007014 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04007015 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04007016 public long since;
7017 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04007018 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05007019 public boolean proto = false;
Vishnu Naire3e4d252018-03-01 11:26:57 -08007020 public boolean criticalPriority = false;
7021 public boolean normalPriority = false;
John Spurlock25e2d242014-06-27 13:58:23 -04007022
Kweku Adams887f09c2017-11-13 17:12:20 -08007023 @NonNull
John Spurlock25e2d242014-06-27 13:58:23 -04007024 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04007025 final DumpFilter filter = new DumpFilter();
7026 for (int ai = 0; ai < args.length; ai++) {
7027 final String a = args[ai];
Kweku Adams62b42242017-09-25 12:54:02 -07007028 if ("--proto".equals(a)) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05007029 filter.proto = true;
Kweku Adams62b42242017-09-25 12:54:02 -07007030 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
Dan Sandlera1770312015-07-10 13:59:29 -04007031 filter.redact = false;
7032 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
7033 if (ai < args.length-1) {
7034 ai++;
7035 filter.pkgFilter = args[ai].trim().toLowerCase();
7036 if (filter.pkgFilter.isEmpty()) {
7037 filter.pkgFilter = null;
7038 } else {
7039 filter.filtered = true;
7040 }
7041 }
7042 } else if ("--zen".equals(a) || "zen".equals(a)) {
7043 filter.filtered = true;
7044 filter.zen = true;
7045 } else if ("--stats".equals(a)) {
7046 filter.stats = true;
7047 if (ai < args.length-1) {
7048 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01007049 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04007050 } else {
7051 filter.since = 0;
7052 }
Vishnu Naire3e4d252018-03-01 11:26:57 -08007053 } else if (PRIORITY_ARG.equals(a)) {
7054 // Bugreport will call the service twice with priority arguments, first to dump
7055 // critical sections and then non critical ones. Set approriate filters
7056 // to generate the desired data.
7057 if (ai < args.length - 1) {
7058 ai++;
7059 switch (args[ai]) {
7060 case PRIORITY_ARG_CRITICAL:
7061 filter.criticalPriority = true;
7062 break;
7063 case PRIORITY_ARG_NORMAL:
7064 filter.normalPriority = true;
7065 break;
7066 }
7067 }
Dan Sandlera1770312015-07-10 13:59:29 -04007068 }
John Spurlock25e2d242014-06-27 13:58:23 -04007069 }
Dan Sandlera1770312015-07-10 13:59:29 -04007070 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04007071 }
7072
7073 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04007074 if (!filtered) return true;
7075 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04007076 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04007077 }
7078
7079 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04007080 if (!filtered) return true;
7081 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04007082 }
7083
7084 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04007085 if (!filtered) return true;
7086 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04007087 }
7088
7089 @Override
7090 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04007091 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04007092 }
7093 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07007094
Beverly5a20a5e2018-03-06 15:02:44 -05007095 @VisibleForTesting
7096 protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
7097 // only use for testing: mimic receive broadcast that package is (un)suspended
7098 // but does not actually (un)suspend the package
7099 final Bundle extras = new Bundle();
7100 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
7101 new String[]{pkg});
7102
7103 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
Beverlyc7858552018-09-14 09:49:07 -04007104 : Intent.ACTION_PACKAGES_UNSUSPENDED;
Beverly5a20a5e2018-03-06 15:02:44 -05007105 final Intent intent = new Intent(action);
7106 intent.putExtras(extras);
7107
7108 mPackageIntentReceiver.onReceive(getContext(), intent);
7109 }
7110
Griff Hazen84a00ea2014-09-02 17:10:47 -07007111 /**
7112 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
7113 * binder without sending large amounts of data over a oneway transaction.
7114 */
7115 private static final class StatusBarNotificationHolder
7116 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07007117 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007118
7119 public StatusBarNotificationHolder(StatusBarNotification value) {
7120 mValue = value;
7121 }
7122
Griff Hazene9aac5f2014-09-05 20:04:09 -07007123 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07007124 @Override
7125 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07007126 StatusBarNotification value = mValue;
7127 mValue = null;
7128 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007129 }
7130 }
John Spurlock7c74f782015-06-04 13:01:42 -04007131
Julia Reynoldsb852e562017-06-06 16:14:18 -04007132 private class ShellCmd extends ShellCommand {
7133 public static final String USAGE = "help\n"
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007134 + "allow_listener COMPONENT [user_id]\n"
7135 + "disallow_listener COMPONENT [user_id]\n"
Julia Reynolds7380d872018-01-12 10:28:26 -05007136 + "allow_assistant COMPONENT\n"
Julia Reynoldseb3dca72017-07-11 10:39:58 -04007137 + "remove_assistant COMPONENT\n"
Julia Reynoldsb852e562017-06-06 16:14:18 -04007138 + "allow_dnd PACKAGE\n"
Beverly5a20a5e2018-03-06 15:02:44 -05007139 + "disallow_dnd PACKAGE\n"
7140 + "suspend_package PACKAGE\n"
7141 + "unsuspend_package PACKAGE";
John Spurlock7c74f782015-06-04 13:01:42 -04007142
Julia Reynoldsb852e562017-06-06 16:14:18 -04007143 @Override
7144 public int onCommand(String cmd) {
Felipe Leme68d80412017-07-14 11:18:08 -07007145 if (cmd == null) {
7146 return handleDefaultCommands(cmd);
7147 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007148 final PrintWriter pw = getOutPrintWriter();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04007149 try {
Julia Reynoldsb852e562017-06-06 16:14:18 -04007150 switch (cmd) {
7151 case "allow_dnd": {
7152 getBinderService().setNotificationPolicyAccessGranted(
7153 getNextArgRequired(), true);
John Spurlock7c74f782015-06-04 13:01:42 -04007154 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04007155 break;
7156
7157 case "disallow_dnd": {
7158 getBinderService().setNotificationPolicyAccessGranted(
7159 getNextArgRequired(), false);
7160 }
7161 break;
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007162 case "allow_listener": {
7163 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7164 if (cn == null) {
7165 pw.println("Invalid listener - must be a ComponentName");
7166 return -1;
7167 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007168 String userId = getNextArg();
7169 if (userId == null) {
7170 getBinderService().setNotificationListenerAccessGranted(cn, true);
7171 } else {
7172 getBinderService().setNotificationListenerAccessGrantedForUser(
7173 cn, Integer.parseInt(userId), true);
7174 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007175 }
7176 break;
7177 case "disallow_listener": {
7178 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7179 if (cn == null) {
7180 pw.println("Invalid listener - must be a ComponentName");
7181 return -1;
7182 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007183 String userId = getNextArg();
7184 if (userId == null) {
7185 getBinderService().setNotificationListenerAccessGranted(cn, false);
7186 } else {
7187 getBinderService().setNotificationListenerAccessGrantedForUser(
7188 cn, Integer.parseInt(userId), false);
7189 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007190 }
7191 break;
Julia Reynoldseb3dca72017-07-11 10:39:58 -04007192 case "allow_assistant": {
7193 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7194 if (cn == null) {
7195 pw.println("Invalid assistant - must be a ComponentName");
7196 return -1;
7197 }
7198 getBinderService().setNotificationAssistantAccessGranted(cn, true);
7199 }
7200 break;
7201 case "disallow_assistant": {
7202 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7203 if (cn == null) {
7204 pw.println("Invalid assistant - must be a ComponentName");
7205 return -1;
7206 }
7207 getBinderService().setNotificationAssistantAccessGranted(cn, false);
7208 }
7209 break;
Beverly5a20a5e2018-03-06 15:02:44 -05007210 case "suspend_package": {
7211 // only use for testing
7212 simulatePackageSuspendBroadcast(true, getNextArgRequired());
7213 }
7214 break;
7215 case "unsuspend_package": {
7216 // only use for testing
7217 simulatePackageSuspendBroadcast(false, getNextArgRequired());
7218 }
7219 break;
Julia Reynoldsb852e562017-06-06 16:14:18 -04007220 default:
7221 return handleDefaultCommands(cmd);
John Spurlock7c74f782015-06-04 13:01:42 -04007222 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007223 } catch (Exception e) {
7224 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
Julia Reynoldsb852e562017-06-06 16:14:18 -04007225 Slog.e(TAG, "Error running shell command", e);
John Spurlock7c74f782015-06-04 13:01:42 -04007226 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04007227 return 0;
John Spurlock7c74f782015-06-04 13:01:42 -04007228 }
7229
Julia Reynoldsb852e562017-06-06 16:14:18 -04007230 @Override
7231 public void onHelp() {
7232 getOutPrintWriter().println(USAGE);
John Spurlock7c74f782015-06-04 13:01:42 -04007233 }
7234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007235}