blob: ef468617bd6aa83fdecef031c5b9cd03b55efc76 [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 Yamasanie1fb58d2018-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
1249 void setVibrator(Vibrator vibrator) {
1250 mVibrator = vibrator;
1251 }
1252
1253 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001254 void setLights(Light light) {
1255 mNotificationLight = light;
1256 mAttentionLight = light;
Julia Reynolds033a4122017-01-31 16:50:38 -05001257 mNotificationPulseEnabled = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001258 }
1259
1260 @VisibleForTesting
1261 void setScreenOn(boolean on) {
1262 mScreenOn = on;
1263 }
1264
1265 @VisibleForTesting
Julia Reynolds080361e2017-07-13 11:23:12 -04001266 int getNotificationRecordCount() {
1267 synchronized (mNotificationLock) {
1268 int count = mNotificationList.size() + mNotificationsByKey.size()
1269 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1270 // subtract duplicates
1271 for (NotificationRecord posted : mNotificationList) {
1272 if (mNotificationsByKey.containsKey(posted.getKey())) {
1273 count--;
1274 }
1275 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001276 count--;
Julia Reynolds080361e2017-07-13 11:23:12 -04001277 }
1278 }
1279
1280 return count;
1281 }
1282 }
1283
Julia Reynolds7380d872018-01-12 10:28:26 -05001284 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001285 void clearNotifications() {
1286 mEnqueuedNotifications.clear();
1287 mNotificationList.clear();
1288 mNotificationsByKey.clear();
1289 mSummaryByGroupKey.clear();
1290 }
1291
Julia Reynolds080361e2017-07-13 11:23:12 -04001292 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001293 void addNotification(NotificationRecord r) {
1294 mNotificationList.add(r);
1295 mNotificationsByKey.put(r.sbn.getKey(), r);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001296 if (r.sbn.isGroup()) {
1297 mSummaryByGroupKey.put(r.getGroupKey(), r);
1298 }
1299 }
1300
1301 @VisibleForTesting
1302 void addEnqueuedNotification(NotificationRecord r) {
1303 mEnqueuedNotifications.add(r);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001304 }
1305
1306 @VisibleForTesting
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001307 NotificationRecord getNotificationRecord(String key) {
1308 return mNotificationsByKey.get(key);
1309 }
1310
1311
1312 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001313 void setSystemReady(boolean systemReady) {
1314 mSystemReady = systemReady;
1315 }
1316
1317 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001318 void setHandler(WorkerHandler handler) {
Chris Wren93bb8b82016-03-29 14:35:05 -04001319 mHandler = handler;
1320 }
1321
Chris Wrend4054312016-06-24 17:07:40 -04001322 @VisibleForTesting
Julia Reynolds0c299d42016-11-15 14:37:04 -05001323 void setFallbackVibrationPattern(long[] vibrationPattern) {
1324 mFallbackVibrationPattern = vibrationPattern;
Chris Wrend4054312016-06-24 17:07:40 -04001325 }
1326
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001327 @VisibleForTesting
1328 void setPackageManager(IPackageManager packageManager) {
1329 mPackageManager = packageManager;
1330 }
1331
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001332 @VisibleForTesting
1333 void setRankingHelper(RankingHelper rankingHelper) {
1334 mRankingHelper = rankingHelper;
1335 }
1336
1337 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001338 void setRankingHandler(RankingHandler rankingHandler) {
1339 mRankingHandler = rankingHandler;
1340 }
1341
1342 @VisibleForTesting
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001343 void setIsTelevision(boolean isTelevision) {
1344 mIsTelevision = isTelevision;
1345 }
1346
Julia Reynolds76c096d2017-06-19 08:16:04 -04001347 @VisibleForTesting
1348 void setUsageStats(NotificationUsageStats us) {
1349 mUsageStats = us;
1350 }
1351
Julia Reynolds94187562017-10-10 13:58:49 -04001352 @VisibleForTesting
1353 void setAccessibilityManager(AccessibilityManager am) {
1354 mAccessibilityManager = am;
1355 }
1356
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001357 // TODO: All tests should use this init instead of the one-off setters above.
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001358 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001359 void init(Looper looper, IPackageManager packageManager,
1360 PackageManager packageManagerClient,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001361 LightsManager lightsManager, NotificationListeners notificationListeners,
Julia Reynoldsb852e562017-06-06 16:14:18 -04001362 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001363 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
Julia Reynolds68263d12017-06-21 14:21:19 -04001364 NotificationUsageStats usageStats, AtomicFile policyFile,
Julia Reynolds7217dc92018-03-07 12:12:09 -05001365 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
Jason Parks50322ff2018-03-27 10:23:33 -05001366 UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm) {
Chris Wren54bbef42014-07-09 18:37:56 -04001367 Resources resources = getContext().getResources();
Chris Wren763a9bb2016-05-31 17:14:12 -04001368 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1369 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1370 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1371
Julia Reynolds94187562017-10-10 13:58:49 -04001372 mAccessibilityManager =
1373 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001374 mAm = am;
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001375 mPackageManager = packageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001376 mPackageManagerClient = packageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001377 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1378 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Julia Reynolds7217dc92018-03-07 12:12:09 -05001379 mAppUsageStats = appUsageStats;
Julia Reynolds2a128742016-11-28 14:29:25 -05001380 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001381 mCompanionManager = companionManager;
Julia Reynolds68263d12017-06-21 14:21:19 -04001382 mActivityManager = activityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -08001383 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1384 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
Jason Parks50322ff2018-03-27 10:23:33 -05001385 mDpm = dpm;
1386
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001387 mHandler = new WorkerHandler(looper);
Chris Wrenf9536642014-04-17 10:01:54 -04001388 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -04001389 String[] extractorNames;
1390 try {
1391 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1392 } catch (Resources.NotFoundException e) {
1393 extractorNames = new String[0];
1394 }
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001395 mUsageStats = usageStats;
Kenny Guy23991102018-04-05 21:18:38 +01001396 mMetricsLogger = new MetricsLogger();
Chris Wren51017d02015-12-15 15:34:46 -05001397 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Julia Reynoldsb852e562017-06-06 16:14:18 -04001398 mConditionProviders = conditionProviders;
John Spurlockb2278d62015-04-07 12:47:12 -04001399 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -04001400 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -04001401 @Override
1402 public void onConfigChanged() {
1403 savePolicyFile();
1404 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001405
1406 @Override
1407 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001408 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -05001409 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -05001410 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1411 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -05001412 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001413 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02001414 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001415 }
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001416 mRankingHandler.requestSort();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001417 }
John Spurlock1fc476d2015-04-14 16:05:20 -04001418
1419 @Override
1420 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001421 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001422 mRankingHandler.requestSort();
John Spurlock80774932015-05-07 17:38:50 -04001423 }
John Spurlock056c5192014-04-20 21:52:01 -04001424 });
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001425 mRankingHelper = new RankingHelper(getContext(),
1426 mPackageManagerClient,
1427 mRankingHandler,
1428 mZenModeHelper,
1429 mUsageStats,
1430 extractorNames);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001431 mSnoozeHelper = snoozeHelper;
Julia Reynolds8aebf352017-06-26 11:35:33 -04001432 mGroupHelper = groupHelper;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04001433
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001434 // This is a ManagedServices object that keeps track of the listeners.
1435 mListeners = notificationListeners;
Chris Wren0efdb882016-03-01 17:17:47 -05001436
Julia Reynolds77b2cc92016-11-08 14:41:09 -05001437 // This is a MangedServices object that keeps track of the assistant.
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001438 mAssistants = notificationAssistants;
Julia Reynoldsb852e562017-06-06 16:14:18 -04001439
Kristian Monsen30f59b22018-04-09 10:27:16 +02001440 // Needs to be set before loadPolicyFile
1441 mAllowedManagedServicePackages = this::canUseManagedServices;
1442
Julia Reynoldsb852e562017-06-06 16:14:18 -04001443 mPolicyFile = policyFile;
1444 loadPolicyFile();
Chris Wren0efdb882016-03-01 17:17:47 -05001445
Adam Lesinski182f73f2013-12-05 16:48:06 -08001446 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -08001447 if (mStatusBar != null) {
1448 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1449 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001450
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001451 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1452 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001453
Daniel Sandleredbb3802012-11-13 20:49:47 -08001454 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001455 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001456 VIBRATE_PATTERN_MAXLEN,
1457 DEFAULT_VIBRATE_PATTERN);
Beverly5d463b62017-07-26 14:13:40 -04001458 mInCallNotificationUri = Uri.parse("file://" +
1459 resources.getString(R.string.config_inCallNotificationSound));
1460 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1461 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1462 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
Beverly5d463b62017-07-26 14:13:40 -04001463 .build();
1464 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1465
Chris Wren5116a822014-06-04 15:59:50 -04001466 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
Julia Reynolds54369232018-07-03 10:43:35 -04001467 mHasLight =
1468 resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
Chris Wren5116a822014-06-04 15:59:50 -04001469
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001470 // Don't start allowing notifications until the setup wizard has run once.
1471 // After that, including subsequent boots, init with notifications turned on.
1472 // This works on the first boot because the setup wizard will toggle this
1473 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001474 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001475 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001476 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001477 }
John Spurlockb2278d62015-04-07 12:47:12 -04001478 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001479 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001480
John Spurlockb408e8e2014-04-23 21:12:45 -04001481 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001482 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001483
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001484 mSettingsObserver = new SettingsObserver(mHandler);
1485
1486 mArchive = new Archive(resources.getInteger(
1487 R.integer.config_notificationServiceArchiveSize));
1488
1489 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1490 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1491 }
1492
1493 @Override
1494 public void onStart() {
1495 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1496 @Override
1497 public void repost(int userId, NotificationRecord r) {
1498 try {
1499 if (DBG) {
1500 Slog.d(TAG, "Reposting " + r.getKey());
1501 }
1502 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1503 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1504 r.sbn.getNotification(), userId);
1505 } catch (Exception e) {
1506 Slog.e(TAG, "Cannot un-snooze notification", e);
1507 }
1508 }
1509 }, mUserProfiles);
1510
1511 final File systemDir = new File(Environment.getDataDirectory(), "system");
1512
1513 init(Looper.myLooper(),
1514 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1515 getLocalService(LightsManager.class),
1516 new NotificationListeners(AppGlobals.getPackageManager()),
Julia Reynolds7380d872018-01-12 10:28:26 -05001517 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
1518 AppGlobals.getPackageManager()),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001519 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1520 null, snoozeHelper, new NotificationUsageStats(getContext()),
Dianne Hackborne17b4452018-01-10 13:15:40 -08001521 new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001522 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
Julia Reynolds7217dc92018-03-07 12:12:09 -05001523 getGroupHelper(), ActivityManager.getService(),
Jason Parks50322ff2018-03-27 10:23:33 -05001524 LocalServices.getService(UsageStatsManagerInternal.class),
1525 LocalServices.getService(DevicePolicyManagerInternal.class));
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001526
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001527 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001529 filter.addAction(Intent.ACTION_SCREEN_ON);
1530 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001531 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001532 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001533 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001534 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001535 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001536 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001537 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001538 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001539 getContext().registerReceiver(mIntentReceiver, filter);
Kenny Guy70058402014-10-28 20:45:06 +00001540
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001541 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001542 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001543 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001544 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001545 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1546 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1547 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001548 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1549 null);
1550
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001551 IntentFilter suspendedPkgFilter = new IntentFilter();
1552 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
Beverly5a20a5e2018-03-06 15:02:44 -05001553 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001554 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1555 suspendedPkgFilter, null, null);
1556
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001557 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001558 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1559 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001560
Julia Reynolds2a128742016-11-28 14:29:25 -05001561 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1562 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1563 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1564
Julia Reynoldsb852e562017-06-06 16:14:18 -04001565 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1566 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1567
Beverlyd4f96492017-08-02 13:36:11 -04001568 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1569 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1570
Vishnu Naire3e4d252018-03-01 11:26:57 -08001571 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
1572 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001573 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 }
1575
Julia Reynolds8aebf352017-06-26 11:35:33 -04001576 private GroupHelper getGroupHelper() {
1577 return new GroupHelper(new GroupHelper.Callback() {
1578 @Override
1579 public void addAutoGroup(String key) {
1580 synchronized (mNotificationLock) {
1581 addAutogroupKeyLocked(key);
1582 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001583 }
1584
1585 @Override
1586 public void removeAutoGroup(String key) {
1587 synchronized (mNotificationLock) {
1588 removeAutogroupKeyLocked(key);
1589 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001590 }
1591
1592 @Override
1593 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1594 createAutoGroupSummary(userId, pkg, triggeringKey);
1595 }
1596
1597 @Override
1598 public void removeAutoGroupSummary(int userId, String pkg) {
1599 synchronized (mNotificationLock) {
1600 clearAutogroupSummaryLocked(userId, pkg);
1601 }
1602 }
1603 });
1604 }
1605
John Spurlocke7a835b2015-05-13 10:47:05 -04001606 private void sendRegisteredOnlyBroadcast(String action) {
1607 getContext().sendBroadcastAsUser(new Intent(action)
1608 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1609 }
1610
Adam Lesinski182f73f2013-12-05 16:48:06 -08001611 @Override
1612 public void onBootPhase(int phase) {
1613 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1614 // no beeping until we're basically done booting
1615 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001616
Adam Lesinski182f73f2013-12-05 16:48:06 -08001617 // Grab our optional AudioService
1618 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001619 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001620 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001621 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001622 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1623 // This observer will force an update when observe is called, causing us to
1624 // bind to listener services.
1625 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001626 mListeners.onBootPhaseAppsCanStart();
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001627 mAssistants.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001628 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 }
1630 }
1631
Julia Reynolds88860ce2017-06-01 16:55:49 -04001632 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04001633 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001634 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001635 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001636 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001637 mListenerHints = hints;
1638 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001639 }
1640
Julia Reynolds88860ce2017-06-01 16:55:49 -04001641 @GuardedBy("mNotificationLock")
John Spurlockb4782522014-08-22 14:54:46 -04001642 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001643 final long updatedSuppressedEffects = calculateSuppressedEffects();
1644 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1645 final List<ComponentName> suppressors = getSuppressors();
1646 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1647 mEffectsSuppressors = suppressors;
1648 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001649 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001650 }
1651
Amith Yamasani396a10c2018-01-19 10:58:07 -08001652 private void exitIdle() {
1653 try {
1654 if (mDeviceIdleController != null) {
1655 mDeviceIdleController.exitIdle("notification interaction");
1656 }
1657 } catch (RemoteException e) {
1658 }
1659 }
1660
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001661 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1662 boolean fromListener) {
Julia Reynolds924eed12017-01-19 09:52:07 -05001663 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1664 // cancel
1665 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001666 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
Julia Reynolds924eed12017-01-19 09:52:07 -05001667 null);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001668 if (isUidSystemOrPhone(uid)) {
1669 int[] profileIds = mUserProfiles.getCurrentProfileIds();
1670 int N = profileIds.length;
1671 for (int i = 0; i < N; i++) {
1672 int profileId = profileIds[i];
1673 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1674 profileId, REASON_CHANNEL_BANNED,
1675 null);
1676 }
1677 }
Julia Reynolds924eed12017-01-19 09:52:07 -05001678 }
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001679 final NotificationChannel preUpdate =
1680 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
1681
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001682 mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001683 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
Julia Reynolds924eed12017-01-19 09:52:07 -05001684
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001685 if (!fromListener) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001686 final NotificationChannel modifiedChannel =
1687 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001688 mListeners.notifyNotificationChannelChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001689 pkg, UserHandle.getUserHandleForUid(uid),
1690 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001691 }
1692
Julia Reynolds924eed12017-01-19 09:52:07 -05001693 savePolicyFile();
1694 }
1695
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001696 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1697 NotificationChannel update) {
1698 try {
1699 if ((preUpdate.getImportance() == IMPORTANCE_NONE
1700 && update.getImportance() != IMPORTANCE_NONE)
1701 || (preUpdate.getImportance() != IMPORTANCE_NONE
1702 && update.getImportance() == IMPORTANCE_NONE)) {
1703 getContext().sendBroadcastAsUser(
1704 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001705 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001706 update.getId())
1707 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1708 update.getImportance() == IMPORTANCE_NONE)
1709 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1710 .setPackage(pkg),
1711 UserHandle.of(UserHandle.getUserId(uid)), null);
1712 }
1713 } catch (SecurityException e) {
1714 Slog.w(TAG, "Can't notify app about channel change", e);
1715 }
1716 }
1717
Julia Reynolds005c8b92017-08-24 10:35:53 -04001718 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
1719 boolean fromApp, boolean fromListener) {
1720 Preconditions.checkNotNull(group);
1721 Preconditions.checkNotNull(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001722
1723 final NotificationChannelGroup preUpdate =
1724 mRankingHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
Julia Reynolds005c8b92017-08-24 10:35:53 -04001725 mRankingHelper.createNotificationChannelGroup(pkg, uid, group,
1726 fromApp);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001727 if (!fromApp) {
1728 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
1729 }
Julia Reynolds005c8b92017-08-24 10:35:53 -04001730 if (!fromListener) {
1731 mListeners.notifyNotificationChannelGroupChanged(pkg,
1732 UserHandle.of(UserHandle.getCallingUserId()), group,
1733 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1734 }
1735 }
1736
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001737 private void maybeNotifyChannelGroupOwner(String pkg, int uid,
1738 NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
1739 try {
1740 if (preUpdate.isBlocked() != update.isBlocked()) {
1741 getContext().sendBroadcastAsUser(
1742 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001743 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001744 update.getId())
1745 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1746 update.isBlocked())
1747 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1748 .setPackage(pkg),
1749 UserHandle.of(UserHandle.getUserId(uid)), null);
1750 }
1751 } catch (SecurityException e) {
1752 Slog.w(TAG, "Can't notify app about group change", e);
1753 }
1754 }
1755
Bryce Lee7219ada2016-04-08 10:54:23 -07001756 private ArrayList<ComponentName> getSuppressors() {
1757 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1758 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1759 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1760
1761 for (ManagedServiceInfo info : serviceInfoList) {
1762 names.add(info.component);
1763 }
1764 }
1765
1766 return names;
1767 }
1768
1769 private boolean removeDisabledHints(ManagedServiceInfo info) {
1770 return removeDisabledHints(info, 0);
1771 }
1772
1773 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1774 boolean removed = false;
1775
1776 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1777 final int hint = mListenersDisablingEffects.keyAt(i);
1778 final ArraySet<ManagedServiceInfo> listeners =
1779 mListenersDisablingEffects.valueAt(i);
1780
1781 if (hints == 0 || (hint & hints) == hint) {
1782 removed = removed || listeners.remove(info);
1783 }
1784 }
1785
1786 return removed;
1787 }
1788
1789 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1790 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1791 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1792 }
1793
1794 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1795 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1796 }
1797
1798 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1799 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1800 }
1801 }
1802
1803 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1804 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1805 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1806 }
1807
1808 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1809 hintListeners.add(info);
1810 }
1811
1812 private int calculateHints() {
1813 int hints = 0;
1814 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1815 int hint = mListenersDisablingEffects.keyAt(i);
1816 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1817
1818 if (!serviceInfoList.isEmpty()) {
1819 hints |= hint;
1820 }
1821 }
1822
1823 return hints;
1824 }
1825
1826 private long calculateSuppressedEffects() {
1827 int hints = calculateHints();
1828 long suppressedEffects = 0;
1829
1830 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1831 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1832 }
1833
1834 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1835 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1836 }
1837
1838 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1839 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1840 }
1841
1842 return suppressedEffects;
1843 }
1844
Julia Reynolds88860ce2017-06-01 16:55:49 -04001845 @GuardedBy("mNotificationLock")
Christoph Studer85a384b2014-08-27 20:16:15 +02001846 private void updateInterruptionFilterLocked() {
1847 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1848 if (interruptionFilter == mInterruptionFilter) return;
1849 mInterruptionFilter = interruptionFilter;
1850 scheduleInterruptionFilterChanged(interruptionFilter);
1851 }
1852
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001853 @VisibleForTesting
1854 INotificationManager getBinderService() {
1855 return INotificationManager.Stub.asInterface(mService);
1856 }
1857
Amith Yamasani7ec89412018-02-07 08:48:49 -08001858 /**
1859 * Report to usage stats that the notification was seen.
1860 * @param r notification record
1861 */
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001862 @GuardedBy("mNotificationLock")
Amith Yamasani803eab692017-11-09 17:47:04 -08001863 protected void reportSeen(NotificationRecord r) {
Amith Yamasani803eab692017-11-09 17:47:04 -08001864 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001865 getRealUserId(r.sbn.getUserId()),
Amith Yamasani803eab692017-11-09 17:47:04 -08001866 UsageEvents.Event.NOTIFICATION_SEEN);
1867 }
1868
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001869 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
1870 int targetSdkVersion) {
1871 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
1872 return incomingPolicy.suppressedVisualEffects;
1873 }
1874 final int[] effectsIntroducedInP = {
1875 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
1876 SUPPRESSED_EFFECT_LIGHTS,
1877 SUPPRESSED_EFFECT_PEEK,
1878 SUPPRESSED_EFFECT_STATUS_BAR,
1879 SUPPRESSED_EFFECT_BADGE,
1880 SUPPRESSED_EFFECT_AMBIENT,
1881 SUPPRESSED_EFFECT_NOTIFICATION_LIST
1882 };
1883
1884 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06001885 if (targetSdkVersion < Build.VERSION_CODES.P) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001886 // unset higher order bits introduced in P, maintain the user's higher order bits
1887 for (int i = 0; i < effectsIntroducedInP.length ; i++) {
1888 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
1889 newSuppressedVisualEffects |=
1890 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
1891 }
1892 // set higher order bits according to lower order bits
1893 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1894 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1895 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001896 }
1897 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1898 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1899 }
1900 } else {
1901 boolean hasNewEffects = (newSuppressedVisualEffects
1902 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
1903 // if any of the new effects introduced in P are set
1904 if (hasNewEffects) {
1905 // clear out the deprecated effects
1906 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
1907 | SUPPRESSED_EFFECT_SCREEN_OFF);
1908
1909 // set the deprecated effects according to the new more specific effects
1910 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
1911 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
1912 }
1913 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
1914 && (newSuppressedVisualEffects
1915 & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
1916 && (newSuppressedVisualEffects
1917 & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
1918 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
1919 }
1920 } else {
1921 // set higher order bits according to lower order bits
1922 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1923 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1924 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
1925 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
1926 }
1927 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1928 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1929 }
1930 }
1931 }
1932
1933 return newSuppressedVisualEffects;
1934 }
1935
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001936 @GuardedBy("mNotificationLock")
1937 protected void maybeRecordInterruptionLocked(NotificationRecord r) {
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04001938 if (r.isInterruptive() && !r.hasRecordedInterruption()) {
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001939 mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
1940 r.getChannel().getId(),
1941 getRealUserId(r.sbn.getUserId()));
Julia Reynoldsad7d7132018-03-21 16:05:00 -04001942 logRecentLocked(r);
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04001943 r.setRecordedInterruption(true);
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001944 }
1945 }
1946
Amith Yamasani7ec89412018-02-07 08:48:49 -08001947 /**
1948 * Report to usage stats that the notification was clicked.
1949 * @param r notification record
1950 */
1951 protected void reportUserInteraction(NotificationRecord r) {
Amith Yamasani7ec89412018-02-07 08:48:49 -08001952 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001953 getRealUserId(r.sbn.getUserId()),
Amith Yamasani7ec89412018-02-07 08:48:49 -08001954 UsageEvents.Event.USER_INTERACTION);
1955 }
1956
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001957 private int getRealUserId(int userId) {
1958 return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
1959 }
1960
Geoffrey Pitsch415e4542017-04-10 13:12:58 -04001961 @VisibleForTesting
1962 NotificationManagerInternal getInternalService() {
1963 return mInternalService;
1964 }
1965
Adam Lesinski182f73f2013-12-05 16:48:06 -08001966 private final IBinder mService = new INotificationManager.Stub() {
1967 // Toasts
1968 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001971 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001972 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001973 if (DBG) {
1974 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1975 + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001977
1978 if (pkg == null || callback == null) {
1979 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1980 return ;
1981 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001982 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001983 final boolean isPackageSuspended =
1984 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
Adam Lesinski182f73f2013-12-05 16:48:06 -08001985
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001986 if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001987 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1988 || isPackageSuspended)) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001989 Slog.e(TAG, "Suppressing toast from package " + pkg
1990 + (isPackageSuspended
1991 ? " due to package suspended by administrator."
1992 : " by user request."));
1993 return;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001994 }
1995
1996 synchronized (mToastQueue) {
1997 int callingPid = Binder.getCallingPid();
1998 long callingId = Binder.clearCallingIdentity();
1999 try {
2000 ToastRecord record;
Beverly Tai98efc792018-06-11 14:50:36 +00002001 int index = indexOfToastLocked(pkg, callback);
2002 // If it's already in the queue, we update it in place, we don't
2003 // move it to the end of the queue.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002004 if (index >= 0) {
2005 record = mToastQueue.get(index);
2006 record.update(duration);
2007 } else {
Beverly Tai98efc792018-06-11 14:50:36 +00002008 // Limit the number of toasts that any given package except the android
2009 // package can enqueue. Prevents DOS attacks and deals with leaks.
2010 if (!isSystemToast) {
2011 int count = 0;
2012 final int N = mToastQueue.size();
2013 for (int i=0; i<N; i++) {
2014 final ToastRecord r = mToastQueue.get(i);
2015 if (r.pkg.equals(pkg)) {
2016 count++;
2017 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2018 Slog.e(TAG, "Package has already posted " + count
2019 + " toasts. Not showing more. Package=" + pkg);
2020 return;
2021 }
2022 }
2023 }
2024 }
2025
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002026 Binder token = new Binder();
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002027 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002028 record = new ToastRecord(callingPid, pkg, callback, duration, token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002029 mToastQueue.add(record);
2030 index = mToastQueue.size() - 1;
Beverly Tai98efc792018-06-11 14:50:36 +00002031 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002032 }
2033 // If it's at index 0, it's the current toast. It doesn't matter if it's
2034 // new or just been updated. Call back and tell it to show itself.
2035 // If the callback fails, this will remove it from the list, so don't
2036 // assume that it's valid after this.
2037 if (index == 0) {
2038 showNextToastLocked();
2039 }
2040 } finally {
2041 Binder.restoreCallingIdentity(callingId);
2042 }
2043 }
2044 }
2045
2046 @Override
2047 public void cancelToast(String pkg, ITransientNotification callback) {
2048 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
2049
2050 if (pkg == null || callback == null) {
2051 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
2052 return ;
2053 }
2054
2055 synchronized (mToastQueue) {
2056 long callingId = Binder.clearCallingIdentity();
2057 try {
2058 int index = indexOfToastLocked(pkg, callback);
2059 if (index >= 0) {
2060 cancelToastLocked(index);
2061 } else {
2062 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
2063 + " callback=" + callback);
2064 }
2065 } finally {
2066 Binder.restoreCallingIdentity(callingId);
2067 }
2068 }
2069 }
2070
2071 @Override
Robert Carr997427342018-02-28 18:06:10 -08002072 public void finishToken(String pkg, ITransientNotification callback) {
2073 synchronized (mToastQueue) {
2074 long callingId = Binder.clearCallingIdentity();
2075 try {
2076 int index = indexOfToastLocked(pkg, callback);
2077 if (index >= 0) {
2078 ToastRecord record = mToastQueue.get(index);
2079 finishTokenLocked(record.token);
2080 } else {
2081 Slog.w(TAG, "Toast already killed. pkg=" + pkg
2082 + " callback=" + callback);
2083 }
2084 } finally {
2085 Binder.restoreCallingIdentity(callingId);
2086 }
2087 }
2088 }
2089
2090 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002091 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002092 Notification notification, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002093 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002094 Binder.getCallingPid(), tag, id, notification, userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002095 }
2096
2097 @Override
2098 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002099 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002100 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2101 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002102 // Don't allow client applications to cancel foreground service notis or autobundled
2103 // summaries.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002104 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
Julia Reynoldse5c60452018-04-30 14:41:36 -04002105 (FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
John Spurlocke6a7d932014-03-13 12:29:00 -04002106 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002107 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002108 }
2109
2110 @Override
2111 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002112 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002113
2114 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2115 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
2116
2117 // Calling from user space, don't allow the canceling of actively
2118 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04002119 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
Julia Reynoldse5c60452018-04-30 14:41:36 -04002120 pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05002121 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002122 }
2123
2124 @Override
2125 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
Rohan Shahca0447e2018-03-30 15:18:27 -07002126 enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002127
Chris Wrenacf424a2016-03-15 12:48:55 -04002128 mRankingHelper.setEnabled(pkg, uid, enabled);
Howard Ro4db243a2018-08-07 15:44:25 -07002129 mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
2130 .setType(MetricsEvent.TYPE_ACTION)
2131 .setPackageName(pkg)
2132 .setSubtype(enabled ? 1 : 0));
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002133 // Now, cancel any outstanding notifications that are part of a just-disabled app
Julia Reynolds4da79702017-06-01 11:06:10 -04002134 if (!enabled) {
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002135 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
2136 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
2137 }
Julia Reynoldsfc9767b2018-01-22 17:45:16 -05002138
2139 try {
2140 getContext().sendBroadcastAsUser(
2141 new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
2142 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
2143 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2144 .setPackage(pkg),
2145 UserHandle.of(UserHandle.getUserId(uid)), null);
2146 } catch (SecurityException e) {
2147 Slog.w(TAG, "Can't notify app about app block change", e);
2148 }
2149
Chris Wrenacf424a2016-03-15 12:48:55 -04002150 savePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002151 }
2152
2153 /**
Rohan Shah590e1b22018-04-10 23:48:47 -04002154 * Updates the enabled state for notifications for the given package (and uid).
2155 * Additionally, this method marks the app importance as locked by the user, which means
2156 * that notifications from the app will <b>not</b> be considered for showing a
2157 * blocking helper.
2158 *
2159 * @param pkg package that owns the notifications to update
2160 * @param uid uid of the app providing notifications
2161 * @param enabled whether notifications should be enabled for the app
2162 *
2163 * @see #setNotificationsEnabledForPackage(String, int, boolean)
2164 */
2165 @Override
2166 public void setNotificationsEnabledWithImportanceLockForPackage(
2167 String pkg, int uid, boolean enabled) {
2168 setNotificationsEnabledForPackage(pkg, uid, enabled);
2169
2170 mRankingHelper.setAppImportanceLocked(pkg, uid);
2171 }
2172
2173 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002174 * Use this when you just want to know if notifications are OK for this package.
2175 */
2176 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002177 public boolean areNotificationsEnabled(String pkg) {
2178 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
2179 }
2180
2181 /**
2182 * Use this when you just want to know if notifications are OK for this package.
2183 */
2184 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002185 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002186 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002187
2188 return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002189 }
2190
Chris Wren54bbef42014-07-09 18:37:56 -04002191 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05002192 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002193 checkCallerIsSystemOrSameApp(pkg);
Julia Reynoldsef37f282016-02-12 09:11:27 -05002194 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002195 }
2196
2197 @Override
Julia Reynolds924eed12017-01-19 09:52:07 -05002198 public boolean canShowBadge(String pkg, int uid) {
2199 checkCallerIsSystem();
2200 return mRankingHelper.canShowBadge(pkg, uid);
2201 }
2202
2203 @Override
2204 public void setShowBadge(String pkg, int uid, boolean showBadge) {
2205 checkCallerIsSystem();
2206 mRankingHelper.setShowBadge(pkg, uid, showBadge);
2207 savePolicyFile();
2208 }
2209
2210 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002211 public void updateNotificationChannelGroupForPackage(String pkg, int uid,
2212 NotificationChannelGroup group) throws RemoteException {
2213 enforceSystemOrSystemUI("Caller not system or systemui");
2214 createNotificationChannelGroup(pkg, uid, group, false, false);
2215 savePolicyFile();
2216 }
2217
2218 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002219 public void createNotificationChannelGroups(String pkg,
2220 ParceledListSlice channelGroupList) throws RemoteException {
2221 checkCallerIsSystemOrSameApp(pkg);
2222 List<NotificationChannelGroup> groups = channelGroupList.getList();
2223 final int groupSize = groups.size();
2224 for (int i = 0; i < groupSize; i++) {
2225 final NotificationChannelGroup group = groups.get(i);
Julia Reynolds005c8b92017-08-24 10:35:53 -04002226 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002227 }
2228 savePolicyFile();
2229 }
2230
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002231 private void createNotificationChannelsImpl(String pkg, int uid,
2232 ParceledListSlice channelsList) {
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002233 List<NotificationChannel> channels = channelsList.getList();
2234 final int channelsSize = channels.size();
2235 for (int i = 0; i < channelsSize; i++) {
2236 final NotificationChannel channel = channels.get(i);
2237 Preconditions.checkNotNull(channel, "channel in list is null");
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002238 mRankingHelper.createNotificationChannel(pkg, uid, channel,
Julia Reynolds1fe10942018-03-28 12:46:51 -04002239 true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed(
2240 pkg, UserHandle.getUserId(uid)));
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002241 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002242 UserHandle.getUserHandleForUid(uid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002243 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
2244 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002245 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002246 savePolicyFile();
2247 }
2248
2249 @Override
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002250 public void createNotificationChannels(String pkg,
2251 ParceledListSlice channelsList) throws RemoteException {
2252 checkCallerIsSystemOrSameApp(pkg);
2253 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
2254 }
2255
2256 @Override
2257 public void createNotificationChannelsForPackage(String pkg, int uid,
2258 ParceledListSlice channelsList) throws RemoteException {
2259 checkCallerIsSystem();
2260 createNotificationChannelsImpl(pkg, uid, channelsList);
2261 }
2262
2263 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002264 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002265 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002266 return mRankingHelper.getNotificationChannel(
2267 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002268 }
2269
2270 @Override
2271 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002272 String channelId, boolean includeDeleted) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002273 checkCallerIsSystem();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002274 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002275 }
2276
2277 @Override
2278 public void deleteNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002279 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002280 final int callingUid = Binder.getCallingUid();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002281 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
2282 throw new IllegalArgumentException("Cannot delete default channel");
2283 }
2284 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002285 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
2286 mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
2287 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002288 UserHandle.getUserHandleForUid(callingUid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002289 mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
2290 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002291 savePolicyFile();
2292 }
2293
2294 @Override
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002295 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
2296 checkCallerIsSystemOrSameApp(pkg);
2297 return mRankingHelper.getNotificationChannelGroupWithChannels(
2298 pkg, Binder.getCallingUid(), groupId, false);
2299 }
2300
2301 @Override
Julia Reynolds9bfba592017-03-15 14:03:55 -04002302 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
2303 String pkg) {
2304 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds173a4822018-09-21 15:20:13 -04002305
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002306 return mRankingHelper.getNotificationChannelGroups(
Julia Reynolds173a4822018-09-21 15:20:13 -04002307 pkg, Binder.getCallingUid(), false, false, true);
Julia Reynolds9bfba592017-03-15 14:03:55 -04002308 }
2309
2310 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002311 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04002312 checkCallerIsSystemOrSameApp(pkg);
2313
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002314 final int callingUid = Binder.getCallingUid();
2315 NotificationChannelGroup groupToDelete =
2316 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
2317 if (groupToDelete != null) {
2318 List<NotificationChannel> deletedChannels =
2319 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
2320 for (int i = 0; i < deletedChannels.size(); i++) {
2321 final NotificationChannel deletedChannel = deletedChannels.get(i);
2322 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2323 true,
2324 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2325 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002326 mListeners.notifyNotificationChannelChanged(pkg,
2327 UserHandle.getUserHandleForUid(callingUid),
2328 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002329 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2330 }
2331 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002332 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2333 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002334 savePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002335 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04002336 }
2337
2338 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002339 public void updateNotificationChannelForPackage(String pkg, int uid,
2340 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002341 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05002342 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002343 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002344 }
2345
2346 @Override
2347 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002348 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002349 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002350 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002351 }
2352
2353 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002354 public int getNumNotificationChannelsForPackage(String pkg, int uid,
2355 boolean includeDeleted) {
2356 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
2357 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
2358 .getList().size();
2359 }
2360
2361 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04002362 public boolean onlyHasDefaultChannel(String pkg, int uid) {
2363 enforceSystemOrSystemUI("onlyHasDefaultChannel");
2364 return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
2365 }
2366
2367 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04002368 public int getDeletedChannelCount(String pkg, int uid) {
2369 enforceSystemOrSystemUI("getDeletedChannelCount");
2370 return mRankingHelper.getDeletedChannelCount(pkg, uid);
2371 }
2372
2373 @Override
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002374 public int getBlockedChannelCount(String pkg, int uid) {
2375 enforceSystemOrSystemUI("getBlockedChannelCount");
2376 return mRankingHelper.getBlockedChannelCount(pkg, uid);
2377 }
2378
2379 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002380 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2381 String pkg, int uid, boolean includeDeleted) {
2382 checkCallerIsSystem();
Julia Reynolds173a4822018-09-21 15:20:13 -04002383
2384 return mRankingHelper.getNotificationChannelGroups(
2385 pkg, uid, includeDeleted, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002386 }
2387
2388 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002389 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2390 String pkg, int uid, String groupId, boolean includeDeleted) {
2391 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
2392 return mRankingHelper.getNotificationChannelGroupWithChannels(
2393 pkg, uid, groupId, includeDeleted);
2394 }
2395
2396 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002397 public NotificationChannelGroup getNotificationChannelGroupForPackage(
2398 String groupId, String pkg, int uid) {
2399 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
2400 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
2401 }
2402
2403 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002404 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
2405 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002406 return mRankingHelper.getNotificationChannels(
2407 pkg, Binder.getCallingUid(), false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002408 }
2409
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002410 @Override
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05002411 public ParceledListSlice<NotifyingApp> getRecentNotifyingAppsForUser(int userId) {
2412 checkCallerIsSystem();
2413 synchronized (mNotificationLock) {
2414 List<NotifyingApp> apps = new ArrayList<>(
2415 mRecentApps.getOrDefault(userId, new ArrayList<>()));
2416 return new ParceledListSlice<>(apps);
2417 }
2418 }
2419
2420 @Override
Julia Reynoldse273f082018-04-12 13:48:49 -04002421 public int getBlockedAppCount(int userId) {
2422 checkCallerIsSystem();
2423 return mRankingHelper.getBlockedAppCount(userId);
2424 }
2425
2426 @Override
Beverly86d076f2018-04-17 14:44:52 -04002427 public boolean areChannelsBypassingDnd() {
2428 return mRankingHelper.areChannelsBypassingDnd();
2429 }
2430
2431 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05002432 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002433 checkCallerIsSystem();
2434
2435 // Cancel posted notifications
2436 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2437 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2438
Julia Reynoldsb852e562017-06-06 16:14:18 -04002439 final String[] packages = new String[] {packageName};
2440 final int[] uids = new int[] {uid};
2441
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002442 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04002443 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002444 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002445
2446 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04002447 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002448
2449 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05002450 if (!fromApp) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002451 mRankingHelper.onPackagesChanged(
2452 true, UserHandle.getCallingUserId(), packages, uids);
Julia Reynolds5355e852017-02-07 14:54:13 -05002453 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002454
2455 savePolicyFile();
2456 }
2457
2458
Adam Lesinski182f73f2013-12-05 16:48:06 -08002459 /**
2460 * System-only API for getting a list of current (i.e. not cleared) notifications.
2461 *
2462 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04002463 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002464 */
2465 @Override
2466 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2467 // enforce() will ensure the calling uid has the correct permission
2468 getContext().enforceCallingOrSelfPermission(
2469 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2470 "NotificationManagerService.getActiveNotifications");
2471
2472 StatusBarNotification[] tmp = null;
2473 int uid = Binder.getCallingUid();
2474
2475 // noteOp will check to make sure the callingPkg matches the uid
2476 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2477 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002478 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002479 tmp = new StatusBarNotification[mNotificationList.size()];
2480 final int N = mNotificationList.size();
2481 for (int i=0; i<N; i++) {
2482 tmp[i] = mNotificationList.get(i).sbn;
2483 }
2484 }
2485 }
2486 return tmp;
2487 }
2488
2489 /**
Dan Sandler994349c2015-04-15 11:02:54 -04002490 * Public API for getting a list of current notifications for the calling package/uid.
2491 *
Julia Reynolds573c6532017-01-24 17:44:38 -05002492 * Note that since notification posting is done asynchronously, this will not return
2493 * notifications that are in the process of being posted.
2494 *
Dan Sandler994349c2015-04-15 11:02:54 -04002495 * @returns A list of all the package's notifications, in natural order.
2496 */
2497 @Override
2498 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2499 int incomingUserId) {
2500 checkCallerIsSystemOrSameApp(pkg);
2501 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2502 Binder.getCallingUid(), incomingUserId, true, false,
2503 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002504 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002505 final ArrayMap<String, StatusBarNotification> map
2506 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002507 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002508 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002509 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2510 mNotificationList.get(i).sbn);
2511 if (sbn != null) {
2512 map.put(sbn.getKey(), sbn);
2513 }
2514 }
2515 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2516 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2517 if (sbn != null) {
2518 map.put(sbn.getKey(), sbn);
2519 }
2520 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002521 final int M = mEnqueuedNotifications.size();
2522 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002523 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2524 mEnqueuedNotifications.get(i).sbn);
2525 if (sbn != null) {
2526 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04002527 }
2528 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002529 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2530 list.addAll(map.values());
2531 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04002532 }
Dan Sandler994349c2015-04-15 11:02:54 -04002533 }
2534
Chris Wren6676dab2016-12-21 18:26:27 -05002535 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2536 StatusBarNotification sbn) {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04002537 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
Chris Wren6676dab2016-12-21 18:26:27 -05002538 // We could pass back a cloneLight() but clients might get confused and
2539 // try to send this thing back to notify() again, which would not work
2540 // very well.
2541 return new StatusBarNotification(
2542 sbn.getPackageName(),
2543 sbn.getOpPkg(),
Chris Wren6676dab2016-12-21 18:26:27 -05002544 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2545 sbn.getNotification().clone(),
2546 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2547 }
2548 return null;
2549 }
2550
Dan Sandler994349c2015-04-15 11:02:54 -04002551 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002552 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2553 *
2554 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2555 */
2556 @Override
2557 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2558 // enforce() will ensure the calling uid has the correct permission
2559 getContext().enforceCallingOrSelfPermission(
2560 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2561 "NotificationManagerService.getHistoricalNotifications");
2562
2563 StatusBarNotification[] tmp = null;
2564 int uid = Binder.getCallingUid();
2565
2566 // noteOp will check to make sure the callingPkg matches the uid
2567 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2568 == AppOpsManager.MODE_ALLOWED) {
2569 synchronized (mArchive) {
2570 tmp = mArchive.getArray(count);
2571 }
2572 }
2573 return tmp;
2574 }
2575
2576 /**
2577 * Register a listener binder directly with the notification manager.
2578 *
2579 * Only works with system callers. Apps should extend
2580 * {@link android.service.notification.NotificationListenerService}.
2581 */
2582 @Override
2583 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05002584 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02002585 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05002586 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002587 }
2588
2589 /**
2590 * Remove a listener binder directly
2591 */
2592 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002593 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05002594 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002595 }
2596
2597 /**
2598 * Allow an INotificationListener to simulate a "clear all" operation.
2599 *
2600 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2601 *
2602 * @param token The binder for the listener, to check that the caller is allowed
2603 */
2604 @Override
John Spurlocka4294292014-03-24 18:02:32 -04002605 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002606 final int callingUid = Binder.getCallingUid();
2607 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002608 long identity = Binder.clearCallingIdentity();
2609 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002610 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002611 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Beverly5a20a5e2018-03-06 15:02:44 -05002612
John Spurlocka4294292014-03-24 18:02:32 -04002613 if (keys != null) {
2614 final int N = keys.length;
2615 for (int i = 0; i < N; i++) {
2616 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07002617 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00002618 final int userId = r.sbn.getUserId();
2619 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04002620 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00002621 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04002622 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00002623 }
Griff Hazen335e1f02014-09-11 14:49:31 -07002624 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2625 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2626 userId);
John Spurlocka4294292014-03-24 18:02:32 -04002627 }
2628 } else {
2629 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00002630 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04002631 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002632 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002633 } finally {
2634 Binder.restoreCallingIdentity(identity);
2635 }
2636 }
2637
Chris Wrenab41eec2016-01-04 18:01:27 -05002638 /**
2639 * Handle request from an approved listener to re-enable itself.
2640 *
2641 * @param component The componenet to be re-enabled, caller must match package.
2642 */
2643 @Override
2644 public void requestBindListener(ComponentName component) {
2645 checkCallerIsSystemOrSameApp(component.getPackageName());
2646 long identity = Binder.clearCallingIdentity();
2647 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002648 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002649 mAssistants.isComponentEnabledForCurrentProfiles(component)
2650 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05002651 : mListeners;
2652 manager.setComponentState(component, true);
2653 } finally {
2654 Binder.restoreCallingIdentity(identity);
2655 }
2656 }
2657
2658 @Override
2659 public void requestUnbindListener(INotificationListener token) {
2660 long identity = Binder.clearCallingIdentity();
2661 try {
2662 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002663 synchronized (mNotificationLock) {
2664 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2665 info.getOwner().setComponentState(info.component, false);
2666 }
Chris Wrenab41eec2016-01-04 18:01:27 -05002667 } finally {
2668 Binder.restoreCallingIdentity(identity);
2669 }
2670 }
2671
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002672 @Override
2673 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002674 long identity = Binder.clearCallingIdentity();
2675 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002676 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002677 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2678 if (keys != null) {
2679 final int N = keys.length;
2680 for (int i = 0; i < N; i++) {
2681 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2682 if (r == null) continue;
2683 final int userId = r.sbn.getUserId();
2684 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2685 !mUserProfiles.isCurrentProfile(userId)) {
2686 throw new SecurityException("Disallowed call from listener: "
2687 + info.service);
2688 }
2689 if (!r.isSeen()) {
2690 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
Amith Yamasani803eab692017-11-09 17:47:04 -08002691 reportSeen(r);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002692 r.setSeen();
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04002693 maybeRecordInterruptionLocked(r);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002694 }
2695 }
2696 }
2697 }
2698 } finally {
2699 Binder.restoreCallingIdentity(identity);
2700 }
2701 }
2702
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002703 /**
2704 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2705 *
2706 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2707 *
Julia Reynolds79672302017-01-12 08:30:16 -05002708 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002709 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04002710 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04002711 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00002712 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04002713 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -04002714 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
John Spurlocka4294292014-03-24 18:02:32 -04002715 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00002716 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04002717 }
2718
Adam Lesinski182f73f2013-12-05 16:48:06 -08002719 /**
Julia Reynolds79672302017-01-12 08:30:16 -05002720 * Allow an INotificationListener to snooze a single notification until a context.
2721 *
2722 * @param token The binder for the listener, to check that the caller is allowed
2723 */
2724 @Override
2725 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2726 String key, String snoozeCriterionId) {
2727 long identity = Binder.clearCallingIdentity();
2728 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002729 synchronized (mNotificationLock) {
2730 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2731 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2732 }
Julia Reynolds79672302017-01-12 08:30:16 -05002733 } finally {
2734 Binder.restoreCallingIdentity(identity);
2735 }
2736 }
2737
2738 /**
2739 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002740 *
2741 * @param token The binder for the listener, to check that the caller is allowed
2742 */
2743 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002744 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05002745 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002746 long identity = Binder.clearCallingIdentity();
2747 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002748 synchronized (mNotificationLock) {
2749 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2750 snoozeNotificationInt(key, duration, null, info);
2751 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002752 } finally {
2753 Binder.restoreCallingIdentity(identity);
2754 }
2755 }
2756
2757 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002758 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002759 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002760 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002761 */
2762 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002763 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002764 long identity = Binder.clearCallingIdentity();
2765 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002766 synchronized (mNotificationLock) {
2767 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002768 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002769 unsnoozeNotificationInt(key, info);
2770 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002771 } finally {
2772 Binder.restoreCallingIdentity(identity);
2773 }
2774 }
2775
2776 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002777 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2778 *
2779 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2780 *
2781 * @param token The binder for the listener, to check that the caller is allowed
2782 */
2783 @Override
2784 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2785 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002786 final int callingUid = Binder.getCallingUid();
2787 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002788 long identity = Binder.clearCallingIdentity();
2789 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002790 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002791 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00002792 if (info.supportsProfiles()) {
2793 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2794 + "from " + info.component
2795 + " use cancelNotification(key) instead.");
2796 } else {
2797 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2798 pkg, tag, id, info.userid);
2799 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002800 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002801 } finally {
2802 Binder.restoreCallingIdentity(identity);
2803 }
2804 }
2805
2806 /**
2807 * Allow an INotificationListener to request the list of outstanding notifications seen by
2808 * the current user. Useful when starting up, after which point the listener callbacks
2809 * should be used.
2810 *
2811 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002812 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04002813 * @returns The return value will contain the notifications specified in keys, in that
2814 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002815 */
2816 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02002817 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02002818 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002819 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002820 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002821 final boolean getKeys = keys != null;
2822 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02002823 final ArrayList<StatusBarNotification> list
2824 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02002825 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002826 final NotificationRecord r = getKeys
2827 ? mNotificationsByKey.get(keys[i])
2828 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02002829 if (r == null) continue;
2830 StatusBarNotification sbn = r.sbn;
2831 if (!isVisibleToListener(sbn, info)) continue;
2832 StatusBarNotification sbnToSend =
2833 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2834 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002835 }
Christoph Studercee44ba2014-05-20 18:36:43 +02002836 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002837 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002838 }
2839
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002840 /**
2841 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2842 * seen by the current user. Useful when starting up, after which point the listener
2843 * callbacks should be used.
2844 *
2845 * @param token The binder for the listener, to check that the caller is allowed
2846 * @returns The return value will contain the notifications specified in keys, in that
2847 * order, or if keys is null, all the notifications, in natural order.
2848 */
2849 @Override
2850 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2851 INotificationListener token, int trim) {
2852 synchronized (mNotificationLock) {
2853 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2854 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2855 final int N = snoozedRecords.size();
2856 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2857 for (int i=0; i < N; i++) {
2858 final NotificationRecord r = snoozedRecords.get(i);
2859 if (r == null) continue;
2860 StatusBarNotification sbn = r.sbn;
2861 if (!isVisibleToListener(sbn, info)) continue;
2862 StatusBarNotification sbnToSend =
2863 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2864 list.add(sbnToSend);
2865 }
2866 return new ParceledListSlice<>(list);
2867 }
2868 }
2869
Adam Lesinski182f73f2013-12-05 16:48:06 -08002870 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002871 public void requestHintsFromListener(INotificationListener token, int hints) {
2872 final long identity = Binder.clearCallingIdentity();
2873 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002874 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002875 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07002876 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2877 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2878 | HINT_HOST_DISABLE_CALL_EFFECTS;
2879 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04002880 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07002881 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002882 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07002883 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002884 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002885 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04002886 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04002887 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002888 } finally {
2889 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04002890 }
2891 }
2892
2893 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002894 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002895 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002896 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04002897 }
2898 }
2899
2900 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02002901 public void requestInterruptionFilterFromListener(INotificationListener token,
2902 int interruptionFilter) throws RemoteException {
2903 final long identity = Binder.clearCallingIdentity();
2904 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002905 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002906 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2907 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02002908 updateInterruptionFilterLocked();
2909 }
2910 } finally {
2911 Binder.restoreCallingIdentity(identity);
2912 }
2913 }
2914
2915 @Override
2916 public int getInterruptionFilterFromListener(INotificationListener token)
2917 throws RemoteException {
2918 synchronized (mNotificationLight) {
2919 return mInterruptionFilter;
2920 }
2921 }
2922
2923 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02002924 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2925 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002926 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02002927 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2928 if (info == null) return;
2929 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2930 }
2931 }
2932
2933 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002934 public int getZenMode() {
2935 return mZenModeHelper.getZenMode();
2936 }
2937
2938 @Override
John Spurlock056c5192014-04-20 21:52:01 -04002939 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002940 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04002941 return mZenModeHelper.getConfig();
2942 }
2943
2944 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002945 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002946 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05002947 final long identity = Binder.clearCallingIdentity();
2948 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002949 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05002950 } finally {
2951 Binder.restoreCallingIdentity(identity);
2952 }
2953 }
2954
2955 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002956 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002957 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05002958 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002959 }
2960
2961 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002962 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2963 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002964 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002965 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002966 }
2967
2968 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002969 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002970 throws RemoteException {
2971 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2972 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2973 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2974 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002975 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002976
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002977 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2978 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002979 }
2980
2981 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002982 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002983 throws RemoteException {
2984 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2985 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2986 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2987 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2988 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002989
Julia Reynolds361e82d32016-02-26 18:19:49 -05002990 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002991 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002992 }
2993
2994 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002995 public boolean removeAutomaticZenRule(String id) throws RemoteException {
2996 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002997 // Verify that they can modify zen rules.
2998 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2999
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003000 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003001 }
3002
3003 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05003004 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
3005 Preconditions.checkNotNull(packageName, "Package name is null");
3006 enforceSystemOrSystemUI("removeAutomaticZenRules");
3007
3008 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
3009 }
3010
3011 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05003012 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
3013 Preconditions.checkNotNull(owner, "Owner is null");
3014 enforceSystemOrSystemUI("getRuleInstanceCount");
3015
3016 return mZenModeHelper.getCurrentInstanceCount(owner);
3017 }
3018
3019 @Override
John Spurlock80774932015-05-07 17:38:50 -04003020 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
3021 enforcePolicyAccess(pkg, "setInterruptionFilter");
3022 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
3023 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
3024 final long identity = Binder.clearCallingIdentity();
3025 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04003026 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04003027 } finally {
3028 Binder.restoreCallingIdentity(identity);
3029 }
3030 }
3031
3032 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04003033 public void notifyConditions(final String pkg, IConditionProvider provider,
3034 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04003035 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3036 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04003037 mHandler.post(new Runnable() {
3038 @Override
3039 public void run() {
3040 mConditionProviders.notifyConditions(pkg, info, conditions);
3041 }
3042 });
John Spurlocke77bb362014-04-26 10:24:59 -04003043 }
3044
Julia Reynolds38e6ca42016-08-08 08:38:09 -04003045 @Override
3046 public void requestUnbindProvider(IConditionProvider provider) {
3047 long identity = Binder.clearCallingIdentity();
3048 try {
3049 // allow bound services to disable themselves
3050 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3051 info.getOwner().setComponentState(info.component, false);
3052 } finally {
3053 Binder.restoreCallingIdentity(identity);
3054 }
3055 }
3056
3057 @Override
3058 public void requestBindProvider(ComponentName component) {
3059 checkCallerIsSystemOrSameApp(component.getPackageName());
3060 long identity = Binder.clearCallingIdentity();
3061 try {
3062 mConditionProviders.setComponentState(component, true);
3063 } finally {
3064 Binder.restoreCallingIdentity(identity);
3065 }
3066 }
3067
John Spurlocke77bb362014-04-26 10:24:59 -04003068 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003069 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04003070 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
3071 message);
John Spurlock7340fc82014-04-24 18:50:12 -04003072 }
3073
Julia Reynolds48034f82016-03-09 10:15:16 -05003074 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
3075 try {
3076 checkCallerIsSystemOrSameApp(pkg);
3077 } catch (SecurityException e) {
3078 getContext().enforceCallingPermission(
3079 android.Manifest.permission.STATUS_BAR_SERVICE,
3080 message);
3081 }
3082 }
3083
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003084 private void enforcePolicyAccess(int uid, String method) {
3085 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3086 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3087 return;
3088 }
3089 boolean accessAllowed = false;
3090 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
3091 final int packageCount = packages.length;
3092 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003093 if (mConditionProviders.isPackageOrComponentAllowed(
3094 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003095 accessAllowed = true;
3096 }
3097 }
3098 if (!accessAllowed) {
3099 Slog.w(TAG, "Notification policy access denied calling " + method);
3100 throw new SecurityException("Notification policy access denied");
3101 }
3102 }
3103
John Spurlock80774932015-05-07 17:38:50 -04003104 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04003105 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3106 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3107 return;
3108 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04003109 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003110 if (!checkPolicyAccess(pkg)) {
3111 Slog.w(TAG, "Notification policy access denied calling " + method);
3112 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04003113 }
3114 }
3115
John Spurlock80774932015-05-07 17:38:50 -04003116 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003117 return mConditionProviders.isPackageOrComponentAllowed(
3118 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04003119 }
3120
3121 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003122 try {
Jason Parks50322ff2018-03-27 10:23:33 -05003123 int uid = getContext().getPackageManager().getPackageUidAsUser(pkg,
3124 UserHandle.getCallingUserId());
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003125 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
3126 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
3127 -1, true)) {
3128 return true;
3129 }
3130 } catch (NameNotFoundException e) {
3131 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003132 }
Jason Parks50322ff2018-03-27 10:23:33 -05003133 return checkPackagePolicyAccess(pkg)
3134 || mListeners.isComponentEnabledForPackage(pkg)
3135 || (mDpm != null &&
3136 mDpm.isActiveAdminWithPolicy(Binder.getCallingUid(),
3137 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER));
John Spurlock1fc476d2015-04-14 16:05:20 -04003138 }
3139
John Spurlock7340fc82014-04-24 18:50:12 -04003140 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08003141 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003142 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04003143 final DumpFilter filter = DumpFilter.parseFromArguments(args);
Kweku Adams887f09c2017-11-13 17:12:20 -08003144 if (filter.stats) {
Chris Wrene4b38802015-07-07 15:54:19 -04003145 dumpJson(pw, filter);
Kweku Adams887f09c2017-11-13 17:12:20 -08003146 } else if (filter.proto) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003147 dumpProto(fd, filter);
Vishnu Naire3e4d252018-03-01 11:26:57 -08003148 } else if (filter.criticalPriority) {
3149 dumpNotificationRecords(pw, filter);
Chris Wrene4b38802015-07-07 15:54:19 -04003150 } else {
3151 dumpImpl(pw, filter);
3152 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003153 }
John Spurlockb4782522014-08-22 14:54:46 -04003154
3155 @Override
3156 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07003157 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04003158 }
John Spurlock2b122f42014-08-27 16:29:47 -04003159
3160 @Override
3161 public boolean matchesCallFilter(Bundle extras) {
3162 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02003163 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003164 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02003165 extras,
3166 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
3167 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
3168 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04003169 }
John Spurlock530052a2014-11-30 16:26:19 -05003170
3171 @Override
3172 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003173 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04003174 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05003175 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003176
Christopher Tatef9767d62015-04-08 14:35:43 -07003177 // Backup/restore interface
3178 @Override
3179 public byte[] getBackupPayload(int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003180 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003181 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003182 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003183 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003184 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
3185 return null;
3186 }
songjinshi9bf22712017-02-04 10:47:45 +08003187 synchronized(mPolicyFile) {
3188 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
3189 try {
3190 writePolicyXml(baos, true /*forBackup*/);
3191 return baos.toByteArray();
3192 } catch (IOException e) {
3193 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
3194 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003195 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003196 return null;
3197 }
3198
3199 @Override
3200 public void applyRestore(byte[] payload, int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003201 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003202 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
3203 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
3204 if (payload == null) {
3205 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
3206 return;
3207 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003208 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003209 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003210 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
3211 return;
3212 }
songjinshi9bf22712017-02-04 10:47:45 +08003213 synchronized(mPolicyFile) {
3214 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
3215 try {
3216 readPolicyXml(bais, true /*forRestore*/);
3217 savePolicyFile();
3218 } catch (NumberFormatException | XmlPullParserException | IOException e) {
3219 Slog.w(TAG, "applyRestore: error reading payload", e);
3220 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003221 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003222 }
3223
John Spurlock1fc476d2015-04-14 16:05:20 -04003224 @Override
John Spurlock80774932015-05-07 17:38:50 -04003225 public boolean isNotificationPolicyAccessGranted(String pkg) {
3226 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04003227 }
3228
3229 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05003230 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
3231 enforceSystemOrSystemUIOrSamePackage(pkg,
3232 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003233 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003234 }
3235
3236 @Override
John Spurlock80774932015-05-07 17:38:50 -04003237 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
3238 throws RemoteException {
Julia Reynolds92febc32017-10-26 11:30:31 -04003239 setNotificationPolicyAccessGrantedForUser(
3240 pkg, getCallingUserHandle().getIdentifier(), granted);
3241 }
3242
3243 @Override
3244 public void setNotificationPolicyAccessGrantedForUser(
3245 String pkg, int userId, boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003246 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003247 final long identity = Binder.clearCallingIdentity();
3248 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003249 if (mAllowedManagedServicePackages.test(pkg)) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003250 mConditionProviders.setPackageOrComponentEnabled(
Julia Reynolds92febc32017-10-26 11:30:31 -04003251 pkg, userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003252
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003253 getContext().sendBroadcastAsUser(new Intent(
3254 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3255 .setPackage(pkg)
3256 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003257 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003258 savePolicyFile();
3259 }
3260 } finally {
3261 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003262 }
John Spurlock80774932015-05-07 17:38:50 -04003263 }
3264
3265 @Override
3266 public Policy getNotificationPolicy(String pkg) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003267 final long identity = Binder.clearCallingIdentity();
3268 try {
3269 return mZenModeHelper.getNotificationPolicy();
3270 } finally {
3271 Binder.restoreCallingIdentity(identity);
3272 }
3273 }
3274
Beverly6697eff2017-12-14 15:00:27 -05003275 /**
3276 * Sets the notification policy. Apps that target API levels below
Beverly98ef61b2018-02-15 10:36:28 -05003277 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
Beverlyd6964762018-02-16 14:07:03 -05003278 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3279 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3280 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
Beverly6697eff2017-12-14 15:00:27 -05003281 */
John Spurlock1fc476d2015-04-14 16:05:20 -04003282 @Override
John Spurlock80774932015-05-07 17:38:50 -04003283 public void setNotificationPolicy(String pkg, Policy policy) {
3284 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04003285 final long identity = Binder.clearCallingIdentity();
3286 try {
Beverly6697eff2017-12-14 15:00:27 -05003287 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3288 0, UserHandle.getUserId(MY_UID));
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003289 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
Beverly6697eff2017-12-14 15:00:27 -05003290
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06003291 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
Beverly98ef61b2018-02-15 10:36:28 -05003292 int priorityCategories = policy.priorityCategories;
3293 // ignore alarm and media values from new policy
3294 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
Beverlyd6964762018-02-16 14:07:03 -05003295 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3296 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003297 // use user-designated values
Beverlyd6964762018-02-16 14:07:03 -05003298 priorityCategories |= currPolicy.priorityCategories
3299 & Policy.PRIORITY_CATEGORY_ALARMS;
3300 priorityCategories |= currPolicy.priorityCategories
3301 & Policy.PRIORITY_CATEGORY_MEDIA;
3302 priorityCategories |= currPolicy.priorityCategories
3303 & Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003304
Beverly6697eff2017-12-14 15:00:27 -05003305 policy = new Policy(priorityCategories,
3306 policy.priorityCallSenders, policy.priorityMessageSenders,
3307 policy.suppressedVisualEffects);
3308 }
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003309 int newVisualEffects = calculateSuppressedVisualEffects(
3310 policy, currPolicy, applicationInfo.targetSdkVersion);
3311 policy = new Policy(policy.priorityCategories,
3312 policy.priorityCallSenders, policy.priorityMessageSenders,
3313 newVisualEffects);
Beverly5e073222018-03-08 10:36:25 -05003314 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
John Spurlock1fc476d2015-04-14 16:05:20 -04003315 mZenModeHelper.setNotificationPolicy(policy);
Beverly6697eff2017-12-14 15:00:27 -05003316 } catch (RemoteException e) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003317 } finally {
3318 Binder.restoreCallingIdentity(identity);
3319 }
3320 }
Chris Wren51017d02015-12-15 15:34:46 -05003321
3322 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003323 public List<String> getEnabledNotificationListenerPackages() {
3324 checkCallerIsSystem();
3325 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3326 }
3327
3328 @Override
3329 public List<ComponentName> getEnabledNotificationListeners(int userId) {
3330 checkCallerIsSystem();
3331 return mListeners.getAllowedComponents(userId);
3332 }
3333
3334 @Override
3335 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3336 Preconditions.checkNotNull(listener);
3337 checkCallerIsSystemOrSameApp(listener.getPackageName());
3338 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3339 getCallingUserHandle().getIdentifier());
3340 }
3341
3342 @Override
3343 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3344 int userId) {
3345 Preconditions.checkNotNull(listener);
3346 checkCallerIsSystem();
3347 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3348 userId);
3349 }
3350
3351 @Override
3352 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3353 Preconditions.checkNotNull(assistant);
3354 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003355 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04003356 getCallingUserHandle().getIdentifier());
3357 }
3358
3359 @Override
3360 public void setNotificationListenerAccessGranted(ComponentName listener,
3361 boolean granted) throws RemoteException {
3362 setNotificationListenerAccessGrantedForUser(
3363 listener, getCallingUserHandle().getIdentifier(), granted);
3364 }
3365
3366 @Override
3367 public void setNotificationAssistantAccessGranted(ComponentName assistant,
3368 boolean granted) throws RemoteException {
3369 setNotificationAssistantAccessGrantedForUser(
3370 assistant, getCallingUserHandle().getIdentifier(), granted);
3371 }
3372
3373 @Override
3374 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3375 boolean granted) throws RemoteException {
3376 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04003377 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003378 final long identity = Binder.clearCallingIdentity();
3379 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003380 if (mAllowedManagedServicePackages.test(listener.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003381 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3382 userId, false, granted);
3383 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3384 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003385
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003386 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds92febc32017-10-26 11:30:31 -04003387 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003388 .setPackage(listener.getPackageName())
3389 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003390 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003391
3392 savePolicyFile();
3393 }
3394 } finally {
3395 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003396 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003397 }
3398
3399 @Override
3400 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3401 int userId, boolean granted) throws RemoteException {
3402 Preconditions.checkNotNull(assistant);
Julia Reynolds0d217642017-08-11 11:26:04 -04003403 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003404 final long identity = Binder.clearCallingIdentity();
3405 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003406 if (mAllowedManagedServicePackages.test(assistant.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003407 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
3408 userId, false, granted);
3409 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
3410 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003411
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003412 getContext().sendBroadcastAsUser(new Intent(
3413 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3414 .setPackage(assistant.getPackageName())
3415 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003416 UserHandle.of(userId), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003417
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003418 savePolicyFile();
3419 }
3420 } finally {
3421 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003422 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003423 }
3424
3425 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003426 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
3427 Adjustment adjustment) throws RemoteException {
3428 final long identity = Binder.clearCallingIdentity();
3429 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003430 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003431 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003432 int N = mEnqueuedNotifications.size();
3433 for (int i = 0; i < N; i++) {
3434 final NotificationRecord n = mEnqueuedNotifications.get(i);
3435 if (Objects.equals(adjustment.getKey(), n.getKey())
3436 && Objects.equals(adjustment.getUser(), n.getUserId())) {
3437 applyAdjustment(n, adjustment);
3438 break;
3439 }
3440 }
3441 }
3442 } finally {
3443 Binder.restoreCallingIdentity(identity);
3444 }
3445 }
3446
3447 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003448 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003449 Adjustment adjustment) throws RemoteException {
Chris Wren51017d02015-12-15 15:34:46 -05003450 final long identity = Binder.clearCallingIdentity();
3451 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003452 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003453 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003454 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3455 applyAdjustment(n, adjustment);
Chris Wren51017d02015-12-15 15:34:46 -05003456 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003457 mRankingHandler.requestSort();
Julia Reynoldse46bb372016-03-17 11:05:58 -04003458 } finally {
3459 Binder.restoreCallingIdentity(identity);
3460 }
3461 }
3462
3463 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003464 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003465 List<Adjustment> adjustments) throws RemoteException {
3466
3467 final long identity = Binder.clearCallingIdentity();
3468 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003469 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003470 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003471 for (Adjustment adjustment : adjustments) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003472 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3473 applyAdjustment(n, adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003474 }
3475 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003476 mRankingHandler.requestSort();
Chris Wren51017d02015-12-15 15:34:46 -05003477 } finally {
3478 Binder.restoreCallingIdentity(identity);
3479 }
3480 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003481
3482 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04003483 public void updateNotificationChannelGroupFromPrivilegedListener(
3484 INotificationListener token, String pkg, UserHandle user,
3485 NotificationChannelGroup group) throws RemoteException {
3486 Preconditions.checkNotNull(user);
3487 verifyPrivilegedListener(token, user);
3488 createNotificationChannelGroup(
3489 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
3490 savePolicyFile();
3491 }
3492
3493 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003494 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003495 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003496 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003497 Preconditions.checkNotNull(pkg);
3498 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003499
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003500 verifyPrivilegedListener(token, user);
3501 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003502 }
3503
3504 @Override
3505 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003506 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3507 Preconditions.checkNotNull(pkg);
3508 Preconditions.checkNotNull(user);
3509 verifyPrivilegedListener(token, user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003510
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003511 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
3512 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003513 }
3514
3515 @Override
3516 public ParceledListSlice<NotificationChannelGroup>
3517 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003518 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3519 Preconditions.checkNotNull(pkg);
3520 Preconditions.checkNotNull(user);
3521 verifyPrivilegedListener(token, user);
3522
3523 List<NotificationChannelGroup> groups = new ArrayList<>();
3524 groups.addAll(mRankingHelper.getNotificationChannelGroups(
3525 pkg, getUidForPackageAndUser(pkg, user)));
3526 return new ParceledListSlice<>(groups);
3527 }
3528
3529 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003530 ManagedServiceInfo info;
3531 synchronized (mNotificationLock) {
3532 info = mListeners.checkServiceTokenLocked(token);
3533 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003534 if (!hasCompanionDevice(info)) {
3535 throw new SecurityException(info + " does not have access");
3536 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003537 if (!info.enabledAndUserMatches(user.getIdentifier())) {
3538 throw new SecurityException(info + " does not have access");
3539 }
3540 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003541
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003542 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3543 int uid = 0;
3544 long identity = Binder.clearCallingIdentity();
3545 try {
3546 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3547 } finally {
3548 Binder.restoreCallingIdentity(identity);
3549 }
3550 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003551 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003552
3553 @Override
3554 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3555 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3556 throws RemoteException {
3557 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3558 }
John Spurlock1fc476d2015-04-14 16:05:20 -04003559 };
John Spurlocka4294292014-03-24 18:02:32 -04003560
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003561 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3562 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003563 return;
3564 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003565 if (adjustment.getSignals() != null) {
3566 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003567 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003568 }
3569 }
3570
Julia Reynolds88860ce2017-06-01 16:55:49 -04003571 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003572 void addAutogroupKeyLocked(String key) {
3573 NotificationRecord r = mNotificationsByKey.get(key);
3574 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003575 return;
3576 }
Julia Reynolds51710712017-07-19 13:48:07 -04003577 if (r.sbn.getOverrideGroupKey() == null) {
3578 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3579 EventLogTags.writeNotificationAutogrouped(key);
3580 mRankingHandler.requestSort();
3581 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003582 }
3583
Julia Reynolds88860ce2017-06-01 16:55:49 -04003584 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003585 void removeAutogroupKeyLocked(String key) {
3586 NotificationRecord r = mNotificationsByKey.get(key);
3587 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003588 return;
3589 }
Julia Reynolds51710712017-07-19 13:48:07 -04003590 if (r.sbn.getOverrideGroupKey() != null) {
3591 addAutoGroupAdjustment(r, null);
3592 EventLogTags.writeNotificationUnautogrouped(key);
3593 mRankingHandler.requestSort();
3594 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003595 }
3596
3597 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3598 Bundle signals = new Bundle();
3599 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3600 Adjustment adjustment =
3601 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3602 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003603 }
3604
3605 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04003606 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04003607 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3608 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3609 if (summaries != null && summaries.containsKey(pkg)) {
3610 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003611 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04003612 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04003613 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003614 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003615 }
3616 }
3617 }
3618
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003619 @GuardedBy("mNotificationLock")
3620 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3621 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3622 return summaries != null && summaries.containsKey(sbn.getPackageName());
3623 }
3624
Julia Reynoldse46bb372016-03-17 11:05:58 -04003625 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04003626 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3627 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003628 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003629 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3630 if (notificationRecord == null) {
3631 // The notification could have been cancelled again already. A successive
3632 // adjustment will post a summary if needed.
3633 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003634 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003635 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3636 userId = adjustedSbn.getUser().getIdentifier();
3637 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3638 if (summaries == null) {
3639 summaries = new ArrayMap<>();
3640 }
3641 mAutobundledSummaries.put(userId, summaries);
3642 if (!summaries.containsKey(pkg)) {
3643 // Add summary
3644 final ApplicationInfo appInfo =
3645 adjustedSbn.getNotification().extras.getParcelable(
3646 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3647 final Bundle extras = new Bundle();
3648 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003649 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04003650 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003651 new Notification.Builder(getContext(), channelId)
3652 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04003653 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04003654 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04003655 .setGroup(GroupHelper.AUTOGROUP_KEY)
3656 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3657 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3658 .setColor(adjustedSbn.getNotification().color)
3659 .setLocalOnly(true)
3660 .build();
3661 summaryNotification.extras.putAll(extras);
3662 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3663 if (appIntent != null) {
3664 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3665 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3666 }
3667 final StatusBarNotification summarySbn =
3668 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003669 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003670 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04003671 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3672 adjustedSbn.getInitialPid(), summaryNotification,
3673 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3674 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05003675 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003676 notificationRecord.getChannel());
Rohan Shah590e1b22018-04-10 23:48:47 -04003677 summaryRecord.setIsAppImportanceLocked(
3678 notificationRecord.getIsAppImportanceLocked());
Julia Reynolds8f488d32016-10-14 10:59:01 -04003679 summaries.put(pkg, summarySbn.getKey());
3680 }
3681 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003682 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04003683 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003684 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04003685 }
3686 }
3687
John Spurlock32fe4c62014-10-02 12:16:02 -04003688 private String disableNotificationEffects(NotificationRecord record) {
3689 if (mDisableNotificationEffects) {
3690 return "booleanState";
3691 }
3692 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3693 return "listenerHints";
3694 }
3695 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3696 return "callState";
3697 }
3698 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04003699 };
3700
Kweku Adams887f09c2017-11-13 17:12:20 -08003701 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
Chris Wrene4b38802015-07-07 15:54:19 -04003702 JSONObject dump = new JSONObject();
3703 try {
3704 dump.put("service", "Notification Manager");
Chris Wrenacf424a2016-03-15 12:48:55 -04003705 dump.put("bans", mRankingHelper.dumpBansJson(filter));
3706 dump.put("ranking", mRankingHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003707 dump.put("stats", mUsageStats.dumpJson(filter));
Julia Reynoldsd373d782017-03-03 13:32:57 -05003708 dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003709 } catch (JSONException e) {
3710 e.printStackTrace();
3711 }
3712 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04003713 }
3714
Kweku Adams887f09c2017-11-13 17:12:20 -08003715 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003716 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3717 synchronized (mNotificationLock) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003718 int N = mNotificationList.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003719 for (int i = 0; i < N; i++) {
3720 final NotificationRecord nr = mNotificationList.get(i);
3721 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3722 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3723 NotificationRecordProto.POSTED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003724 }
3725 N = mEnqueuedNotifications.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003726 for (int i = 0; i < N; i++) {
3727 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3728 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3729 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3730 NotificationRecordProto.ENQUEUED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003731 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003732 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3733 N = snoozed.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003734 for (int i = 0; i < N; i++) {
3735 final NotificationRecord nr = snoozed.get(i);
3736 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3737 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3738 NotificationRecordProto.SNOOZED);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003739 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003740
Kweku Adams93304b62017-09-20 17:03:00 -07003741 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3742 mZenModeHelper.dump(proto);
3743 for (ComponentName suppressor : mEffectsSuppressors) {
Kweku Adams99546332018-01-24 17:03:50 -08003744 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
Kweku Adams93304b62017-09-20 17:03:00 -07003745 }
3746 proto.end(zenLog);
3747
3748 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
3749 mListeners.dump(proto, filter);
3750 proto.end(listenersToken);
3751
3752 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
3753
3754 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
3755 long effectsToken = proto.start(
3756 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
3757
3758 proto.write(
3759 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
3760 final ArraySet<ManagedServiceInfo> listeners =
3761 mListenersDisablingEffects.valueAt(i);
3762 for (int j = 0; j < listeners.size(); j++) {
3763 final ManagedServiceInfo listener = listeners.valueAt(i);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08003764 listener.writeToProto(proto, ListenersDisablingEffectsProto.LISTENERS, null);
Kweku Adams93304b62017-09-20 17:03:00 -07003765 }
3766
3767 proto.end(effectsToken);
3768 }
3769
3770 long assistantsToken = proto.start(
3771 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
3772 mAssistants.dump(proto, filter);
3773 proto.end(assistantsToken);
3774
3775 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
3776 mConditionProviders.dump(proto, filter);
3777 proto.end(conditionsToken);
Kweku Adams62b42242017-09-25 12:54:02 -07003778
3779 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
3780 mRankingHelper.dump(proto, filter);
3781 proto.end(rankingToken);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003782 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003783
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003784 proto.flush();
3785 }
3786
Vishnu Naire3e4d252018-03-01 11:26:57 -08003787 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
3788 synchronized (mNotificationLock) {
3789 int N;
3790 N = mNotificationList.size();
3791 if (N > 0) {
3792 pw.println(" Notification List:");
3793 for (int i = 0; i < N; i++) {
3794 final NotificationRecord nr = mNotificationList.get(i);
3795 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3796 nr.dump(pw, " ", getContext(), filter.redact);
3797 }
3798 pw.println(" ");
3799 }
3800 }
3801 }
3802
Kweku Adams887f09c2017-11-13 17:12:20 -08003803 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
John Spurlock25e2d242014-06-27 13:58:23 -04003804 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04003805 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003806 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04003807 }
3808 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08003809 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003810 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003811
John Spurlock50806fc2014-07-15 10:22:02 -04003812 if (!zenOnly) {
3813 synchronized (mToastQueue) {
3814 N = mToastQueue.size();
3815 if (N > 0) {
3816 pw.println(" Toast Queue:");
3817 for (int i=0; i<N; i++) {
3818 mToastQueue.get(i).dump(pw, " ", filter);
3819 }
3820 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003821 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003822 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003823 }
3824
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003825 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04003826 if (!zenOnly) {
Vishnu Naire3e4d252018-03-01 11:26:57 -08003827 // Priority filters are only set when called via bugreport. If set
3828 // skip sections that are part of the critical section.
3829 if (!filter.normalPriority) {
3830 dumpNotificationRecords(pw, filter);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003831 }
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003832 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003833 N = mLights.size();
3834 if (N > 0) {
3835 pw.println(" Lights List:");
3836 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05003837 if (i == N - 1) {
3838 pw.print(" > ");
3839 } else {
3840 pw.print(" ");
3841 }
3842 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04003843 }
3844 pw.println(" ");
3845 }
John Spurlockcb566aa2014-08-03 22:58:28 -04003846 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
Julia Reynolds54369232018-07-03 10:43:35 -04003847 pw.println(" mHasLight=" + mHasLight);
John Spurlockcb566aa2014-08-03 22:58:28 -04003848 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05003849 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3850 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003851 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04003852 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04003853 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04003854 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04003855 }
3856 pw.println(" mArchive=" + mArchive.toString());
3857 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003858 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04003859 while (iter.hasNext()) {
3860 final StatusBarNotification sbn = iter.next();
3861 if (filter != null && !filter.matches(sbn)) continue;
3862 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003863 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04003864 if (iter.hasNext()) pw.println(" ...");
3865 break;
3866 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003867 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003868
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003869 if (!zenOnly) {
3870 N = mEnqueuedNotifications.size();
3871 if (N > 0) {
3872 pw.println(" Enqueued Notification List:");
3873 for (int i = 0; i < N; i++) {
3874 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3875 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3876 nr.dump(pw, " ", getContext(), filter.redact);
3877 }
3878 pw.println(" ");
3879 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003880
3881 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003882 }
3883 }
3884
John Spurlock50806fc2014-07-15 10:22:02 -04003885 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04003886 pw.println("\n Ranking Config:");
3887 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04003888
John Spurlock50806fc2014-07-15 10:22:02 -04003889 pw.println("\n Notification listeners:");
3890 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003891 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3892 pw.print(" mListenersDisablingEffects: (");
3893 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04003894 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003895 final int hint = mListenersDisablingEffects.keyAt(i);
3896 if (i > 0) pw.print(';');
3897 pw.print("hint[" + hint + "]:");
3898
3899 final ArraySet<ManagedServiceInfo> listeners =
3900 mListenersDisablingEffects.valueAt(i);
3901 final int listenerSize = listeners.size();
3902
3903 for (int j = 0; j < listenerSize; j++) {
3904 if (i > 0) pw.print(',');
3905 final ManagedServiceInfo listener = listeners.valueAt(i);
Julia Reynolds1f580572018-04-27 14:48:36 -04003906 if (listener != null) {
3907 pw.print(listener.component);
3908 }
Bryce Lee7219ada2016-04-08 10:54:23 -07003909 }
John Spurlock1fa865f2014-07-21 14:56:39 -04003910 }
3911 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05003912 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003913 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04003914 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003915
Julia Reynolds520df6e2017-02-13 09:05:10 -05003916 if (!filter.filtered || zenOnly) {
3917 pw.println("\n Zen Mode:");
3918 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3919 mZenModeHelper.dump(pw, " ");
3920
3921 pw.println("\n Zen Log:");
3922 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003923 }
3924
John Spurlocke77bb362014-04-26 10:24:59 -04003925 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04003926 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02003927
3928 pw.println("\n Group summaries:");
3929 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3930 NotificationRecord r = entry.getValue();
3931 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3932 if (mNotificationsByKey.get(r.getKey()) != r) {
3933 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04003934 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02003935 }
3936 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003937
3938 if (!zenOnly) {
3939 pw.println("\n Usage Stats:");
3940 mUsageStats.dump(pw, " ", filter);
3941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003942 }
3943 }
3944
Adam Lesinski182f73f2013-12-05 16:48:06 -08003945 /**
3946 * The private API only accessible to the system process.
3947 */
3948 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3949 @Override
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04003950 public NotificationChannel getNotificationChannel(String pkg, int uid, String
3951 channelId) {
3952 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
3953 }
3954
3955 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003956 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003957 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003958 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003959 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003960 }
Christoph Studer365e4c32014-09-18 20:35:36 +02003961
3962 @Override
3963 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3964 int userId) {
3965 checkCallerIsSystem();
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003966 mHandler.post(new Runnable() {
3967 @Override
3968 public void run() {
3969 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003970 removeForegroundServiceFlagByListLocked(
3971 mEnqueuedNotifications, pkg, notificationId, userId);
3972 removeForegroundServiceFlagByListLocked(
3973 mNotificationList, pkg, notificationId, userId);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003974 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003975 }
3976 });
3977 }
3978
Julia Reynolds88860ce2017-06-01 16:55:49 -04003979 @GuardedBy("mNotificationLock")
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003980 private void removeForegroundServiceFlagByListLocked(
Julia Reynolds88860ce2017-06-01 16:55:49 -04003981 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3982 int userId) {
3983 NotificationRecord r = findNotificationByListLocked(
3984 notificationList, pkg, null, notificationId, userId);
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003985 if (r == null) {
3986 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02003987 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003988 StatusBarNotification sbn = r.sbn;
3989 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3990 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3991 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3992 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3993 sbn.getNotification().flags =
Julia Reynoldse5c60452018-04-30 14:41:36 -04003994 (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003995 mRankingHelper.sort(mNotificationList);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06003996 mListeners.notifyPostedLocked(r, r);
Christoph Studer365e4c32014-09-18 20:35:36 +02003997 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003998 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003999
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004000 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04004001 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004002 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04004003 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08004004 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
4005 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04004006 }
John Spurlock7340fc82014-04-24 18:50:12 -04004007 checkCallerIsSystemOrSameApp(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004008
Scott Greenwald9b05c612013-06-25 23:44:05 -04004009 final int userId = ActivityManager.handleIncomingUser(callingPid,
4010 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
Jeff Sharkey65c4a2b2012-09-25 17:22:27 -07004011 final UserHandle user = new UserHandle(userId);
Dianne Hackborn41203752012-08-31 14:05:51 -07004012
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004013 if (pkg == null || notification == null) {
4014 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
4015 + " id=" + id + " notification=" + notification);
4016 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004017
4018 // The system can post notifications for any package, let us resolve that.
4019 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
4020
Julia Reynoldse46bb372016-03-17 11:05:58 -04004021 // Fix the notification as best we can.
4022 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004023 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06004024 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
Julia Reynoldse0d711f2017-09-01 08:50:47 -04004025 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
Julia Reynoldse071abd2017-03-22 10:52:11 -04004026 Notification.addFieldsFromContext(ai, notification);
Julia Reynolds4db59552017-06-30 13:34:01 -04004027
4028 int canColorize = mPackageManagerClient.checkPermission(
4029 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
4030 if (canColorize == PERMISSION_GRANTED) {
4031 notification.flags |= Notification.FLAG_CAN_COLORIZE;
4032 } else {
4033 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
4034 }
4035
Julia Reynoldse46bb372016-03-17 11:05:58 -04004036 } catch (NameNotFoundException e) {
4037 Slog.e(TAG, "Cannot create a context for sending app", e);
4038 return;
4039 }
4040
Chris Wren888b7a82016-06-17 15:47:19 -04004041 mUsageStats.registerEnqueuedByApp(pkg);
4042
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004043 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04004044 String channelId = notification.getChannelId();
4045 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
4046 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05004047 }
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004048 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004049 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004050 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004051 final String noChannelStr = "No Channel found for "
4052 + "pkg=" + pkg
4053 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04004054 + ", id=" + id
4055 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004056 + ", opPkg=" + opPkg
4057 + ", callingUid=" + callingUid
4058 + ", userId=" + userId
4059 + ", incomingUserId=" + incomingUserId
4060 + ", notificationUid=" + notificationUid
4061 + ", notification=" + notification;
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004062 Log.e(TAG, noChannelStr);
Beverly5d4564b2018-04-10 20:09:23 -04004063 boolean appNotificationsOff = mRankingHelper.getImportance(pkg, notificationUid)
4064 == NotificationManager.IMPORTANCE_NONE;
4065
4066 if (!appNotificationsOff) {
4067 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
4068 "Failed to post notification on channel \"" + channelId + "\"\n" +
4069 "See log for more details");
4070 }
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004071 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004072 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004073
Chris Wrena61f1792016-08-04 11:24:42 -04004074 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004075 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004076 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004077 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Rohan Shah590e1b22018-04-10 23:48:47 -04004078 r.setIsAppImportanceLocked(mRankingHelper.getIsAppImportanceLocked(pkg, callingUid));
Chris Wrena61f1792016-08-04 11:24:42 -04004079
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004080 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4081 final boolean fgServiceShown = channel.isFgServiceShown();
4082 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
4083 || !fgServiceShown)
4084 && (r.getImportance() == IMPORTANCE_MIN
4085 || r.getImportance() == IMPORTANCE_NONE)) {
4086 // Increase the importance of foreground service notifications unless the user had
4087 // an opinion otherwise (and the channel hasn't yet shown a fg service).
4088 if (TextUtils.isEmpty(channelId)
4089 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4090 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
4091 } else {
4092 channel.setImportance(IMPORTANCE_LOW);
4093 if (!fgServiceShown) {
4094 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
4095 channel.setFgServiceShown(true);
4096 }
4097 mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
4098 r.updateNotificationChannel(channel);
4099 }
4100 } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
4101 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4102 channel.setFgServiceShown(true);
Julia Reynolds8617e4e2017-09-18 16:52:37 -04004103 r.updateNotificationChannel(channel);
4104 }
4105 }
4106
Julia Reynolds5e702192017-08-18 09:22:40 -04004107 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
4108 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004109 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07004110 }
4111
Felipe Lemedd85da62016-06-28 11:29:54 -07004112 // Whitelist pending intents.
4113 if (notification.allPendingIntents != null) {
4114 final int intentCount = notification.allPendingIntents.size();
4115 if (intentCount > 0) {
4116 final ActivityManagerInternal am = LocalServices
4117 .getService(ActivityManagerInternal.class);
4118 final long duration = LocalServices.getService(
4119 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
4120 for (int i = 0; i < intentCount; i++) {
4121 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4122 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07004123 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4124 WHITELIST_TOKEN, duration);
Felipe Lemedd85da62016-06-28 11:29:54 -07004125 }
4126 }
4127 }
4128 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07004129
Chris Wren47633422016-01-22 09:56:59 -05004130 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004131 }
4132
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04004133 private void doChannelWarningToast(CharSequence toastText) {
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04004134 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04004135 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04004136 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4137 if (warningEnabled) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04004138 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
Geoffrey Pitsch5bdddbd2017-05-26 10:50:05 -04004139 Toast.LENGTH_SHORT);
Geoffrey Pitschd34c1872017-05-04 16:02:15 -04004140 toast.show();
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004141 }
4142 }
4143
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004144 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
4145 // The system can post notifications on behalf of any package it wants
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004146 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004147 try {
4148 return getContext().getPackageManager()
4149 .getPackageUidAsUser(opPackageName, userId);
4150 } catch (NameNotFoundException e) {
4151 /* ignore */
4152 }
4153 }
4154 return callingUid;
4155 }
4156
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004157 /**
4158 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4159 *
4160 * Has side effects.
4161 */
4162 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04004163 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004164 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004165 final boolean isSystemNotification =
4166 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004167 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
4168
4169 // Limit the number of notifications that any given package except the android
4170 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
4171 if (!isSystemNotification && !isNotificationFromListener) {
4172 synchronized (mNotificationLock) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004173 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
4174 // Ephemeral apps have some special constraints for notifications.
4175 // They are not allowed to create new notifications however they are allowed to
4176 // update notifications created by the system (e.g. a foreground service
4177 // notification).
4178 throw new SecurityException("Instant app " + pkg
4179 + " cannot create notifications");
4180 }
4181
4182 // rate limit updates that aren't completed progress notifications
4183 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04004184 && !r.getNotification().hasCompletedProgress()
4185 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004186
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004187 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
4188 if (appEnqueueRate > mMaxPackageEnqueueRate) {
4189 mUsageStats.registerOverRateQuota(pkg);
4190 final long now = SystemClock.elapsedRealtime();
4191 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
4192 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04004193 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004194 mLastOverRateLogTime = now;
4195 }
4196 return false;
4197 }
4198 }
4199
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004200 // limit the number of outstanding notificationrecords an app can have
4201 int count = getNotificationCountLocked(pkg, userId, id, tag);
4202 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
4203 mUsageStats.registerOverCountQuota(pkg);
4204 Slog.e(TAG, "Package has already posted or enqueued " + count
4205 + " notifications. Not showing more. package=" + pkg);
4206 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004207 }
4208 }
4209 }
4210
4211 // snoozed apps
4212 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05004213 MetricsLogger.action(r.getLogMaker()
4214 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
4215 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004216 if (DBG) {
4217 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
4218 }
4219 mSnoozeHelper.update(userId, r);
4220 savePolicyFile();
4221 return false;
4222 }
4223
4224
4225 // blocked apps
4226 if (isBlocked(r, mUsageStats)) {
4227 return false;
4228 }
4229
4230 return true;
4231 }
4232
Andreas Gampea36dc622018-02-05 17:19:22 -08004233 @GuardedBy("mNotificationLock")
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004234 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
4235 String excludedTag) {
4236 int count = 0;
4237 final int N = mNotificationList.size();
4238 for (int i = 0; i < N; i++) {
4239 final NotificationRecord existing = mNotificationList.get(i);
4240 if (existing.sbn.getPackageName().equals(pkg)
4241 && existing.sbn.getUserId() == userId) {
4242 if (existing.sbn.getId() == excludedId
4243 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
4244 continue;
4245 }
4246 count++;
4247 }
4248 }
4249 final int M = mEnqueuedNotifications.size();
4250 for (int i = 0; i < M; i++) {
4251 final NotificationRecord existing = mEnqueuedNotifications.get(i);
4252 if (existing.sbn.getPackageName().equals(pkg)
4253 && existing.sbn.getUserId() == userId) {
4254 count++;
4255 }
4256 }
4257 return count;
4258 }
4259
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004260 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
4261 final String pkg = r.sbn.getPackageName();
4262 final int callingUid = r.sbn.getUid();
4263
Julia Reynolds4da79702017-06-01 11:06:10 -04004264 final boolean isBlocked =
Julia Reynolds005c8b92017-08-24 10:35:53 -04004265 mRankingHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
4266 || mRankingHelper.getImportance(pkg, callingUid)
4267 == NotificationManager.IMPORTANCE_NONE
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04004268 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004269 if (isBlocked) {
4270 Slog.e(TAG, "Suppressing notification from package by user request.");
4271 usageStats.registerBlocked(r);
Beverlyc7858552018-09-14 09:49:07 -04004272 return true;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004273 }
Beverlyc7858552018-09-14 09:49:07 -04004274 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004275 }
4276
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004277 protected class SnoozeNotificationRunnable implements Runnable {
4278 private final String mKey;
4279 private final long mDuration;
4280 private final String mSnoozeCriterionId;
4281
4282 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
4283 mKey = key;
4284 mDuration = duration;
4285 mSnoozeCriterionId = snoozeCriterionId;
4286 }
4287
4288 @Override
4289 public void run() {
4290 synchronized (mNotificationLock) {
4291 final NotificationRecord r = findNotificationByKeyLocked(mKey);
4292 if (r != null) {
4293 snoozeLocked(r);
4294 }
4295 }
4296 }
4297
Julia Reynolds88860ce2017-06-01 16:55:49 -04004298 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004299 void snoozeLocked(NotificationRecord r) {
4300 if (r.sbn.isGroup()) {
4301 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
4302 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
4303 if (r.getNotification().isGroupSummary()) {
4304 // snooze summary and all children
4305 for (int i = 0; i < groupNotifications.size(); i++) {
4306 snoozeNotificationLocked(groupNotifications.get(i));
4307 }
4308 } else {
4309 // if there is a valid summary for this group, and we are snoozing the only
4310 // child, also snooze the summary
4311 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
4312 if (groupNotifications.size() != 2) {
4313 snoozeNotificationLocked(r);
4314 } else {
4315 // snooze summary and the one child
4316 for (int i = 0; i < groupNotifications.size(); i++) {
4317 snoozeNotificationLocked(groupNotifications.get(i));
4318 }
4319 }
4320 } else {
4321 snoozeNotificationLocked(r);
4322 }
4323 }
4324 } else {
4325 // just snooze the one notification
4326 snoozeNotificationLocked(r);
4327 }
4328 }
4329
Julia Reynolds88860ce2017-06-01 16:55:49 -04004330 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004331 void snoozeNotificationLocked(NotificationRecord r) {
4332 MetricsLogger.action(r.getLogMaker()
4333 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4334 .setType(MetricsEvent.TYPE_CLOSE)
Chris Wren21a2e722017-10-02 17:44:53 -04004335 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
4336 mDuration)
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004337 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4338 mSnoozeCriterionId == null ? 0 : 1));
Julia Reynolds0839c022017-06-15 15:24:01 -04004339 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004340 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004341 updateLightsLocked();
4342 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004343 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004344 mSnoozeHelper.snooze(r);
4345 } else {
4346 mSnoozeHelper.snooze(r, mDuration);
4347 }
Julia Reynolds503ed942017-10-04 16:04:56 -04004348 r.recordSnoozed();
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004349 savePolicyFile();
4350 }
4351 }
4352
Julia Reynoldsbaff4002016-12-15 11:34:26 -05004353 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05004354 private final NotificationRecord r;
4355 private final int userId;
4356
4357 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
4358 this.userId = userId;
4359 this.r = r;
4360 };
4361
4362 @Override
4363 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004364 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05004365 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05004366 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05004367
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004368 final StatusBarNotification n = r.sbn;
4369 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
4370 NotificationRecord old = mNotificationsByKey.get(n.getKey());
4371 if (old != null) {
4372 // Retain ranking information from previous record
4373 r.copyRankingInformation(old);
4374 }
4375
4376 final int callingUid = n.getUid();
4377 final int callingPid = n.getInitialPid();
4378 final Notification notification = n.getNotification();
4379 final String pkg = n.getPackageName();
4380 final int id = n.getId();
4381 final String tag = n.getTag();
4382
4383 // Handle grouped notifications and bail out early if we
4384 // can to avoid extracting signals.
4385 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
4386
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004387 // if this is a group child, unsnooze parent summary
4388 if (n.isGroup() && notification.isGroupChild()) {
4389 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
4390 }
4391
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004392 // This conditional is a dirty hack to limit the logging done on
4393 // behalf of the download manager without affecting other apps.
4394 if (!pkg.equals("com.android.providers.downloads")
4395 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
4396 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05004397 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004398 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05004399 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004400 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
4401 pkg, id, tag, userId, notification.toString(),
4402 enqueueStatus);
4403 }
Chris Wren6676dab2016-12-21 18:26:27 -05004404
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004405 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05004406
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004407 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004408 if (mAssistants.isEnabled()) {
4409 mAssistants.onNotificationEnqueued(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004410 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004411 DELAY_FOR_ASSISTANT_TIME);
4412 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004413 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004414 }
4415 }
4416 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004417 }
4418
Beverly5a20a5e2018-03-06 15:02:44 -05004419 @GuardedBy("mNotificationLock")
4420 private boolean isPackageSuspendedLocked(NotificationRecord r) {
4421 final String pkg = r.sbn.getPackageName();
4422 final int callingUid = r.sbn.getUid();
4423
4424 return isPackageSuspendedForUser(pkg, callingUid);
4425 }
4426
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004427 protected class PostNotificationRunnable implements Runnable {
4428 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004429
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004430 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004431 this.key = key;
4432 }
4433
4434 @Override
4435 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004436 synchronized (mNotificationLock) {
4437 try {
4438 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004439 int N = mEnqueuedNotifications.size();
4440 for (int i = 0; i < N; i++) {
4441 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4442 if (Objects.equals(key, enqueued.getKey())) {
4443 r = enqueued;
4444 break;
Chris Wren6676dab2016-12-21 18:26:27 -05004445 }
Chris Wren6676dab2016-12-21 18:26:27 -05004446 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004447 if (r == null) {
4448 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
4449 return;
4450 }
Beverly5a20a5e2018-03-06 15:02:44 -05004451
Beverlyc7858552018-09-14 09:49:07 -04004452 final boolean isPackageSuspended = isPackageSuspendedLocked(r);
4453 r.setHidden(isPackageSuspended);
4454 if (isPackageSuspended) {
4455 mUsageStats.registerSuspendedByAdmin(r);
4456 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004457 NotificationRecord old = mNotificationsByKey.get(key);
4458 final StatusBarNotification n = r.sbn;
4459 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05004460 int index = indexOfNotificationLocked(n.getKey());
4461 if (index < 0) {
4462 mNotificationList.add(r);
4463 mUsageStats.registerPostedByApp(r);
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004464 r.setInterruptive(isVisuallyInterruptive(null, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004465 } else {
4466 old = mNotificationList.get(index);
4467 mNotificationList.set(index, r);
4468 mUsageStats.registerUpdatedByApp(r, old);
4469 // Make sure we don't lose the foreground service state.
4470 notification.flags |=
Julia Reynoldse5c60452018-04-30 14:41:36 -04004471 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
Chris Wren6676dab2016-12-21 18:26:27 -05004472 r.isUpdate = true;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04004473 r.setTextChanged(isVisuallyInterruptive(old, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004474 }
4475
4476 mNotificationsByKey.put(n.getKey(), r);
4477
4478 // Ensure if this is a foreground service that the proper additional
4479 // flags are set.
Julia Reynoldse5c60452018-04-30 14:41:36 -04004480 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
Chris Wren6676dab2016-12-21 18:26:27 -05004481 notification.flags |= Notification.FLAG_ONGOING_EVENT
4482 | Notification.FLAG_NO_CLEAR;
4483 }
4484
4485 applyZenModeLocked(r);
4486 mRankingHelper.sort(mNotificationList);
4487
4488 if (notification.getSmallIcon() != null) {
4489 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06004490 mListeners.notifyPostedLocked(r, old);
Julia Reynolds8aebf352017-06-26 11:35:33 -04004491 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
4492 mHandler.post(new Runnable() {
4493 @Override
4494 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04004495 mGroupHelper.onNotificationPosted(
4496 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04004497 }
4498 });
4499 }
Chris Wren6676dab2016-12-21 18:26:27 -05004500 } else {
4501 Slog.e(TAG, "Not posting notification without small icon: " + notification);
4502 if (old != null && !old.isCanceled) {
Beverly5a20a5e2018-03-06 15:02:44 -05004503 mListeners.notifyRemovedLocked(r,
Julia Reynolds503ed942017-10-04 16:04:56 -04004504 NotificationListenerService.REASON_ERROR, null);
Chris Wren6676dab2016-12-21 18:26:27 -05004505 mHandler.post(new Runnable() {
4506 @Override
4507 public void run() {
4508 mGroupHelper.onNotificationRemoved(n);
4509 }
4510 });
4511 }
4512 // ATTENTION: in a future release we will bail out here
4513 // so that we do not play sounds, show lights, etc. for invalid
4514 // notifications
4515 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
4516 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05004517 }
Chris Wren47633422016-01-22 09:56:59 -05004518
Beverly5a20a5e2018-03-06 15:02:44 -05004519 if (!r.isHidden()) {
4520 buzzBeepBlinkLocked(r);
4521 }
Julia Reynolds1fac86e2018-03-07 08:30:37 -05004522 maybeRecordInterruptionLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004523 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004524 int N = mEnqueuedNotifications.size();
4525 for (int i = 0; i < N; i++) {
4526 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4527 if (Objects.equals(key, enqueued.getKey())) {
4528 mEnqueuedNotifications.remove(i);
4529 break;
4530 }
4531 }
Chris Wren6676dab2016-12-21 18:26:27 -05004532 }
Chris Wren47633422016-01-22 09:56:59 -05004533 }
4534 }
4535 }
4536
Christoph Studer265c1052014-07-23 17:14:33 +02004537 /**
Julia Reynolds7217dc92018-03-07 12:12:09 -05004538 * If the notification differs enough visually, consider it a new interruptive notification.
4539 */
4540 @GuardedBy("mNotificationLock")
4541 @VisibleForTesting
4542 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
Julia Reynolds6b302d02018-06-19 15:39:23 -04004543 // Ignore summary updates because we don't display most of the information.
4544 if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
4545 if (DEBUG_INTERRUPTIVENESS) {
4546 Log.v(TAG, "INTERRUPTIVENESS: "
4547 + r.getKey() + " is not interruptive: summary");
4548 }
4549 return false;
4550 }
4551
Dan Sandler7d67bd42018-05-15 14:06:38 -04004552 if (old == null) {
4553 if (DEBUG_INTERRUPTIVENESS) {
4554 Log.v(TAG, "INTERRUPTIVENESS: "
4555 + r.getKey() + " is interruptive: new notification");
4556 }
4557 return true;
4558 }
4559
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004560 if (r == null) {
4561 if (DEBUG_INTERRUPTIVENESS) {
4562 Log.v(TAG, "INTERRUPTIVENESS: "
4563 + r.getKey() + " is not interruptive: null");
4564 }
4565 return false;
4566 }
4567
Julia Reynolds7217dc92018-03-07 12:12:09 -05004568 Notification oldN = old.sbn.getNotification();
4569 Notification newN = r.sbn.getNotification();
Dan Sandler7d67bd42018-05-15 14:06:38 -04004570
Julia Reynolds7217dc92018-03-07 12:12:09 -05004571 if (oldN.extras == null || newN.extras == null) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004572 if (DEBUG_INTERRUPTIVENESS) {
4573 Log.v(TAG, "INTERRUPTIVENESS: "
4574 + r.getKey() + " is not interruptive: no extras");
4575 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004576 return false;
4577 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004578
4579 // Ignore visual interruptions from foreground services because users
4580 // consider them one 'session'. Count them for everything else.
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004581 if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004582 if (DEBUG_INTERRUPTIVENESS) {
4583 Log.v(TAG, "INTERRUPTIVENESS: "
4584 + r.getKey() + " is not interruptive: foreground service");
4585 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004586 return false;
4587 }
4588
Dan Sandler7d67bd42018-05-15 14:06:38 -04004589 final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
4590 final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
4591 if (!Objects.equals(oldTitle, newTitle)) {
4592 if (DEBUG_INTERRUPTIVENESS) {
4593 Log.v(TAG, "INTERRUPTIVENESS: "
4594 + r.getKey() + " is interruptive: changed title");
4595 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)",
4596 oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
4597 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)",
4598 newTitle, newTitle.getClass(), newTitle.hashCode()));
4599 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004600 return true;
4601 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004602 // Do not compare Spannables (will always return false); compare unstyled Strings
4603 final String oldText = String.valueOf(oldN.extras.get(Notification.EXTRA_TEXT));
4604 final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT));
4605 if (!Objects.equals(oldText, newText)) {
4606 if (DEBUG_INTERRUPTIVENESS) {
4607 Log.v(TAG, "INTERRUPTIVENESS: "
4608 + r.getKey() + " is interruptive: changed text");
4609 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)",
4610 oldText, oldText.getClass(), oldText.hashCode()));
4611 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)",
4612 newText, newText.getClass(), newText.hashCode()));
4613 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004614 return true;
4615 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004616 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
4617 if (DEBUG_INTERRUPTIVENESS) {
4618 Log.v(TAG, "INTERRUPTIVENESS: "
4619 + r.getKey() + " is interruptive: completed progress");
4620 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004621 return true;
4622 }
4623 // Actions
4624 if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004625 if (DEBUG_INTERRUPTIVENESS) {
4626 Log.v(TAG, "INTERRUPTIVENESS: "
4627 + r.getKey() + " is interruptive: changed actions");
4628 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004629 return true;
4630 }
4631
4632 try {
4633 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
4634 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
4635
4636 // Style based comparisons
4637 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004638 if (DEBUG_INTERRUPTIVENESS) {
4639 Log.v(TAG, "INTERRUPTIVENESS: "
4640 + r.getKey() + " is interruptive: styles differ");
4641 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004642 return true;
4643 }
4644
4645 // Remote views
4646 if (Notification.areRemoteViewsChanged(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004647 if (DEBUG_INTERRUPTIVENESS) {
4648 Log.v(TAG, "INTERRUPTIVENESS: "
4649 + r.getKey() + " is interruptive: remoteviews differ");
4650 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004651 return true;
4652 }
4653 } catch (Exception e) {
4654 Slog.w(TAG, "error recovering builder", e);
4655 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004656
Julia Reynolds7217dc92018-03-07 12:12:09 -05004657 return false;
4658 }
4659
4660 /**
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05004661 * Keeps the last 5 packages that have notified, by user.
4662 */
4663 @GuardedBy("mNotificationLock")
4664 @VisibleForTesting
4665 protected void logRecentLocked(NotificationRecord r) {
4666 if (r.isUpdate) {
4667 return;
4668 }
4669 ArrayList<NotifyingApp> recentAppsForUser =
4670 mRecentApps.getOrDefault(r.getUser().getIdentifier(), new ArrayList<>(6));
4671 NotifyingApp na = new NotifyingApp()
4672 .setPackage(r.sbn.getPackageName())
4673 .setUid(r.sbn.getUid())
4674 .setLastNotified(r.sbn.getPostTime());
4675 // A new notification gets an app moved to the front of the list
4676 for (int i = recentAppsForUser.size() - 1; i >= 0; i--) {
4677 NotifyingApp naExisting = recentAppsForUser.get(i);
4678 if (na.getPackage().equals(naExisting.getPackage())
4679 && na.getUid() == naExisting.getUid()) {
4680 recentAppsForUser.remove(i);
4681 break;
4682 }
4683 }
4684 // time is always increasing, so always add to the front of the list
4685 recentAppsForUser.add(0, na);
4686 if (recentAppsForUser.size() > 5) {
4687 recentAppsForUser.remove(recentAppsForUser.size() -1);
4688 }
4689 mRecentApps.put(r.getUser().getIdentifier(), recentAppsForUser);
4690 }
4691
4692 /**
Christoph Studer265c1052014-07-23 17:14:33 +02004693 * Ensures that grouped notification receive their special treatment.
4694 *
4695 * <p>Cancels group children if the new notification causes a group to lose
4696 * its summary.</p>
4697 *
4698 * <p>Updates mSummaryByGroupKey.</p>
4699 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004700 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02004701 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
4702 int callingUid, int callingPid) {
4703 StatusBarNotification sbn = r.sbn;
4704 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07004705 if (n.isGroupSummary() && !sbn.isAppGroup()) {
4706 // notifications without a group shouldn't be a summary, otherwise autobundling can
4707 // lead to bugs
4708 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
4709 }
4710
Christoph Studer265c1052014-07-23 17:14:33 +02004711 String group = sbn.getGroupKey();
4712 boolean isSummary = n.isGroupSummary();
4713
4714 Notification oldN = old != null ? old.sbn.getNotification() : null;
4715 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
4716 boolean oldIsSummary = old != null && oldN.isGroupSummary();
4717
4718 if (oldIsSummary) {
4719 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
4720 if (removedSummary != old) {
4721 String removedKey =
4722 removedSummary != null ? removedSummary.getKey() : "<null>";
4723 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
4724 ", removed=" + removedKey);
4725 }
4726 }
4727 if (isSummary) {
4728 mSummaryByGroupKey.put(group, r);
4729 }
4730
4731 // Clear out group children of the old notification if the update
4732 // causes the group summary to go away. This happens when the old
4733 // notification was a summary and the new one isn't, or when the old
4734 // notification was a summary and its group key changed.
4735 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04004736 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
4737 null);
Christoph Studer265c1052014-07-23 17:14:33 +02004738 }
4739 }
4740
Chris Wren93bb8b82016-03-29 14:35:05 -04004741 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004742 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05004743 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04004744 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05004745 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4746 REQUEST_CODE_TIMEOUT,
4747 new Intent(ACTION_NOTIFICATION_TIMEOUT)
4748 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4749 .appendPath(record.getKey()).build())
4750 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4751 .putExtra(EXTRA_KEY, record.getKey()),
4752 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05004753 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04004754 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05004755 }
4756 }
4757
4758 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004759 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04004760 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04004761 boolean buzz = false;
4762 boolean beep = false;
4763 boolean blink = false;
4764
Chris Wrena3446562014-06-03 18:11:47 -04004765 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04004766 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04004767
4768 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04004769 final boolean aboveThreshold =
4770 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04004771
4772 // Remember if this notification already owns the notification channels.
4773 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4774 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04004775 // These are set inside the conditional if the notification is allowed to make noise.
4776 boolean hasValidVibrate = false;
4777 boolean hasValidSound = false;
Julia Reynolds94187562017-10-10 13:58:49 -04004778 boolean sentAccessibilityEvent = false;
4779 // If the notification will appear in the status bar, it should send an accessibility
4780 // event
4781 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4782 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4783 sentAccessibilityEvent = true;
4784 }
Chris Wrena3446562014-06-03 18:11:47 -04004785
Julia Reynolds76c096d2017-06-19 08:16:04 -04004786 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004787
Julia Reynolds76c096d2017-06-19 08:16:04 -04004788 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004789 Uri soundUri = record.getSound();
4790 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4791 long[] vibration = record.getVibration();
4792 // Demote sound to vibration if vibration missing & phone in vibration mode.
4793 if (vibration == null
4794 && hasValidSound
4795 && (mAudioManager.getRingerModeInternal()
Julia Reynolds85896572017-09-20 12:54:52 -04004796 == AudioManager.RINGER_MODE_VIBRATE)
4797 && mAudioManager.getStreamVolume(
4798 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004799 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04004800 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004801 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01004802
Julia Reynolds76c096d2017-06-19 08:16:04 -04004803 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
Julia Reynolds76c096d2017-06-19 08:16:04 -04004804 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004805 if (!sentAccessibilityEvent) {
4806 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4807 sentAccessibilityEvent = true;
4808 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004809 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04004810 if (hasValidSound) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004811 if (mInCall) {
4812 playInCallNotification();
4813 beep = true;
4814 } else {
4815 beep = playSound(record, soundUri);
4816 }
Seungho Lee2ca1aec2018-12-09 19:27:36 +09004817 if(beep) {
4818 mSoundNotificationKey = key;
4819 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004820 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004821
Julia Reynolds7c96b582017-05-25 12:35:36 -04004822 final boolean ringerModeSilent =
4823 mAudioManager.getRingerModeInternal()
4824 == AudioManager.RINGER_MODE_SILENT;
4825 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004826 buzz = playVibration(record, vibration, hasValidSound);
Seungho Lee2ca1aec2018-12-09 19:27:36 +09004827 if(buzz) {
4828 mVibrateNotificationKey = key;
4829 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004830 }
Chris Wrena3446562014-06-03 18:11:47 -04004831 }
4832 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004833 }
4834 // If a notification is updated to remove the actively playing sound or vibrate,
4835 // cancel that feedback now
4836 if (wasBeep && !hasValidSound) {
4837 clearSoundLocked();
4838 }
4839 if (wasBuzz && !hasValidVibrate) {
4840 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04004841 }
4842
4843 // light
4844 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04004845 boolean wasShowLights = mLights.remove(key);
Julia Reynolds54369232018-07-03 10:43:35 -04004846 if (canShowLightsLocked(record, aboveThreshold)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04004847 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04004848 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04004849 if (mUseAttentionLight) {
4850 mAttentionLight.pulse();
4851 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004852 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04004853 } else if (wasShowLights) {
4854 updateLightsLocked();
4855 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004856 if (buzz || beep || blink) {
Julia Reynolds54369232018-07-03 10:43:35 -04004857 // Ignore summary updates because we don't display most of the information.
4858 if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) {
4859 if (DEBUG_INTERRUPTIVENESS) {
4860 Log.v(TAG, "INTERRUPTIVENESS: "
4861 + record.getKey() + " is not interruptive: summary");
4862 }
4863 } else {
4864 if (DEBUG_INTERRUPTIVENESS) {
4865 Log.v(TAG, "INTERRUPTIVENESS: "
4866 + record.getKey() + " is interruptive: alerted");
4867 }
4868 record.setInterruptive(true);
4869 }
Julia Reynolds445cfa82017-05-08 15:41:45 -04004870 MetricsLogger.action(record.getLogMaker()
4871 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4872 .setType(MetricsEvent.TYPE_OPEN)
4873 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4874 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04004875 }
Chris Wrena3446562014-06-03 18:11:47 -04004876 }
4877
Julia Reynolds88860ce2017-06-01 16:55:49 -04004878 @GuardedBy("mNotificationLock")
Julia Reynolds54369232018-07-03 10:43:35 -04004879 boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
4880 // device lacks light
4881 if (!mHasLight) {
4882 return false;
4883 }
4884 // user turned lights off globally
4885 if (!mNotificationPulseEnabled) {
4886 return false;
4887 }
4888 // the notification/channel has no light
4889 if (record.getLight() == null) {
4890 return false;
4891 }
4892 // unimportant notification
4893 if (!aboveThreshold) {
4894 return false;
4895 }
4896 // suppressed due to DND
4897 if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
4898 return false;
4899 }
4900 // Suppressed because it's a silent update
4901 final Notification notification = record.getNotification();
4902 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4903 return false;
4904 }
4905 // Suppressed because another notification in its group handles alerting
4906 if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
4907 return false;
4908 }
4909 // not if in call or the screen's on
4910 if (mInCall || mScreenOn) {
4911 return false;
4912 }
4913
4914 return true;
4915 }
4916
4917 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004918 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04004919 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004920 final Notification notification = record.getNotification();
Julia Reynolds54369232018-07-03 10:43:35 -04004921 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004922 return true;
4923 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004924
Julia Reynolds76c096d2017-06-19 08:16:04 -04004925 // muted by listener
4926 final String disableEffects = disableNotificationEffects(record);
4927 if (disableEffects != null) {
4928 ZenLog.traceDisableEffects(record, disableEffects);
4929 return true;
4930 }
4931
4932 // suppressed due to DND
4933 if (record.isIntercepted()) {
4934 return true;
4935 }
4936
4937 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004938 if (record.sbn.isGroup()) {
Julia Reynolds79dfdd62018-04-17 15:36:33 -04004939 if (notification.suppressAlertingDueToGrouping()) {
4940 return true;
4941 }
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004942 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004943
Julia Reynolds65b85cf2017-07-20 09:19:20 -04004944 // Suppressed for being too recently noisy
4945 final String pkg = record.sbn.getPackageName();
4946 if (mUsageStats.isAlertRateLimited(pkg)) {
4947 Slog.e(TAG, "Muting recently noisy " + record.getKey());
4948 return true;
4949 }
4950
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004951 return false;
4952 }
4953
Julia Reynolds0c299d42016-11-15 14:37:04 -05004954 private boolean playSound(final NotificationRecord record, Uri soundUri) {
4955 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
Jean-Michel Triviec2bb182018-03-23 18:04:00 -07004956 // play notifications if there is no user of exclusive audio focus
4957 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
4958 // VIBRATE ringer mode)
4959 if (!mAudioManager.isAudioFocusExclusive()
4960 && (mAudioManager.getStreamVolume(
4961 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05004962 final long identity = Binder.clearCallingIdentity();
4963 try {
4964 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4965 if (player != null) {
4966 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4967 + " with attributes " + record.getAudioAttributes());
4968 player.playAsync(soundUri, record.sbn.getUser(), looping,
4969 record.getAudioAttributes());
4970 return true;
4971 }
4972 } catch (RemoteException e) {
4973 } finally {
4974 Binder.restoreCallingIdentity(identity);
4975 }
4976 }
4977 return false;
4978 }
4979
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004980 private boolean playVibration(final NotificationRecord record, long[] vibration,
4981 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004982 // Escalate privileges so we can use the vibrator even if the
4983 // notifying app does not have the VIBRATE permission.
4984 long identity = Binder.clearCallingIdentity();
4985 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004986 final VibrationEffect effect;
4987 try {
4988 final boolean insistent =
4989 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4990 effect = VibrationEffect.createWaveform(
4991 vibration, insistent ? 0 : -1 /*repeatIndex*/);
4992 } catch (IllegalArgumentException e) {
4993 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4994 Arrays.toString(vibration));
4995 return false;
4996 }
4997 if (delayVibForSound) {
4998 new Thread(() -> {
4999 // delay the vibration by the same amount as the notification sound
5000 final int waitMs = mAudioManager.getFocusRampTimeMs(
5001 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
5002 record.getAudioAttributes());
5003 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
5004 try {
5005 Thread.sleep(waitMs);
5006 } catch (InterruptedException e) { }
Seungho Lee0e97ae62018-10-31 21:49:09 +09005007
5008 // Notifications might be canceled before it actually vibrates due to waitMs,
5009 // so need to check the notification still valide for vibrate.
5010 synchronized (mNotificationLock) {
5011 if (mNotificationsByKey.get(record.getKey()) != null) {
5012 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
5013 effect, record.getAudioAttributes());
5014 } else {
5015 Slog.e(TAG, "No vibration for canceled notification : " + record.getKey());
5016 }
5017 }
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005018 }).start();
5019 } else {
5020 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
5021 effect, record.getAudioAttributes());
5022 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005023 return true;
5024 } finally{
5025 Binder.restoreCallingIdentity(identity);
5026 }
5027 }
5028
Julia Reynolds7c96b582017-05-25 12:35:36 -04005029 private boolean isNotificationForCurrentUser(NotificationRecord record) {
5030 final int currentUser;
5031 final long token = Binder.clearCallingIdentity();
5032 try {
5033 currentUser = ActivityManager.getCurrentUser();
5034 } finally {
5035 Binder.restoreCallingIdentity(token);
5036 }
5037 return (record.getUserId() == UserHandle.USER_ALL ||
5038 record.getUserId() == currentUser ||
5039 mUserProfiles.isCurrentProfile(record.getUserId()));
5040 }
5041
Beverly5d463b62017-07-26 14:13:40 -04005042 protected void playInCallNotification() {
Marta Białka39c992f2011-03-10 10:27:24 +01005043 new Thread() {
5044 @Override
5045 public void run() {
Beverly5d463b62017-07-26 14:13:40 -04005046 final long identity = Binder.clearCallingIdentity();
Marta Białka39c992f2011-03-10 10:27:24 +01005047 try {
Beverly5d463b62017-07-26 14:13:40 -04005048 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5049 if (player != null) {
luochaojiang50e5273c2018-04-16 16:55:03 +08005050 if (mCallNotificationToken != null) {
5051 player.stop(mCallNotificationToken);
5052 }
5053 mCallNotificationToken = new Binder();
5054 player.play(mCallNotificationToken, mInCallNotificationUri,
Beverly5d463b62017-07-26 14:13:40 -04005055 mInCallNotificationAudioAttributes,
5056 mInCallNotificationVolume, false);
Marta Białka39c992f2011-03-10 10:27:24 +01005057 }
Beverly5d463b62017-07-26 14:13:40 -04005058 } catch (RemoteException e) {
5059 } finally {
5060 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01005061 }
5062 }
5063 }.start();
5064 }
5065
Julia Reynolds88860ce2017-06-01 16:55:49 -04005066 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005067 void showNextToastLocked() {
5068 ToastRecord record = mToastQueue.get(0);
5069 while (record != null) {
5070 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
5071 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005072 record.callback.show(record.token);
Robert Carr997427342018-02-28 18:06:10 -08005073 scheduleDurationReachedLocked(record);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005074 return;
5075 } catch (RemoteException e) {
5076 Slog.w(TAG, "Object died trying to show notification " + record.callback
5077 + " in package " + record.pkg);
5078 // remove it from the list and let the process die
5079 int index = mToastQueue.indexOf(record);
5080 if (index >= 0) {
5081 mToastQueue.remove(index);
5082 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005083 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005084 if (mToastQueue.size() > 0) {
5085 record = mToastQueue.get(0);
5086 } else {
5087 record = null;
5088 }
5089 }
5090 }
5091 }
5092
Julia Reynolds88860ce2017-06-01 16:55:49 -04005093 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005094 void cancelToastLocked(int index) {
5095 ToastRecord record = mToastQueue.get(index);
5096 try {
5097 record.callback.hide();
5098 } catch (RemoteException e) {
5099 Slog.w(TAG, "Object died trying to hide notification " + record.callback
5100 + " in package " + record.pkg);
5101 // don't worry about this, we're about to remove it from
5102 // the list anyway
5103 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005104
5105 ToastRecord lastToast = mToastQueue.remove(index);
Robert Carr997427342018-02-28 18:06:10 -08005106
5107 mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
5108 DEFAULT_DISPLAY);
5109 // We passed 'false' for 'removeWindows' so that the client has time to stop
5110 // rendering (as hide above is a one-way message), otherwise we could crash
5111 // a client which was actively using a surface made from the token. However
5112 // we need to schedule a timeout to make sure the token is eventually killed
5113 // one way or another.
5114 scheduleKillTokenTimeout(lastToast.token);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005115
5116 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005117 if (mToastQueue.size() > 0) {
5118 // Show the next one. If the callback fails, this will remove
5119 // it from the list, so don't assume that the list hasn't changed
5120 // after this point.
5121 showNextToastLocked();
5122 }
5123 }
5124
Robert Carr997427342018-02-28 18:06:10 -08005125 void finishTokenLocked(IBinder t) {
5126 mHandler.removeCallbacksAndMessages(t);
5127 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
5128 // remaining surfaces as either the client has called finishToken indicating
5129 // it has successfully removed the views, or the client has timed out
5130 // at which point anything goes.
5131 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */,
5132 DEFAULT_DISPLAY);
5133 }
5134
Julia Reynolds88860ce2017-06-01 16:55:49 -04005135 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08005136 private void scheduleDurationReachedLocked(ToastRecord r)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005137 {
5138 mHandler.removeCallbacksAndMessages(r);
Robert Carr997427342018-02-28 18:06:10 -08005139 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005140 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
5141 mHandler.sendMessageDelayed(m, delay);
5142 }
5143
Robert Carr997427342018-02-28 18:06:10 -08005144 private void handleDurationReached(ToastRecord record)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005145 {
5146 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
5147 synchronized (mToastQueue) {
5148 int index = indexOfToastLocked(record.pkg, record.callback);
5149 if (index >= 0) {
5150 cancelToastLocked(index);
5151 }
5152 }
5153 }
5154
Julia Reynolds88860ce2017-06-01 16:55:49 -04005155 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08005156 private void scheduleKillTokenTimeout(IBinder token)
5157 {
5158 mHandler.removeCallbacksAndMessages(token);
5159 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, token);
Robert Carr3406d462018-03-15 16:19:07 -07005160 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
Robert Carr997427342018-02-28 18:06:10 -08005161 }
5162
5163 private void handleKillTokenTimeout(IBinder token)
5164 {
5165 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + token);
5166 synchronized (mToastQueue) {
5167 finishTokenLocked(token);
5168 }
5169 }
5170
5171 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005172 int indexOfToastLocked(String pkg, ITransientNotification callback)
5173 {
5174 IBinder cbak = callback.asBinder();
5175 ArrayList<ToastRecord> list = mToastQueue;
5176 int len = list.size();
5177 for (int i=0; i<len; i++) {
5178 ToastRecord r = list.get(i);
Beverly Tai98efc792018-06-11 14:50:36 +00005179 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08005180 return i;
5181 }
5182 }
5183 return -1;
5184 }
5185
Julia Reynolds88860ce2017-06-01 16:55:49 -04005186 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005187 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005188 {
5189 int toastCount = 0; // toasts from this pid
5190 ArrayList<ToastRecord> list = mToastQueue;
5191 int N = list.size();
5192 for (int i=0; i<N; i++) {
5193 ToastRecord r = list.get(i);
5194 if (r.pid == pid) {
5195 toastCount++;
5196 }
5197 }
5198 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07005199 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08005200 } catch (RemoteException e) {
5201 // Shouldn't happen.
5202 }
5203 }
5204
Chris Wrenf9536642014-04-17 10:01:54 -04005205 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005206 if (!(message.obj instanceof RankingReconsideration)) return;
5207 RankingReconsideration recon = (RankingReconsideration) message.obj;
5208 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04005209 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005210 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005211 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
5212 if (record == null) {
5213 return;
Chris Wrenf9536642014-04-17 10:01:54 -04005214 }
Chris Wren333a61c2014-05-28 16:40:57 -04005215 int indexBefore = findNotificationRecordIndexLocked(record);
5216 boolean interceptBefore = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005217 float contactAffinityBefore = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005218 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04005219 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04005220 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04005221 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04005222 int indexAfter = findNotificationRecordIndexLocked(record);
5223 boolean interceptAfter = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005224 float contactAffinityAfter = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005225 int visibilityAfter = record.getPackageVisibilityOverride();
5226 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
5227 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005228 if (interceptBefore && !interceptAfter
5229 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
Chris Wrena3446562014-06-03 18:11:47 -04005230 buzzBeepBlinkLocked(record);
5231 }
Chris Wrenf9536642014-04-17 10:01:54 -04005232 }
Chris Wren333a61c2014-05-28 16:40:57 -04005233 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005234 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04005235 }
5236 }
5237
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005238 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04005239 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005240 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04005241 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005242 // Any field that can change via one of the extractors needs to be added here.
5243 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005244 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05005245 boolean[] showBadges = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005246 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
5247 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
5248 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
5249 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Julia Reynolds503ed942017-10-04 16:04:56 -04005250 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005251 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
Chris Wren54bbef42014-07-09 18:37:56 -04005252 for (int i = 0; i < N; i++) {
5253 final NotificationRecord r = mNotificationList.get(i);
5254 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005255 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05005256 showBadges[i] = r.canShowBadge();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005257 channelBefore.add(r.getChannel());
5258 groupKeyBefore.add(r.getGroupKey());
5259 overridePeopleBefore.add(r.getPeopleOverride());
5260 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Julia Reynolds503ed942017-10-04 16:04:56 -04005261 userSentimentBefore.add(r.getUserSentiment());
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005262 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
Chris Wren54bbef42014-07-09 18:37:56 -04005263 mRankingHelper.extractSignals(r);
5264 }
Chris Wren19a02b02015-12-22 10:34:22 -05005265 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04005266 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005267 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005268 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05005269 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005270 || showBadges[i] != r.canShowBadge()
5271 || !Objects.equals(channelBefore.get(i), r.getChannel())
5272 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
5273 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
Julia Reynolds503ed942017-10-04 16:04:56 -04005274 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005275 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
5276 || !Objects.equals(suppressVisuallyBefore.get(i),
5277 r.getSuppressedVisualEffects())) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005278 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04005279 return;
5280 }
5281 }
5282 }
5283 }
5284
Julia Reynolds88860ce2017-06-01 16:55:49 -04005285 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005286 private void recordCallerLocked(NotificationRecord record) {
5287 if (mZenModeHelper.isCall(record)) {
5288 mZenModeHelper.recordCaller(record);
5289 }
5290 }
5291
Christoph Studerd5092bc2014-07-03 17:47:58 +02005292 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04005293 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005294 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02005295 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005296 if (record.isIntercepted()) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05005297 record.setSuppressedVisualEffects(
5298 mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
Julia Reynolds445cfa82017-05-08 15:41:45 -04005299 } else {
5300 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005301 }
Chris Wren333a61c2014-05-28 16:40:57 -04005302 }
5303
Julia Reynolds88860ce2017-06-01 16:55:49 -04005304 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04005305 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04005306 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04005307 }
5308
Chris Wrenf9536642014-04-17 10:01:54 -04005309 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005310 synchronized (mNotificationLock) {
Beverly5a20a5e2018-03-06 15:02:44 -05005311 mListeners.notifyRankingUpdateLocked(null);
Chris Wrenf9536642014-04-17 10:01:54 -04005312 }
5313 }
5314
John Spurlockd8afe3c2014-08-01 14:04:07 -04005315 private void scheduleListenerHintsChanged(int state) {
5316 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
5317 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04005318 }
5319
Christoph Studer85a384b2014-08-27 20:16:15 +02005320 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
5321 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
5322 mHandler.obtainMessage(
5323 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
5324 listenerInterruptionFilter,
5325 0).sendToTarget();
5326 }
5327
John Spurlockd8afe3c2014-08-01 14:04:07 -04005328 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005329 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005330 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005331 }
5332 }
5333
Christoph Studer85a384b2014-08-27 20:16:15 +02005334 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005335 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02005336 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
5337 }
5338 }
5339
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005340 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08005341 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005342 public WorkerHandler(Looper looper) {
5343 super(looper);
5344 }
5345
Adam Lesinski182f73f2013-12-05 16:48:06 -08005346 @Override
5347 public void handleMessage(Message msg)
5348 {
5349 switch (msg.what)
5350 {
Robert Carr997427342018-02-28 18:06:10 -08005351 case MESSAGE_DURATION_REACHED:
5352 handleDurationReached((ToastRecord)msg.obj);
5353 break;
5354 case MESSAGE_FINISH_TOKEN_TIMEOUT:
5355 handleKillTokenTimeout((IBinder)msg.obj);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005356 break;
John Spurlock056c5192014-04-20 21:52:01 -04005357 case MESSAGE_SAVE_POLICY_FILE:
5358 handleSavePolicyFile();
5359 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005360 case MESSAGE_SEND_RANKING_UPDATE:
5361 handleSendRankingUpdate();
5362 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04005363 case MESSAGE_LISTENER_HINTS_CHANGED:
5364 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04005365 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02005366 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
5367 handleListenerInterruptionFilterChanged(msg.arg1);
5368 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005369 }
5370 }
5371
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005372 protected void scheduleSendRankingUpdate() {
5373 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
5374 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
5375 sendMessage(m);
5376 }
5377 }
5378
Chris Wrenf9536642014-04-17 10:01:54 -04005379 }
5380
Chris Wren51017d02015-12-15 15:34:46 -05005381 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04005382 {
Chris Wren51017d02015-12-15 15:34:46 -05005383 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04005384 super(looper);
5385 }
5386
5387 @Override
5388 public void handleMessage(Message msg) {
5389 switch (msg.what) {
5390 case MESSAGE_RECONSIDER_RANKING:
5391 handleRankingReconsideration(msg);
5392 break;
Chris Wren51017d02015-12-15 15:34:46 -05005393 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005394 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04005395 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08005396 }
5397 }
Chris Wren51017d02015-12-15 15:34:46 -05005398
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005399 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05005400 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05005401 Message msg = Message.obtain();
5402 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05005403 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05005404 }
5405
5406 public void requestReconsideration(RankingReconsideration recon) {
5407 Message m = Message.obtain(this,
5408 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
5409 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
5410 sendMessageDelayed(m, delay);
5411 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08005412 }
5413
Adam Lesinski182f73f2013-12-05 16:48:06 -08005414 // Notifications
5415 // ============================================================================
5416 static int clamp(int x, int low, int high) {
5417 return (x < low) ? low : ((x > high) ? high : x);
5418 }
5419
5420 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
Eugene Suslad4128ec2017-12-04 19:48:41 +00005421 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07005422 return;
5423 }
5424
5425 AccessibilityEvent event =
5426 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
5427 event.setPackageName(packageName);
5428 event.setClassName(Notification.class.getName());
5429 event.setParcelableData(notification);
5430 CharSequence tickerText = notification.tickerText;
5431 if (!TextUtils.isEmpty(tickerText)) {
5432 event.getText().add(tickerText);
5433 }
5434
Julia Reynolds94187562017-10-10 13:58:49 -04005435 mAccessibilityManager.sendAccessibilityEvent(event);
svetoslavganov75986cf2009-05-14 22:28:01 -07005436 }
5437
Julia Reynolds0839c022017-06-15 15:24:01 -04005438 /**
5439 * Removes all NotificationsRecords with the same key as the given notification record
5440 * from both lists. Do not call this method while iterating over either list.
5441 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005442 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04005443 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
5444 // Remove from both lists, either list could have a separate Record for what is
5445 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005446 boolean wasPosted = false;
5447 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04005448 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
5449 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005450 mNotificationList.remove(recordInList);
5451 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005452 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005453 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005454 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005455 != null) {
5456 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005457 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005458 return wasPosted;
5459 }
5460
5461 @GuardedBy("mNotificationLock")
5462 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04005463 boolean wasPosted, String listenerName) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005464 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName);
5465 }
5466
5467 @GuardedBy("mNotificationLock")
5468 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
5469 int rank, int count, boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04005470 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005471
5472 // Record caller.
5473 recordCallerLocked(r);
5474
Julia Reynolds503ed942017-10-04 16:04:56 -04005475 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
5476 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
5477 }
5478
Joe Onorato46439ce2010-11-19 13:56:21 -08005479 // tell the app
5480 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005481 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08005482 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005483 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08005484 } catch (PendingIntent.CanceledException ex) {
5485 // do nothing - there's no relevant way to recover, and
5486 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04005487 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08005488 }
5489 }
5490 }
5491
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005492 // Only cancel these if this notification actually got to be posted.
5493 if (wasPosted) {
5494 // status bar
5495 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005496 if (reason != REASON_SNOOZED) {
5497 r.isCanceled = true;
5498 }
Beverly5a20a5e2018-03-06 15:02:44 -05005499 mListeners.notifyRemovedLocked(r, reason, r.getStats());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005500 mHandler.post(new Runnable() {
5501 @Override
5502 public void run() {
5503 mGroupHelper.onNotificationRemoved(r.sbn);
5504 }
5505 });
5506 }
5507
5508 // sound
5509 if (canceledKey.equals(mSoundNotificationKey)) {
5510 mSoundNotificationKey = null;
5511 final long identity = Binder.clearCallingIdentity();
5512 try {
5513 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5514 if (player != null) {
5515 player.stopAsync();
5516 }
5517 } catch (RemoteException e) {
5518 } finally {
5519 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04005520 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005521 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005522
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005523 // vibrate
5524 if (canceledKey.equals(mVibrateNotificationKey)) {
5525 mVibrateNotificationKey = null;
5526 long identity = Binder.clearCallingIdentity();
5527 try {
5528 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005529 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005530 finally {
5531 Binder.restoreCallingIdentity(identity);
5532 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005533 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005534
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005535 // light
5536 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005537 }
5538
Christoph Studer546bec82014-03-14 12:17:12 +01005539 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04005540 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01005541 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005542 case REASON_CANCEL:
5543 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005544 case REASON_LISTENER_CANCEL:
5545 case REASON_LISTENER_CANCEL_ALL:
5546 mUsageStats.registerDismissedByUser(r);
5547 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05005548 case REASON_APP_CANCEL:
5549 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005550 mUsageStats.registerRemovedByApp(r);
5551 break;
Christoph Studer546bec82014-03-14 12:17:12 +01005552 }
5553
Christoph Studer265c1052014-07-23 17:14:33 +02005554 String groupKey = r.getGroupKey();
5555 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005556 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02005557 mSummaryByGroupKey.remove(groupKey);
5558 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04005559 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
5560 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
5561 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04005562 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005563
Daniel Sandler23d7c702013-03-07 16:32:06 -05005564 // Save it for users of getHistoricalNotifications()
5565 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02005566
Chris Wren6650e572015-05-15 17:19:25 -04005567 final long now = System.currentTimeMillis();
Dieter Hsud39f0d52018-04-14 02:08:30 +08005568 final LogMaker logMaker = r.getLogMaker(now)
Chris Wren9eb5e102017-01-26 13:15:06 -05005569 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
5570 .setType(MetricsEvent.TYPE_DISMISS)
Dieter Hsud39f0d52018-04-14 02:08:30 +08005571 .setSubtype(reason);
5572 if (rank != -1 && count != -1) {
5573 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
5574 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
5575 }
5576 MetricsLogger.action(logMaker);
Chris Wrene6ddb8a2015-05-27 15:21:00 -04005577 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Dieter Hsud39f0d52018-04-14 02:08:30 +08005578 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
5579 rank, count, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005580 }
5581
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005582 @VisibleForTesting
5583 void updateUriPermissions(@Nullable NotificationRecord newRecord,
5584 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) {
5585 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey();
5586 if (DBG) Slog.d(TAG, key + ": updating permissions");
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005587
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005588 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null;
5589 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null;
5590
5591 // Shortcut when no Uris involved
5592 if (newUris == null && oldUris == null) {
5593 return;
5594 }
5595
5596 // Inherit any existing owner
5597 IBinder permissionOwner = null;
5598 if (newRecord != null && permissionOwner == null) {
5599 permissionOwner = newRecord.permissionOwner;
5600 }
5601 if (oldRecord != null && permissionOwner == null) {
5602 permissionOwner = oldRecord.permissionOwner;
5603 }
5604
5605 // If we have Uris to grant, but no owner yet, go create one
5606 if (newUris != null && permissionOwner == null) {
5607 try {
5608 if (DBG) Slog.d(TAG, key + ": creating owner");
5609 permissionOwner = mAm.newUriPermissionOwner("NOTIF:" + key);
5610 } catch (RemoteException ignored) {
5611 // Ignored because we're in same process
5612 }
5613 }
5614
5615 // If we have no Uris to grant, but an existing owner, go destroy it
5616 if (newUris == null && permissionOwner != null) {
5617 final long ident = Binder.clearCallingIdentity();
5618 try {
5619 if (DBG) Slog.d(TAG, key + ": destroying owner");
5620 mAm.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
5621 UserHandle.getUserId(oldRecord.getUid()));
5622 permissionOwner = null;
5623 } catch (RemoteException ignored) {
5624 // Ignored because we're in same process
5625 } finally {
5626 Binder.restoreCallingIdentity(ident);
5627 }
5628 }
5629
5630 // Grant access to new Uris
5631 if (newUris != null && permissionOwner != null) {
5632 for (int i = 0; i < newUris.size(); i++) {
5633 final Uri uri = newUris.valueAt(i);
5634 if (oldUris == null || !oldUris.contains(uri)) {
5635 if (DBG) Slog.d(TAG, key + ": granting " + uri);
5636 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
5637 targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005638 }
5639 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005640 }
5641
5642 // Revoke access to old Uris
5643 if (oldUris != null && permissionOwner != null) {
5644 for (int i = 0; i < oldUris.size(); i++) {
5645 final Uri uri = oldUris.valueAt(i);
5646 if (newUris == null || !newUris.contains(uri)) {
5647 if (DBG) Slog.d(TAG, key + ": revoking " + uri);
5648 revokeUriPermission(permissionOwner, uri, oldRecord.getUid());
5649 }
5650 }
5651 }
5652
5653 if (newRecord != null) {
5654 newRecord.permissionOwner = permissionOwner;
5655 }
5656 }
5657
5658 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg,
5659 int targetUserId) {
5660 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5661
5662 final long ident = Binder.clearCallingIdentity();
5663 try {
5664 mAm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
5665 ContentProvider.getUriWithoutUserId(uri),
5666 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5667 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
5668 targetUserId);
5669 } catch (RemoteException ignored) {
5670 // Ignored because we're in same process
5671 } finally {
5672 Binder.restoreCallingIdentity(ident);
5673 }
5674 }
5675
5676 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUid) {
5677 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5678
5679 final long ident = Binder.clearCallingIdentity();
5680 try {
5681 mAm.revokeUriPermissionFromOwner(owner,
5682 ContentProvider.getUriWithoutUserId(uri),
5683 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5684 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
5685 } catch (RemoteException ignored) {
5686 // Ignored because we're in same process
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005687 } finally {
5688 Binder.restoreCallingIdentity(ident);
5689 }
5690 }
5691
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005692 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07005693 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005694 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005695 */
John Spurlocke6a7d932014-03-13 12:29:00 -04005696 void cancelNotification(final int callingUid, final int callingPid,
5697 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005698 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04005699 final int userId, final int reason, final ManagedServiceInfo listener) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005700 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
5701 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
5702 }
5703
5704 /**
5705 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
5706 * and none of the {@code mustNotHaveFlags}.
5707 */
5708 void cancelNotification(final int callingUid, final int callingPid,
5709 final String pkg, final String tag, final int id,
5710 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
5711 final int userId, final int reason, int rank, int count, final ManagedServiceInfo listener) {
Beverly5a20a5e2018-03-06 15:02:44 -05005712
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005713 // In enqueueNotificationInternal notifications are added by scheduling the
5714 // work on the worker handler. Hence, we also schedule the cancel on this
5715 // handler to avoid a scenario where an add notification call followed by a
5716 // remove notification call ends up in not removing the notification.
5717 mHandler.post(new Runnable() {
5718 @Override
5719 public void run() {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005720 String listenerName = listener == null ? null : listener.component.toShortString();
Chris Wrenbddb5bc2015-03-04 08:47:46 -08005721 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
5722 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005723
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005724 synchronized (mNotificationLock) {
5725 // Look for the notification, searching both the posted and enqueued lists.
5726 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
5727 if (r != null) {
5728 // The notification was found, check if it should be removed.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005729
Christoph Studer546bec82014-03-14 12:17:12 +01005730 // Ideally we'd do this in the caller of this method. However, that would
5731 // require the caller to also find the notification.
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005732 if (reason == REASON_CLICK) {
Christoph Studer546bec82014-03-14 12:17:12 +01005733 mUsageStats.registerClickedByUser(r);
5734 }
5735
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005736 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
5737 return;
5738 }
5739 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
5740 return;
5741 }
5742
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005743 // Cancel the notification.
Julia Reynolds0839c022017-06-15 15:24:01 -04005744 boolean wasPosted = removeFromNotificationListsLocked(r);
Dieter Hsud39f0d52018-04-14 02:08:30 +08005745 cancelNotificationLocked(r, sendDelete, reason, rank, count, wasPosted, listenerName);
Christoph Studer265c1052014-07-23 17:14:33 +02005746 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005747 sendDelete, null);
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005748 updateLightsLocked();
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005749 } else {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005750 // No notification was found, assume that it is snoozed and cancel it.
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005751 if (reason != REASON_SNOOZED) {
5752 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
5753 if (wasSnoozed) {
5754 savePolicyFile();
5755 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005756 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005757 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005758 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005759 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005760 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005761 }
5762
5763 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07005764 * Determine whether the userId applies to the notification in question, either because
5765 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
5766 */
5767 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
5768 return
5769 // looking for USER_ALL notifications? match everything
5770 userId == UserHandle.USER_ALL
5771 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005772 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07005773 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005774 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07005775 }
5776
5777 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005778 * Determine whether the userId applies to the notification in question, either because
5779 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01005780 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005781 */
Kenny Guy2a764942014-04-02 13:29:20 +01005782 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00005783 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04005784 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005785 }
5786
5787 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05005788 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005789 * {@code mustHaveFlags}.
5790 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005791 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005792 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005793 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005794 mHandler.post(new Runnable() {
5795 @Override
5796 public void run() {
5797 String listenerName = listener == null ? null : listener.component.toShortString();
5798 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5799 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
5800 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005801
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005802 // Why does this parameter exist? Do we actually want to execute the above if doit
5803 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005804 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005805 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005806 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005807
5808 synchronized (mNotificationLock) {
5809 FlagChecker flagChecker = (int flags) -> {
5810 if ((flags & mustHaveFlags) != mustHaveFlags) {
5811 return false;
5812 }
5813 if ((flags & mustNotHaveFlags) != 0) {
5814 return false;
5815 }
5816 return true;
5817 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005818 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5819 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
5820 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005821 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005822 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5823 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
5824 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005825 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005826 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005827 }
5828 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005829 });
5830 }
5831
5832 private interface FlagChecker {
5833 // Returns false if these flags do not pass the defined flag test.
5834 public boolean apply(int flags);
5835 }
5836
Julia Reynolds88860ce2017-06-01 16:55:49 -04005837 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005838 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
5839 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
5840 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005841 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005842 ArrayList<NotificationRecord> canceledNotifications = null;
5843 for (int i = notificationList.size() - 1; i >= 0; --i) {
5844 NotificationRecord r = notificationList.get(i);
5845 if (includeCurrentProfiles) {
5846 if (!notificationMatchesCurrentProfiles(r, userId)) {
5847 continue;
5848 }
5849 } else if (!notificationMatchesUserId(r, userId)) {
5850 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005851 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005852 // Don't remove notifications to all, if there's no package name specified
5853 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
5854 continue;
5855 }
5856 if (!flagChecker.apply(r.getFlags())) {
5857 continue;
5858 }
5859 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
5860 continue;
5861 }
5862 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
5863 continue;
5864 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005865 if (canceledNotifications == null) {
5866 canceledNotifications = new ArrayList<>();
5867 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005868 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005869 mNotificationsByKey.remove(r.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005870 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04005871 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005872 }
5873 if (canceledNotifications != null) {
5874 final int M = canceledNotifications.size();
5875 for (int i = 0; i < M; i++) {
5876 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005877 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005878 }
5879 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005880 }
5881 }
5882
Julia Reynolds50989772017-02-23 14:32:16 -05005883 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005884 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05005885 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005886 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05005887 return;
5888 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05005889
Julia Reynolds79672302017-01-12 08:30:16 -05005890 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05005891 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
5892 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05005893 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005894 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005895 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005896 }
5897
5898 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
5899 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005900 if (DBG) {
5901 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
5902 }
Julia Reynolds79672302017-01-12 08:30:16 -05005903 mSnoozeHelper.repost(key);
5904 savePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005905 }
5906
Julia Reynolds88860ce2017-06-01 16:55:49 -04005907 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07005908 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005909 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005910 mHandler.post(new Runnable() {
5911 @Override
5912 public void run() {
5913 synchronized (mNotificationLock) {
5914 String listenerName =
5915 listener == null ? null : listener.component.toShortString();
5916 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5917 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01005918
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005919 FlagChecker flagChecker = (int flags) -> {
5920 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
5921 != 0) {
5922 return false;
5923 }
5924 return true;
5925 };
5926
5927 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5928 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
5929 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005930 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005931 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5932 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
5933 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04005934 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005935 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00005936 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005937 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005938 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005939 }
5940
Christoph Studere4ef156b2014-07-04 18:41:57 +02005941 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04005942 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02005943 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005944 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005945 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02005946 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005947 return;
5948 }
5949
5950 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02005951
5952 if (pkg == null) {
5953 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
5954 return;
5955 }
5956
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005957 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005958 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005959 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005960 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005961 }
5962
Julia Reynolds88860ce2017-06-01 16:55:49 -04005963 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005964 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
5965 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005966 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005967 final String pkg = parentNotification.sbn.getPackageName();
5968 final int userId = parentNotification.getUserId();
5969 final int reason = REASON_GROUP_SUMMARY_CANCELED;
5970 for (int i = notificationList.size() - 1; i >= 0; i--) {
5971 final NotificationRecord childR = notificationList.get(i);
5972 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04005973 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005974 childR.getGroupKey().equals(parentNotification.getGroupKey())
Julia Reynoldse5c60452018-04-30 14:41:36 -04005975 && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
Beverly40239d92017-07-07 10:20:41 -04005976 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02005977 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
5978 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04005979 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005980 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04005981 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005982 }
5983 }
5984 }
5985
Julia Reynolds88860ce2017-06-01 16:55:49 -04005986 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005987 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005988 {
The Android Open Source Project10592532009-03-18 17:39:46 -07005989 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05005990 NotificationRecord ledNotification = null;
5991 while (ledNotification == null && !mLights.isEmpty()) {
5992 final String owner = mLights.get(mLights.size() - 1);
5993 ledNotification = mNotificationsByKey.get(owner);
5994 if (ledNotification == null) {
5995 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
5996 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005997 }
5998 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005999
Mike Lockwood63b5ad92011-08-30 09:55:30 -04006000 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05006001 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05006002 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07006003 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006004 NotificationRecord.Light light = ledNotification.getLight();
6005 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05006006 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006007 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
6008 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05006009 }
The Android Open Source Project10592532009-03-18 17:39:46 -07006010 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006011 }
6012
Julia Reynolds88860ce2017-06-01 16:55:49 -04006013 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006014 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
6015 String groupKey, int userId) {
6016 List<NotificationRecord> records = new ArrayList<>();
6017 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
6018 records.addAll(
6019 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
6020 return records;
6021 }
6022
6023
Julia Reynolds88860ce2017-06-01 16:55:49 -04006024 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006025 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
6026 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
6027 List<NotificationRecord> records = new ArrayList<>();
6028 final int len = list.size();
6029 for (int i = 0; i < len; i++) {
6030 NotificationRecord r = list.get(i);
6031 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
6032 && r.sbn.getPackageName().equals(pkg)) {
6033 records.add(r);
6034 }
6035 }
6036 return records;
6037 }
6038
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006039 // Searches both enqueued and posted notifications by key.
6040 // TODO: need to combine a bunch of these getters with slightly different behavior.
6041 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04006042 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006043 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006044 NotificationRecord r;
6045 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
6046 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006047 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006048 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
6049 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006050 }
6051 return null;
6052 }
6053
Julia Reynolds88860ce2017-06-01 16:55:49 -04006054 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006055 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006056 NotificationRecord r;
6057 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
6058 return r;
6059 }
6060 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
6061 != null) {
6062 return r;
6063 }
6064 return null;
6065 }
6066
Julia Reynolds88860ce2017-06-01 16:55:49 -04006067 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006068 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006069 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006070 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006071 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006072 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01006073 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
6074 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006075 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006076 }
6077 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006078 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006079 }
6080
Julia Reynolds88860ce2017-06-01 16:55:49 -04006081 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006082 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04006083 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006084 final int N = list.size();
6085 for (int i = 0; i < N; i++) {
6086 if (key.equals(list.get(i).getKey())) {
6087 return list.get(i);
6088 }
6089 }
6090 return null;
6091 }
6092
Julia Reynolds88860ce2017-06-01 16:55:49 -04006093 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02006094 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02006095 final int N = mNotificationList.size();
6096 for (int i = 0; i < N; i++) {
6097 if (key.equals(mNotificationList.get(i).getKey())) {
6098 return i;
6099 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02006100 }
Christoph Studerc5115552014-06-12 20:22:31 +02006101 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02006102 }
6103
Beverly5a20a5e2018-03-06 15:02:44 -05006104 @VisibleForTesting
6105 protected void hideNotificationsForPackages(String[] pkgs) {
6106 synchronized (mNotificationLock) {
6107 List<String> pkgList = Arrays.asList(pkgs);
6108 List<NotificationRecord> changedNotifications = new ArrayList<>();
6109 int numNotifications = mNotificationList.size();
6110 for (int i = 0; i < numNotifications; i++) {
6111 NotificationRecord rec = mNotificationList.get(i);
6112 if (pkgList.contains(rec.sbn.getPackageName())) {
6113 rec.setHidden(true);
6114 changedNotifications.add(rec);
6115 }
6116 }
6117
6118 mListeners.notifyHiddenLocked(changedNotifications);
6119 }
6120 }
6121
6122 @VisibleForTesting
6123 protected void unhideNotificationsForPackages(String[] pkgs) {
6124 synchronized (mNotificationLock) {
6125 List<String> pkgList = Arrays.asList(pkgs);
6126 List<NotificationRecord> changedNotifications = new ArrayList<>();
6127 int numNotifications = mNotificationList.size();
6128 for (int i = 0; i < numNotifications; i++) {
6129 NotificationRecord rec = mNotificationList.get(i);
6130 if (pkgList.contains(rec.sbn.getPackageName())) {
6131 rec.setHidden(false);
6132 changedNotifications.add(rec);
6133 }
6134 }
6135
6136 mListeners.notifyUnhiddenLocked(changedNotifications);
6137 }
6138 }
6139
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006140 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006141 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006142 updateLightsLocked();
6143 }
6144 }
John Spurlocke677d712014-02-13 12:52:19 -05006145
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006146 protected boolean isCallingUidSystem() {
6147 final int uid = Binder.getCallingUid();
6148 return uid == Process.SYSTEM_UID;
6149 }
6150
6151 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04006152 final int appid = UserHandle.getAppId(uid);
6153 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
6154 }
John Spurlockb408e8e2014-04-23 21:12:45 -04006155
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006156 // TODO: Most calls should probably move to isCallerSystem.
6157 protected boolean isCallerSystemOrPhone() {
6158 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04006159 }
6160
Julia Reynoldsb852e562017-06-06 16:14:18 -04006161 private void checkCallerIsSystemOrShell() {
6162 if (Binder.getCallingUid() == Process.SHELL_UID) {
6163 return;
6164 }
6165 checkCallerIsSystem();
6166 }
6167
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006168 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006169 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006170 return;
6171 }
6172 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
6173 }
6174
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006175 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006176 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006177 return;
6178 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04006179 checkCallerIsSameApp(pkg);
6180 }
6181
Chad Brubaker6b68f102017-01-27 13:39:00 -08006182 private boolean isCallerInstantApp(String pkg) {
6183 // System is always allowed to act for ephemeral apps.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006184 if (isCallerSystemOrPhone()) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08006185 return false;
6186 }
6187
6188 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
6189
6190 try {
6191 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
6192 UserHandle.getCallingUserId());
6193 if (ai == null) {
6194 throw new SecurityException("Unknown package " + pkg);
6195 }
6196 return ai.isInstantApp();
6197 } catch (RemoteException re) {
6198 throw new SecurityException("Unknown package " + pkg, re);
6199 }
6200
6201 }
6202
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006203 private void checkCallerIsSameApp(String pkg) {
John Spurlock7340fc82014-04-24 18:50:12 -04006204 final int uid = Binder.getCallingUid();
6205 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006206 ApplicationInfo ai = mPackageManager.getApplicationInfo(
John Spurlock7340fc82014-04-24 18:50:12 -04006207 pkg, 0, UserHandle.getCallingUserId());
Dan Sandler09afc2e2014-07-18 14:29:20 -04006208 if (ai == null) {
6209 throw new SecurityException("Unknown package " + pkg);
6210 }
John Spurlock7340fc82014-04-24 18:50:12 -04006211 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006212 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04006213 + pkg + " which is owned by uid " + ai.uid);
6214 }
6215 } catch (RemoteException re) {
6216 throw new SecurityException("Unknown package " + pkg + "\n" + re);
6217 }
6218 }
6219
John Spurlock32fe4c62014-10-02 12:16:02 -04006220 private static String callStateToString(int state) {
6221 switch (state) {
6222 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
6223 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
6224 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
6225 default: return "CALL_STATE_UNKNOWN_" + state;
6226 }
6227 }
6228
6229 private void listenForCallState() {
6230 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
6231 @Override
6232 public void onCallStateChanged(int state, String incomingNumber) {
6233 if (mCallState == state) return;
6234 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
6235 mCallState = state;
6236 }
6237 }, PhoneStateListener.LISTEN_CALL_STATE);
6238 }
6239
Christoph Studer05ad4822014-05-16 14:16:03 +02006240 /**
6241 * Generates a NotificationRankingUpdate from 'sbns', considering only
6242 * notifications visible to the given listener.
6243 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006244 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04006245 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04006246 final int N = mNotificationList.size();
6247 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02006248 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05006249 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04006250 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006251 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006252 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05006253 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006254 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05006255 Bundle overridePeople = new Bundle();
6256 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006257 Bundle showBadge = new Bundle();
Julia Reynolds503ed942017-10-04 16:04:56 -04006258 Bundle userSentiment = new Bundle();
Beverly5a20a5e2018-03-06 15:02:44 -05006259 Bundle hidden = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04006260 for (int i = 0; i < N; i++) {
6261 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02006262 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006263 continue;
6264 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006265 final String key = record.sbn.getKey();
6266 keys.add(key);
6267 importance.add(record.getImportance());
6268 if (record.getImportanceExplanation() != null) {
6269 explanation.putCharSequence(key, record.getImportanceExplanation());
6270 }
Chris Wren333a61c2014-05-28 16:40:57 -04006271 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006272 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006273
Christoph Studer05ad4822014-05-16 14:16:03 +02006274 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006275 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006276 if (record.getPackageVisibilityOverride()
6277 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006278 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006279 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04006280 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05006281 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05006282 overridePeople.putStringArrayList(key, record.getPeopleOverride());
6283 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05006284 showBadge.putBoolean(key, record.canShowBadge());
Julia Reynolds503ed942017-10-04 16:04:56 -04006285 userSentiment.putInt(key, record.getUserSentiment());
Beverly5a20a5e2018-03-06 15:02:44 -05006286 hidden.putBoolean(key, record.isHidden());
Christoph Studer05ad4822014-05-16 14:16:03 +02006287 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006288 final int M = keys.size();
6289 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02006290 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05006291 int[] importanceAr = new int[M];
6292 for (int i = 0; i < M; i++) {
6293 importanceAr[i] = importance.get(i);
6294 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006295 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05006296 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Beverly5a20a5e2018-03-06 15:02:44 -05006297 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden);
Christoph Studer05ad4822014-05-16 14:16:03 +02006298 }
6299
Julia Reynoldsda781472017-04-12 09:41:16 -04006300 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006301 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04006302 mCompanionManager = getCompanionManager();
6303 }
6304 // Companion mgr doesn't exist on all device types
6305 if (mCompanionManager == null) {
6306 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006307 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006308 long identity = Binder.clearCallingIdentity();
6309 try {
6310 List<String> associations = mCompanionManager.getAssociations(
6311 info.component.getPackageName(), info.userid);
6312 if (!ArrayUtils.isEmpty(associations)) {
6313 return true;
6314 }
6315 } catch (SecurityException se) {
6316 // Not a privileged listener
6317 } catch (RemoteException re) {
6318 Slog.e(TAG, "Cannot reach companion device service", re);
6319 } catch (Exception e) {
6320 Slog.e(TAG, "Cannot verify listener " + info, e);
6321 } finally {
6322 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006323 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006324 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006325 }
6326
Julia Reynolds727a7282017-04-13 10:54:01 -04006327 protected ICompanionDeviceManager getCompanionManager() {
6328 return ICompanionDeviceManager.Stub.asInterface(
6329 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
6330 }
6331
Christoph Studercef37cf2014-07-25 14:18:17 +02006332 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
6333 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
6334 return false;
6335 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07006336 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02006337 return true;
6338 }
6339
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00006340 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Beverly2be7a052018-03-27 11:37:58 -04006341 final long identity = Binder.clearCallingIdentity();
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006342 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006343 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006344 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006345 } catch (RemoteException re) {
6346 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00006347 } catch (IllegalArgumentException ex) {
6348 // Package not found.
6349 return false;
Beverly2be7a052018-03-27 11:37:58 -04006350 } finally {
6351 Binder.restoreCallingIdentity(identity);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006352 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006353 }
6354
Kristian Monsen30f59b22018-04-09 10:27:16 +02006355 @VisibleForTesting
6356 boolean canUseManagedServices(String pkg) {
6357 boolean canUseManagedServices = !mActivityManager.isLowRamDevice()
Julia Reynoldse1816412017-10-24 10:39:11 -04006358 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
Kristian Monsen30f59b22018-04-09 10:27:16 +02006359
6360 for (String whitelisted : getContext().getResources().getStringArray(
6361 R.array.config_allowedManagedServicesOnLowRamDevices)) {
6362 if (whitelisted.equals(pkg)) {
6363 canUseManagedServices = true;
6364 }
6365 }
6366
6367 return canUseManagedServices;
Julia Reynoldse1816412017-10-24 10:39:11 -04006368 }
6369
Chris Wren47633422016-01-22 09:56:59 -05006370 private class TrimCache {
6371 StatusBarNotification heavy;
6372 StatusBarNotification sbnClone;
6373 StatusBarNotification sbnCloneLight;
6374
6375 TrimCache(StatusBarNotification sbn) {
6376 heavy = sbn;
6377 }
6378
6379 StatusBarNotification ForListener(ManagedServiceInfo info) {
6380 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
6381 if (sbnCloneLight == null) {
6382 sbnCloneLight = heavy.cloneLight();
6383 }
6384 return sbnCloneLight;
6385 } else {
6386 if (sbnClone == null) {
6387 sbnClone = heavy.clone();
6388 }
6389 return sbnClone;
6390 }
6391 }
6392 }
6393
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006394 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006395 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05006396
Julia Reynolds7380d872018-01-12 10:28:26 -05006397 public NotificationAssistants(Context context, Object lock, UserProfiles up,
6398 IPackageManager pm) {
6399 super(context, lock, up, pm);
Chris Wren51017d02015-12-15 15:34:46 -05006400 }
6401
6402 @Override
6403 protected Config getConfig() {
6404 Config c = new Config();
Julia Reynolds503ed942017-10-04 16:04:56 -04006405 c.caption = "notification assistant";
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006406 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006407 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006408 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
6409 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05006410 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006411 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05006412 return c;
6413 }
6414
6415 @Override
6416 protected IInterface asInterface(IBinder binder) {
6417 return INotificationListener.Stub.asInterface(binder);
6418 }
6419
6420 @Override
6421 protected boolean checkType(IInterface service) {
6422 return service instanceof INotificationListener;
6423 }
6424
6425 @Override
6426 protected void onServiceAdded(ManagedServiceInfo info) {
6427 mListeners.registerGuestService(info);
6428 }
6429
6430 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006431 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05006432 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
6433 mListeners.unregisterService(removed.service, removed.userid);
6434 }
Chris Wren47633422016-01-22 09:56:59 -05006435
Julia Reynoldsef934fd2018-02-01 14:39:17 -05006436 @Override
6437 public void onUserUnlocked(int user) {
6438 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
6439 rebindServices(true);
6440 }
6441
Chris Wren47633422016-01-22 09:56:59 -05006442 public void onNotificationEnqueued(final NotificationRecord r) {
6443 final StatusBarNotification sbn = r.sbn;
6444 TrimCache trimCache = new TrimCache(sbn);
6445
Chris Wren47633422016-01-22 09:56:59 -05006446 // There should be only one, but it's a list, so while we enforce
6447 // singularity elsewhere, we keep it general here, to avoid surprises.
Julia Reynolds00314d92017-04-14 10:01:24 -04006448 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
Chris Wren47633422016-01-22 09:56:59 -05006449 boolean sbnVisible = isVisibleToListener(sbn, info);
6450 if (!sbnVisible) {
6451 continue;
6452 }
6453
Chris Wren47633422016-01-22 09:56:59 -05006454 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006455 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05006456 @Override
6457 public void run() {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006458 notifyEnqueued(info, sbnToPost);
Chris Wren47633422016-01-22 09:56:59 -05006459 }
6460 });
6461 }
6462 }
6463
6464 private void notifyEnqueued(final ManagedServiceInfo info,
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006465 final StatusBarNotification sbn) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006466 final INotificationListener assistant = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05006467 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6468 try {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006469 assistant.onNotificationEnqueued(sbnHolder);
Chris Wren47633422016-01-22 09:56:59 -05006470 } catch (RemoteException ex) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006471 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Chris Wren47633422016-01-22 09:56:59 -05006472 }
6473 }
6474
Julia Reynolds79672302017-01-12 08:30:16 -05006475 /**
6476 * asynchronously notify the assistant that a notification has been snoozed until a
6477 * context
6478 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006479 @GuardedBy("mNotificationLock")
Julia Reynolds79672302017-01-12 08:30:16 -05006480 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
6481 final String snoozeCriterionId) {
6482 TrimCache trimCache = new TrimCache(sbn);
Julia Reynolds00314d92017-04-14 10:01:24 -04006483 for (final ManagedServiceInfo info : getServices()) {
Julia Reynolds503ed942017-10-04 16:04:56 -04006484 boolean sbnVisible = isVisibleToListener(sbn, info);
6485 if (!sbnVisible) {
6486 continue;
6487 }
Julia Reynolds79672302017-01-12 08:30:16 -05006488 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
6489 mHandler.post(new Runnable() {
6490 @Override
6491 public void run() {
6492 final INotificationListener assistant =
6493 (INotificationListener) info.service;
6494 StatusBarNotificationHolder sbnHolder
6495 = new StatusBarNotificationHolder(sbnToPost);
6496 try {
6497 assistant.onNotificationSnoozedUntilContext(
6498 sbnHolder, snoozeCriterionId);
6499 } catch (RemoteException ex) {
6500 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
6501 }
6502 }
6503 });
6504 }
6505 }
6506
Chris Wren47633422016-01-22 09:56:59 -05006507 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04006508 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05006509 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006510
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04006511 protected void ensureAssistant() {
6512 final List<UserInfo> activeUsers = mUm.getUsers(true);
6513 for (UserInfo userInfo : activeUsers) {
6514 int userId = userInfo.getUserHandle().getIdentifier();
6515 if (getAllowedPackages(userId).isEmpty()) {
6516 Slog.d(TAG, "Approving default notification assistant for user " + userId);
6517 readDefaultAssistant(userId);
6518 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006519 }
6520 }
Chris Wren51017d02015-12-15 15:34:46 -05006521 }
6522
John Spurlock7340fc82014-04-24 18:50:12 -04006523 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006524 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04006525
Christoph Studerb82bc782014-08-20 14:29:43 +02006526 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
6527
Julia Reynoldsb852e562017-06-06 16:14:18 -04006528 public NotificationListeners(IPackageManager pm) {
6529 super(getContext(), mNotificationLock, mUserProfiles, pm);
6530
John Spurlock7340fc82014-04-24 18:50:12 -04006531 }
6532
6533 @Override
Amith Yamasanie1fb58d2018-09-05 18:52:35 -07006534 protected int getBindFlags() {
6535 // Most of the same flags as the base, but also add BIND_ADJUST_BELOW_PERCEPTIBLE
6536 // because too many 3P apps could be kept in memory as notification listeners and
6537 // cause extreme memory pressure.
6538 // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation.
6539 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
6540 | BIND_ADJUST_BELOW_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
6541 }
6542
6543 @Override
John Spurlock7340fc82014-04-24 18:50:12 -04006544 protected Config getConfig() {
6545 Config c = new Config();
6546 c.caption = "notification listener";
6547 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006548 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04006549 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
6550 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
6551 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
6552 c.clientLabel = R.string.notification_listener_binding_label;
6553 return c;
6554 }
6555
6556 @Override
6557 protected IInterface asInterface(IBinder binder) {
6558 return INotificationListener.Stub.asInterface(binder);
6559 }
6560
6561 @Override
Chris Wren51017d02015-12-15 15:34:46 -05006562 protected boolean checkType(IInterface service) {
6563 return service instanceof INotificationListener;
6564 }
6565
6566 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04006567 public void onServiceAdded(ManagedServiceInfo info) {
6568 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04006569 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006570 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04006571 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006572 }
John Spurlock7340fc82014-04-24 18:50:12 -04006573 try {
Chris Wren333a61c2014-05-28 16:40:57 -04006574 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04006575 } catch (RemoteException e) {
6576 // we tried
6577 }
6578 }
6579
John Spurlock1fa865f2014-07-21 14:56:39 -04006580 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006581 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04006582 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07006583 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006584 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01006585 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04006586 }
Christoph Studerb82bc782014-08-20 14:29:43 +02006587 mLightTrimListeners.remove(removed);
6588 }
6589
Julia Reynolds88860ce2017-06-01 16:55:49 -04006590 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02006591 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
6592 if (trim == TRIM_LIGHT) {
6593 mLightTrimListeners.add(info);
6594 } else {
6595 mLightTrimListeners.remove(info);
6596 }
6597 }
6598
6599 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
6600 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04006601 }
6602
John Spurlock7340fc82014-04-24 18:50:12 -04006603 /**
6604 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02006605 *
6606 * <p>
6607 * Also takes care of removing a notification that has been visible to a listener before,
6608 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04006609 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006610 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006611 public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
6612 notifyPostedLocked(r, old, true);
Beverly5a20a5e2018-03-06 15:02:44 -05006613 }
6614
6615 /**
6616 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
6617 * targetting <= O_MR1
6618 */
6619 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006620 private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
Beverly5a20a5e2018-03-06 15:02:44 -05006621 boolean notifyAllListeners) {
Christoph Studerb82bc782014-08-20 14:29:43 +02006622 // Lazily initialized snapshots of the notification.
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006623 StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006624 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Chris Wren47633422016-01-22 09:56:59 -05006625 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02006626
Julia Reynolds00314d92017-04-14 10:01:24 -04006627 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02006628 boolean sbnVisible = isVisibleToListener(sbn, info);
6629 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
6630 // This notification hasn't been and still isn't visible -> ignore.
6631 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006632 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04006633 }
Beverly5a20a5e2018-03-06 15:02:44 -05006634 // If the notification is hidden, don't notifyPosted listeners targeting < P.
6635 // Instead, those listeners will receive notifyPosted when the notification is
6636 // unhidden.
6637 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
6638 continue;
6639 }
6640
6641 // If we shouldn't notify all listeners, this means the hidden state of
6642 // a notification was changed. Don't notifyPosted listeners targeting >= P.
6643 // Instead, those listeners will receive notifyRankingUpdate.
6644 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6645 continue;
6646 }
6647
Chris Wren333a61c2014-05-28 16:40:57 -04006648 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02006649
6650 // This notification became invisible -> remove the old one.
6651 if (oldSbnVisible && !sbnVisible) {
6652 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
6653 mHandler.post(new Runnable() {
6654 @Override
6655 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04006656 notifyRemoved(
6657 info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02006658 }
6659 });
Christoph Studer05ad4822014-05-16 14:16:03 +02006660 continue;
6661 }
Christoph Studercef37cf2014-07-25 14:18:17 +02006662
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006663 // Grant access before listener is notified
6664 final int targetUserId = (info.userid == UserHandle.USER_ALL)
6665 ? UserHandle.USER_SYSTEM : info.userid;
6666 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006667
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006668 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006669 mHandler.post(new Runnable() {
6670 @Override
6671 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02006672 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02006673 }
6674 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006675 }
6676 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006677
John Spurlock7340fc82014-04-24 18:50:12 -04006678 /**
6679 * asynchronously notify all listeners about a removed notification
6680 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006681 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05006682 public void notifyRemovedLocked(NotificationRecord r, int reason,
Julia Reynolds503ed942017-10-04 16:04:56 -04006683 NotificationStats notificationStats) {
Beverly5a20a5e2018-03-06 15:02:44 -05006684 final StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006685
John Spurlock7340fc82014-04-24 18:50:12 -04006686 // make a copy in case changes are made to the underlying Notification object
6687 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
6688 // notification
6689 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04006690 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02006691 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006692 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04006693 }
Beverly5a20a5e2018-03-06 15:02:44 -05006694
6695 // don't notifyRemoved for listeners targeting < P
6696 // if not for reason package suspended
6697 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
6698 && info.targetSdkVersion < Build.VERSION_CODES.P) {
6699 continue;
6700 }
6701
6702 // don't notifyRemoved for listeners targeting >= P
6703 // if the reason is package suspended
6704 if (reason == REASON_PACKAGE_SUSPENDED
6705 && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6706 continue;
6707 }
6708
Julia Reynolds503ed942017-10-04 16:04:56 -04006709 // Only assistants can get stats
6710 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
6711 ? notificationStats : null;
Chris Wren333a61c2014-05-28 16:40:57 -04006712 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006713 mHandler.post(new Runnable() {
6714 @Override
6715 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04006716 notifyRemoved(info, sbnLight, update, stats, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02006717 }
6718 });
Chris Wrenf9536642014-04-17 10:01:54 -04006719 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006720
6721 // Revoke access after all listeners have been updated
6722 mHandler.post(() -> {
6723 updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM);
6724 });
Chris Wrenf9536642014-04-17 10:01:54 -04006725 }
6726
6727 /**
Beverly5a20a5e2018-03-06 15:02:44 -05006728 * Asynchronously notify all listeners about a reordering of notifications
6729 * unless changedHiddenNotifications is populated.
6730 * If changedHiddenNotifications is populated, there was a change in the hidden state
6731 * of the notifications. In this case, we only send updates to listeners that
6732 * target >= P.
Chris Wrenf9536642014-04-17 10:01:54 -04006733 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006734 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05006735 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
6736 boolean isHiddenRankingUpdate = changedHiddenNotifications != null
6737 && changedHiddenNotifications.size() > 0;
6738
Julia Reynolds00314d92017-04-14 10:01:24 -04006739 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006740 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6741 continue;
6742 }
Beverly5a20a5e2018-03-06 15:02:44 -05006743
6744 boolean notifyThisListener = false;
6745 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
6746 Build.VERSION_CODES.P) {
6747 for (NotificationRecord rec : changedHiddenNotifications) {
6748 if (isVisibleToListener(rec.sbn, serviceInfo)) {
6749 notifyThisListener = true;
6750 break;
6751 }
John Spurlock7340fc82014-04-24 18:50:12 -04006752 }
Beverly5a20a5e2018-03-06 15:02:44 -05006753 }
6754
6755 if (notifyThisListener || !isHiddenRankingUpdate) {
6756 final NotificationRankingUpdate update = makeRankingUpdateLocked(
6757 serviceInfo);
6758
6759 mHandler.post(new Runnable() {
6760 @Override
6761 public void run() {
6762 notifyRankingUpdate(serviceInfo, update);
6763 }
6764 });
6765 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006766 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006767 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006768
Julia Reynolds88860ce2017-06-01 16:55:49 -04006769 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04006770 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006771 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04006772 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6773 continue;
6774 }
6775 mHandler.post(new Runnable() {
6776 @Override
6777 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006778 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006779 }
6780 });
6781 }
6782 }
6783
Beverly5a20a5e2018-03-06 15:02:44 -05006784 /**
6785 * asynchronously notify relevant listeners their notification is hidden
6786 * NotificationListenerServices that target P+:
6787 * NotificationListenerService#notifyRankingUpdateLocked()
6788 * NotificationListenerServices that target <= P:
6789 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
6790 */
6791 @GuardedBy("mNotificationLock")
6792 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
6793 if (changedNotifications == null || changedNotifications.size() == 0) {
6794 return;
6795 }
6796
6797 notifyRankingUpdateLocked(changedNotifications);
6798
6799 // for listeners that target < P, notifyRemoveLocked
6800 int numChangedNotifications = changedNotifications.size();
6801 for (int i = 0; i < numChangedNotifications; i++) {
6802 NotificationRecord rec = changedNotifications.get(i);
6803 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
6804 }
6805 }
6806
6807 /**
6808 * asynchronously notify relevant listeners their notification is unhidden
6809 * NotificationListenerServices that target P+:
6810 * NotificationListenerService#notifyRankingUpdateLocked()
6811 * NotificationListenerServices that target <= P:
6812 * NotificationListeners#notifyPostedLocked()
6813 */
6814 @GuardedBy("mNotificationLock")
6815 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
6816 if (changedNotifications == null || changedNotifications.size() == 0) {
6817 return;
6818 }
6819
6820 notifyRankingUpdateLocked(changedNotifications);
6821
6822 // for listeners that target < P, notifyPostedLocked
6823 int numChangedNotifications = changedNotifications.size();
6824 for (int i = 0; i < numChangedNotifications; i++) {
6825 NotificationRecord rec = changedNotifications.get(i);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006826 mListeners.notifyPostedLocked(rec, rec, false);
Beverly5a20a5e2018-03-06 15:02:44 -05006827 }
6828 }
6829
Christoph Studer85a384b2014-08-27 20:16:15 +02006830 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006831 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02006832 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6833 continue;
6834 }
6835 mHandler.post(new Runnable() {
6836 @Override
6837 public void run() {
6838 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
6839 }
6840 });
6841 }
6842 }
6843
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006844 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006845 final NotificationChannel channel, final int modificationType) {
6846 if (channel == null) {
6847 return;
6848 }
6849 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04006850 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006851 continue;
6852 }
Julia Reynolds018aa622017-04-20 11:31:30 -04006853
Eugene Suslaa25d17f2017-08-24 11:28:08 -07006854 BackgroundThread.getHandler().post(() -> {
6855 if (hasCompanionDevice(serviceInfo)) {
6856 notifyNotificationChannelChanged(
6857 serviceInfo, pkg, user, channel, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04006858 }
6859 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006860 }
6861 }
6862
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006863 protected void notifyNotificationChannelGroupChanged(
6864 final String pkg, final UserHandle user, final NotificationChannelGroup group,
6865 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006866 if (group == null) {
6867 return;
6868 }
6869 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04006870 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006871 continue;
6872 }
Julia Reynolds018aa622017-04-20 11:31:30 -04006873
Eugene Suslaa25d17f2017-08-24 11:28:08 -07006874 BackgroundThread.getHandler().post(() -> {
6875 if (hasCompanionDevice(serviceInfo)) {
6876 notifyNotificationChannelGroupChanged(
6877 serviceInfo, pkg, user, group, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04006878 }
6879 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006880 }
6881 }
6882
Christoph Studercef37cf2014-07-25 14:18:17 +02006883 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02006884 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04006885 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006886 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04006887 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07006888 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04006889 } catch (RemoteException ex) {
6890 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
6891 }
6892 }
6893
Christoph Studercef37cf2014-07-25 14:18:17 +02006894 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds503ed942017-10-04 16:04:56 -04006895 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04006896 if (!info.enabledAndUserMatches(sbn.getUserId())) {
6897 return;
6898 }
Christoph Studer05ad4822014-05-16 14:16:03 +02006899 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006900 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04006901 try {
Julia Reynolds503ed942017-10-04 16:04:56 -04006902 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04006903 } catch (RemoteException ex) {
6904 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04006905 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006906 }
Chris Wrenf9536642014-04-17 10:01:54 -04006907
Christoph Studer05ad4822014-05-16 14:16:03 +02006908 private void notifyRankingUpdate(ManagedServiceInfo info,
6909 NotificationRankingUpdate rankingUpdate) {
6910 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04006911 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02006912 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04006913 } catch (RemoteException ex) {
6914 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
6915 }
6916 }
John Spurlock1fa865f2014-07-21 14:56:39 -04006917
John Spurlockd8afe3c2014-08-01 14:04:07 -04006918 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04006919 final INotificationListener listener = (INotificationListener) info.service;
6920 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006921 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006922 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006923 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04006924 }
6925 }
Justin Koh38156c52014-06-04 13:57:49 -07006926
Christoph Studer85a384b2014-08-27 20:16:15 +02006927 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
6928 int interruptionFilter) {
6929 final INotificationListener listener = (INotificationListener) info.service;
6930 try {
6931 listener.onInterruptionFilterChanged(interruptionFilter);
6932 } catch (RemoteException ex) {
6933 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
6934 }
6935 }
6936
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006937 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006938 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006939 final int modificationType) {
6940 final INotificationListener listener = (INotificationListener) info.service;
6941 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006942 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006943 } catch (RemoteException ex) {
6944 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
6945 }
6946 }
6947
6948 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006949 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006950 final int modificationType) {
6951 final INotificationListener listener = (INotificationListener) info.service;
6952 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006953 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006954 } catch (RemoteException ex) {
6955 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
6956 }
6957 }
6958
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006959 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07006960 if (packageName == null) {
6961 return false;
6962 }
6963 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006964 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006965 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07006966 if (packageName.equals(serviceInfo.component.getPackageName())) {
6967 return true;
6968 }
6969 }
6970 }
6971 return false;
6972 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006973 }
John Spurlock25e2d242014-06-27 13:58:23 -04006974
6975 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04006976 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04006977 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04006978 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04006979 public long since;
6980 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04006981 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05006982 public boolean proto = false;
Vishnu Naire3e4d252018-03-01 11:26:57 -08006983 public boolean criticalPriority = false;
6984 public boolean normalPriority = false;
John Spurlock25e2d242014-06-27 13:58:23 -04006985
Kweku Adams887f09c2017-11-13 17:12:20 -08006986 @NonNull
John Spurlock25e2d242014-06-27 13:58:23 -04006987 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04006988 final DumpFilter filter = new DumpFilter();
6989 for (int ai = 0; ai < args.length; ai++) {
6990 final String a = args[ai];
Kweku Adams62b42242017-09-25 12:54:02 -07006991 if ("--proto".equals(a)) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05006992 filter.proto = true;
Kweku Adams62b42242017-09-25 12:54:02 -07006993 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
Dan Sandlera1770312015-07-10 13:59:29 -04006994 filter.redact = false;
6995 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
6996 if (ai < args.length-1) {
6997 ai++;
6998 filter.pkgFilter = args[ai].trim().toLowerCase();
6999 if (filter.pkgFilter.isEmpty()) {
7000 filter.pkgFilter = null;
7001 } else {
7002 filter.filtered = true;
7003 }
7004 }
7005 } else if ("--zen".equals(a) || "zen".equals(a)) {
7006 filter.filtered = true;
7007 filter.zen = true;
7008 } else if ("--stats".equals(a)) {
7009 filter.stats = true;
7010 if (ai < args.length-1) {
7011 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01007012 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04007013 } else {
7014 filter.since = 0;
7015 }
Vishnu Naire3e4d252018-03-01 11:26:57 -08007016 } else if (PRIORITY_ARG.equals(a)) {
7017 // Bugreport will call the service twice with priority arguments, first to dump
7018 // critical sections and then non critical ones. Set approriate filters
7019 // to generate the desired data.
7020 if (ai < args.length - 1) {
7021 ai++;
7022 switch (args[ai]) {
7023 case PRIORITY_ARG_CRITICAL:
7024 filter.criticalPriority = true;
7025 break;
7026 case PRIORITY_ARG_NORMAL:
7027 filter.normalPriority = true;
7028 break;
7029 }
7030 }
Dan Sandlera1770312015-07-10 13:59:29 -04007031 }
John Spurlock25e2d242014-06-27 13:58:23 -04007032 }
Dan Sandlera1770312015-07-10 13:59:29 -04007033 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04007034 }
7035
7036 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04007037 if (!filtered) return true;
7038 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04007039 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04007040 }
7041
7042 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04007043 if (!filtered) return true;
7044 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04007045 }
7046
7047 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04007048 if (!filtered) return true;
7049 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04007050 }
7051
7052 @Override
7053 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04007054 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04007055 }
7056 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07007057
Beverly5a20a5e2018-03-06 15:02:44 -05007058 @VisibleForTesting
7059 protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
7060 // only use for testing: mimic receive broadcast that package is (un)suspended
7061 // but does not actually (un)suspend the package
7062 final Bundle extras = new Bundle();
7063 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
7064 new String[]{pkg});
7065
7066 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
Beverlyc7858552018-09-14 09:49:07 -04007067 : Intent.ACTION_PACKAGES_UNSUSPENDED;
Beverly5a20a5e2018-03-06 15:02:44 -05007068 final Intent intent = new Intent(action);
7069 intent.putExtras(extras);
7070
7071 mPackageIntentReceiver.onReceive(getContext(), intent);
7072 }
7073
Griff Hazen84a00ea2014-09-02 17:10:47 -07007074 /**
7075 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
7076 * binder without sending large amounts of data over a oneway transaction.
7077 */
7078 private static final class StatusBarNotificationHolder
7079 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07007080 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007081
7082 public StatusBarNotificationHolder(StatusBarNotification value) {
7083 mValue = value;
7084 }
7085
Griff Hazene9aac5f2014-09-05 20:04:09 -07007086 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07007087 @Override
7088 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07007089 StatusBarNotification value = mValue;
7090 mValue = null;
7091 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007092 }
7093 }
John Spurlock7c74f782015-06-04 13:01:42 -04007094
Julia Reynoldsb852e562017-06-06 16:14:18 -04007095 private class ShellCmd extends ShellCommand {
7096 public static final String USAGE = "help\n"
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007097 + "allow_listener COMPONENT [user_id]\n"
7098 + "disallow_listener COMPONENT [user_id]\n"
Julia Reynolds7380d872018-01-12 10:28:26 -05007099 + "allow_assistant COMPONENT\n"
Julia Reynoldseb3dca72017-07-11 10:39:58 -04007100 + "remove_assistant COMPONENT\n"
Julia Reynoldsb852e562017-06-06 16:14:18 -04007101 + "allow_dnd PACKAGE\n"
Beverly5a20a5e2018-03-06 15:02:44 -05007102 + "disallow_dnd PACKAGE\n"
7103 + "suspend_package PACKAGE\n"
7104 + "unsuspend_package PACKAGE";
John Spurlock7c74f782015-06-04 13:01:42 -04007105
Julia Reynoldsb852e562017-06-06 16:14:18 -04007106 @Override
7107 public int onCommand(String cmd) {
Felipe Leme68d80412017-07-14 11:18:08 -07007108 if (cmd == null) {
7109 return handleDefaultCommands(cmd);
7110 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007111 final PrintWriter pw = getOutPrintWriter();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04007112 try {
Julia Reynoldsb852e562017-06-06 16:14:18 -04007113 switch (cmd) {
7114 case "allow_dnd": {
7115 getBinderService().setNotificationPolicyAccessGranted(
7116 getNextArgRequired(), true);
John Spurlock7c74f782015-06-04 13:01:42 -04007117 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04007118 break;
7119
7120 case "disallow_dnd": {
7121 getBinderService().setNotificationPolicyAccessGranted(
7122 getNextArgRequired(), false);
7123 }
7124 break;
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007125 case "allow_listener": {
7126 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7127 if (cn == null) {
7128 pw.println("Invalid listener - must be a ComponentName");
7129 return -1;
7130 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007131 String userId = getNextArg();
7132 if (userId == null) {
7133 getBinderService().setNotificationListenerAccessGranted(cn, true);
7134 } else {
7135 getBinderService().setNotificationListenerAccessGrantedForUser(
7136 cn, Integer.parseInt(userId), true);
7137 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007138 }
7139 break;
7140 case "disallow_listener": {
7141 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7142 if (cn == null) {
7143 pw.println("Invalid listener - must be a ComponentName");
7144 return -1;
7145 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007146 String userId = getNextArg();
7147 if (userId == null) {
7148 getBinderService().setNotificationListenerAccessGranted(cn, false);
7149 } else {
7150 getBinderService().setNotificationListenerAccessGrantedForUser(
7151 cn, Integer.parseInt(userId), false);
7152 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007153 }
7154 break;
Julia Reynoldseb3dca72017-07-11 10:39:58 -04007155 case "allow_assistant": {
7156 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7157 if (cn == null) {
7158 pw.println("Invalid assistant - must be a ComponentName");
7159 return -1;
7160 }
7161 getBinderService().setNotificationAssistantAccessGranted(cn, true);
7162 }
7163 break;
7164 case "disallow_assistant": {
7165 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7166 if (cn == null) {
7167 pw.println("Invalid assistant - must be a ComponentName");
7168 return -1;
7169 }
7170 getBinderService().setNotificationAssistantAccessGranted(cn, false);
7171 }
7172 break;
Beverly5a20a5e2018-03-06 15:02:44 -05007173 case "suspend_package": {
7174 // only use for testing
7175 simulatePackageSuspendBroadcast(true, getNextArgRequired());
7176 }
7177 break;
7178 case "unsuspend_package": {
7179 // only use for testing
7180 simulatePackageSuspendBroadcast(false, getNextArgRequired());
7181 }
7182 break;
Julia Reynoldsb852e562017-06-06 16:14:18 -04007183 default:
7184 return handleDefaultCommands(cmd);
John Spurlock7c74f782015-06-04 13:01:42 -04007185 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007186 } catch (Exception e) {
7187 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
Julia Reynoldsb852e562017-06-06 16:14:18 -04007188 Slog.e(TAG, "Error running shell command", e);
John Spurlock7c74f782015-06-04 13:01:42 -04007189 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04007190 return 0;
John Spurlock7c74f782015-06-04 13:01:42 -04007191 }
7192
Julia Reynoldsb852e562017-06-06 16:14:18 -04007193 @Override
7194 public void onHelp() {
7195 getOutPrintWriter().println(USAGE);
John Spurlock7c74f782015-06-04 13:01:42 -04007196 }
7197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007198}