blob: bca3f5d7c59f311a4508a8f11b64099e98c8245b [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 Reynolds3eb3ffd2017-11-16 10:11:32 -05002305 return mRankingHelper.getNotificationChannelGroups(
2306 pkg, Binder.getCallingUid(), false, false);
Julia Reynolds9bfba592017-03-15 14:03:55 -04002307 }
2308
2309 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002310 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04002311 checkCallerIsSystemOrSameApp(pkg);
2312
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002313 final int callingUid = Binder.getCallingUid();
2314 NotificationChannelGroup groupToDelete =
2315 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
2316 if (groupToDelete != null) {
2317 List<NotificationChannel> deletedChannels =
2318 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
2319 for (int i = 0; i < deletedChannels.size(); i++) {
2320 final NotificationChannel deletedChannel = deletedChannels.get(i);
2321 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2322 true,
2323 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2324 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002325 mListeners.notifyNotificationChannelChanged(pkg,
2326 UserHandle.getUserHandleForUid(callingUid),
2327 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002328 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2329 }
2330 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002331 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2332 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002333 savePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002334 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04002335 }
2336
2337 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002338 public void updateNotificationChannelForPackage(String pkg, int uid,
2339 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002340 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05002341 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002342 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002343 }
2344
2345 @Override
2346 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002347 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002348 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002349 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002350 }
2351
2352 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002353 public int getNumNotificationChannelsForPackage(String pkg, int uid,
2354 boolean includeDeleted) {
2355 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
2356 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
2357 .getList().size();
2358 }
2359
2360 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04002361 public boolean onlyHasDefaultChannel(String pkg, int uid) {
2362 enforceSystemOrSystemUI("onlyHasDefaultChannel");
2363 return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
2364 }
2365
2366 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04002367 public int getDeletedChannelCount(String pkg, int uid) {
2368 enforceSystemOrSystemUI("getDeletedChannelCount");
2369 return mRankingHelper.getDeletedChannelCount(pkg, uid);
2370 }
2371
2372 @Override
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002373 public int getBlockedChannelCount(String pkg, int uid) {
2374 enforceSystemOrSystemUI("getBlockedChannelCount");
2375 return mRankingHelper.getBlockedChannelCount(pkg, uid);
2376 }
2377
2378 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002379 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2380 String pkg, int uid, boolean includeDeleted) {
2381 checkCallerIsSystem();
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002382 return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted, true);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002383 }
2384
2385 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002386 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2387 String pkg, int uid, String groupId, boolean includeDeleted) {
2388 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
2389 return mRankingHelper.getNotificationChannelGroupWithChannels(
2390 pkg, uid, groupId, includeDeleted);
2391 }
2392
2393 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002394 public NotificationChannelGroup getNotificationChannelGroupForPackage(
2395 String groupId, String pkg, int uid) {
2396 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
2397 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
2398 }
2399
2400 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002401 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
2402 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002403 return mRankingHelper.getNotificationChannels(
2404 pkg, Binder.getCallingUid(), false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002405 }
2406
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002407 @Override
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05002408 public ParceledListSlice<NotifyingApp> getRecentNotifyingAppsForUser(int userId) {
2409 checkCallerIsSystem();
2410 synchronized (mNotificationLock) {
2411 List<NotifyingApp> apps = new ArrayList<>(
2412 mRecentApps.getOrDefault(userId, new ArrayList<>()));
2413 return new ParceledListSlice<>(apps);
2414 }
2415 }
2416
2417 @Override
Julia Reynoldse273f082018-04-12 13:48:49 -04002418 public int getBlockedAppCount(int userId) {
2419 checkCallerIsSystem();
2420 return mRankingHelper.getBlockedAppCount(userId);
2421 }
2422
2423 @Override
Beverly86d076f2018-04-17 14:44:52 -04002424 public boolean areChannelsBypassingDnd() {
2425 return mRankingHelper.areChannelsBypassingDnd();
2426 }
2427
2428 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05002429 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002430 checkCallerIsSystem();
2431
2432 // Cancel posted notifications
2433 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2434 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2435
Julia Reynoldsb852e562017-06-06 16:14:18 -04002436 final String[] packages = new String[] {packageName};
2437 final int[] uids = new int[] {uid};
2438
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002439 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04002440 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002441 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002442
2443 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04002444 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002445
2446 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05002447 if (!fromApp) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002448 mRankingHelper.onPackagesChanged(
2449 true, UserHandle.getCallingUserId(), packages, uids);
Julia Reynolds5355e852017-02-07 14:54:13 -05002450 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002451
2452 savePolicyFile();
2453 }
2454
2455
Adam Lesinski182f73f2013-12-05 16:48:06 -08002456 /**
2457 * System-only API for getting a list of current (i.e. not cleared) notifications.
2458 *
2459 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04002460 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002461 */
2462 @Override
2463 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2464 // enforce() will ensure the calling uid has the correct permission
2465 getContext().enforceCallingOrSelfPermission(
2466 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2467 "NotificationManagerService.getActiveNotifications");
2468
2469 StatusBarNotification[] tmp = null;
2470 int uid = Binder.getCallingUid();
2471
2472 // noteOp will check to make sure the callingPkg matches the uid
2473 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2474 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002475 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002476 tmp = new StatusBarNotification[mNotificationList.size()];
2477 final int N = mNotificationList.size();
2478 for (int i=0; i<N; i++) {
2479 tmp[i] = mNotificationList.get(i).sbn;
2480 }
2481 }
2482 }
2483 return tmp;
2484 }
2485
2486 /**
Dan Sandler994349c2015-04-15 11:02:54 -04002487 * Public API for getting a list of current notifications for the calling package/uid.
2488 *
Julia Reynolds573c6532017-01-24 17:44:38 -05002489 * Note that since notification posting is done asynchronously, this will not return
2490 * notifications that are in the process of being posted.
2491 *
Dan Sandler994349c2015-04-15 11:02:54 -04002492 * @returns A list of all the package's notifications, in natural order.
2493 */
2494 @Override
2495 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2496 int incomingUserId) {
2497 checkCallerIsSystemOrSameApp(pkg);
2498 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2499 Binder.getCallingUid(), incomingUserId, true, false,
2500 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002501 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002502 final ArrayMap<String, StatusBarNotification> map
2503 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002504 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002505 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002506 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2507 mNotificationList.get(i).sbn);
2508 if (sbn != null) {
2509 map.put(sbn.getKey(), sbn);
2510 }
2511 }
2512 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2513 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2514 if (sbn != null) {
2515 map.put(sbn.getKey(), sbn);
2516 }
2517 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002518 final int M = mEnqueuedNotifications.size();
2519 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002520 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2521 mEnqueuedNotifications.get(i).sbn);
2522 if (sbn != null) {
2523 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04002524 }
2525 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002526 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2527 list.addAll(map.values());
2528 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04002529 }
Dan Sandler994349c2015-04-15 11:02:54 -04002530 }
2531
Chris Wren6676dab2016-12-21 18:26:27 -05002532 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2533 StatusBarNotification sbn) {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04002534 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
Chris Wren6676dab2016-12-21 18:26:27 -05002535 // We could pass back a cloneLight() but clients might get confused and
2536 // try to send this thing back to notify() again, which would not work
2537 // very well.
2538 return new StatusBarNotification(
2539 sbn.getPackageName(),
2540 sbn.getOpPkg(),
Chris Wren6676dab2016-12-21 18:26:27 -05002541 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2542 sbn.getNotification().clone(),
2543 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2544 }
2545 return null;
2546 }
2547
Dan Sandler994349c2015-04-15 11:02:54 -04002548 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002549 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2550 *
2551 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2552 */
2553 @Override
2554 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2555 // enforce() will ensure the calling uid has the correct permission
2556 getContext().enforceCallingOrSelfPermission(
2557 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2558 "NotificationManagerService.getHistoricalNotifications");
2559
2560 StatusBarNotification[] tmp = null;
2561 int uid = Binder.getCallingUid();
2562
2563 // noteOp will check to make sure the callingPkg matches the uid
2564 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2565 == AppOpsManager.MODE_ALLOWED) {
2566 synchronized (mArchive) {
2567 tmp = mArchive.getArray(count);
2568 }
2569 }
2570 return tmp;
2571 }
2572
2573 /**
2574 * Register a listener binder directly with the notification manager.
2575 *
2576 * Only works with system callers. Apps should extend
2577 * {@link android.service.notification.NotificationListenerService}.
2578 */
2579 @Override
2580 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05002581 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02002582 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05002583 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002584 }
2585
2586 /**
2587 * Remove a listener binder directly
2588 */
2589 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002590 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05002591 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002592 }
2593
2594 /**
2595 * Allow an INotificationListener to simulate a "clear all" operation.
2596 *
2597 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2598 *
2599 * @param token The binder for the listener, to check that the caller is allowed
2600 */
2601 @Override
John Spurlocka4294292014-03-24 18:02:32 -04002602 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002603 final int callingUid = Binder.getCallingUid();
2604 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002605 long identity = Binder.clearCallingIdentity();
2606 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002607 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002608 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Beverly5a20a5e2018-03-06 15:02:44 -05002609
John Spurlocka4294292014-03-24 18:02:32 -04002610 if (keys != null) {
2611 final int N = keys.length;
2612 for (int i = 0; i < N; i++) {
2613 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07002614 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00002615 final int userId = r.sbn.getUserId();
2616 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04002617 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00002618 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04002619 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00002620 }
Griff Hazen335e1f02014-09-11 14:49:31 -07002621 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2622 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2623 userId);
John Spurlocka4294292014-03-24 18:02:32 -04002624 }
2625 } else {
2626 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00002627 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04002628 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002629 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002630 } finally {
2631 Binder.restoreCallingIdentity(identity);
2632 }
2633 }
2634
Chris Wrenab41eec2016-01-04 18:01:27 -05002635 /**
2636 * Handle request from an approved listener to re-enable itself.
2637 *
2638 * @param component The componenet to be re-enabled, caller must match package.
2639 */
2640 @Override
2641 public void requestBindListener(ComponentName component) {
2642 checkCallerIsSystemOrSameApp(component.getPackageName());
2643 long identity = Binder.clearCallingIdentity();
2644 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002645 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002646 mAssistants.isComponentEnabledForCurrentProfiles(component)
2647 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05002648 : mListeners;
2649 manager.setComponentState(component, true);
2650 } finally {
2651 Binder.restoreCallingIdentity(identity);
2652 }
2653 }
2654
2655 @Override
2656 public void requestUnbindListener(INotificationListener token) {
2657 long identity = Binder.clearCallingIdentity();
2658 try {
2659 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002660 synchronized (mNotificationLock) {
2661 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2662 info.getOwner().setComponentState(info.component, false);
2663 }
Chris Wrenab41eec2016-01-04 18:01:27 -05002664 } finally {
2665 Binder.restoreCallingIdentity(identity);
2666 }
2667 }
2668
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002669 @Override
2670 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002671 long identity = Binder.clearCallingIdentity();
2672 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002673 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002674 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2675 if (keys != null) {
2676 final int N = keys.length;
2677 for (int i = 0; i < N; i++) {
2678 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2679 if (r == null) continue;
2680 final int userId = r.sbn.getUserId();
2681 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2682 !mUserProfiles.isCurrentProfile(userId)) {
2683 throw new SecurityException("Disallowed call from listener: "
2684 + info.service);
2685 }
2686 if (!r.isSeen()) {
2687 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
Amith Yamasani803eab692017-11-09 17:47:04 -08002688 reportSeen(r);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002689 r.setSeen();
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04002690 maybeRecordInterruptionLocked(r);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002691 }
2692 }
2693 }
2694 }
2695 } finally {
2696 Binder.restoreCallingIdentity(identity);
2697 }
2698 }
2699
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002700 /**
2701 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2702 *
2703 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2704 *
Julia Reynolds79672302017-01-12 08:30:16 -05002705 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002706 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04002707 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04002708 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00002709 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04002710 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -04002711 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
John Spurlocka4294292014-03-24 18:02:32 -04002712 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00002713 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04002714 }
2715
Adam Lesinski182f73f2013-12-05 16:48:06 -08002716 /**
Julia Reynolds79672302017-01-12 08:30:16 -05002717 * Allow an INotificationListener to snooze a single notification until a context.
2718 *
2719 * @param token The binder for the listener, to check that the caller is allowed
2720 */
2721 @Override
2722 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2723 String key, String snoozeCriterionId) {
2724 long identity = Binder.clearCallingIdentity();
2725 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002726 synchronized (mNotificationLock) {
2727 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2728 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2729 }
Julia Reynolds79672302017-01-12 08:30:16 -05002730 } finally {
2731 Binder.restoreCallingIdentity(identity);
2732 }
2733 }
2734
2735 /**
2736 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002737 *
2738 * @param token The binder for the listener, to check that the caller is allowed
2739 */
2740 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002741 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05002742 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002743 long identity = Binder.clearCallingIdentity();
2744 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002745 synchronized (mNotificationLock) {
2746 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2747 snoozeNotificationInt(key, duration, null, info);
2748 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002749 } finally {
2750 Binder.restoreCallingIdentity(identity);
2751 }
2752 }
2753
2754 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002755 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002756 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002757 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002758 */
2759 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002760 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002761 long identity = Binder.clearCallingIdentity();
2762 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002763 synchronized (mNotificationLock) {
2764 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002765 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002766 unsnoozeNotificationInt(key, info);
2767 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002768 } finally {
2769 Binder.restoreCallingIdentity(identity);
2770 }
2771 }
2772
2773 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002774 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2775 *
2776 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2777 *
2778 * @param token The binder for the listener, to check that the caller is allowed
2779 */
2780 @Override
2781 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2782 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002783 final int callingUid = Binder.getCallingUid();
2784 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002785 long identity = Binder.clearCallingIdentity();
2786 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002787 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002788 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00002789 if (info.supportsProfiles()) {
2790 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2791 + "from " + info.component
2792 + " use cancelNotification(key) instead.");
2793 } else {
2794 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2795 pkg, tag, id, info.userid);
2796 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002797 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002798 } finally {
2799 Binder.restoreCallingIdentity(identity);
2800 }
2801 }
2802
2803 /**
2804 * Allow an INotificationListener to request the list of outstanding notifications seen by
2805 * the current user. Useful when starting up, after which point the listener callbacks
2806 * should be used.
2807 *
2808 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002809 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04002810 * @returns The return value will contain the notifications specified in keys, in that
2811 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002812 */
2813 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02002814 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02002815 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002816 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002817 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002818 final boolean getKeys = keys != null;
2819 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02002820 final ArrayList<StatusBarNotification> list
2821 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02002822 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002823 final NotificationRecord r = getKeys
2824 ? mNotificationsByKey.get(keys[i])
2825 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02002826 if (r == null) continue;
2827 StatusBarNotification sbn = r.sbn;
2828 if (!isVisibleToListener(sbn, info)) continue;
2829 StatusBarNotification sbnToSend =
2830 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2831 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002832 }
Christoph Studercee44ba2014-05-20 18:36:43 +02002833 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002834 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002835 }
2836
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002837 /**
2838 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2839 * seen by the current user. Useful when starting up, after which point the listener
2840 * callbacks should be used.
2841 *
2842 * @param token The binder for the listener, to check that the caller is allowed
2843 * @returns The return value will contain the notifications specified in keys, in that
2844 * order, or if keys is null, all the notifications, in natural order.
2845 */
2846 @Override
2847 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2848 INotificationListener token, int trim) {
2849 synchronized (mNotificationLock) {
2850 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2851 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2852 final int N = snoozedRecords.size();
2853 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2854 for (int i=0; i < N; i++) {
2855 final NotificationRecord r = snoozedRecords.get(i);
2856 if (r == null) continue;
2857 StatusBarNotification sbn = r.sbn;
2858 if (!isVisibleToListener(sbn, info)) continue;
2859 StatusBarNotification sbnToSend =
2860 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2861 list.add(sbnToSend);
2862 }
2863 return new ParceledListSlice<>(list);
2864 }
2865 }
2866
Adam Lesinski182f73f2013-12-05 16:48:06 -08002867 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002868 public void requestHintsFromListener(INotificationListener token, int hints) {
2869 final long identity = Binder.clearCallingIdentity();
2870 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002871 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002872 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07002873 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2874 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2875 | HINT_HOST_DISABLE_CALL_EFFECTS;
2876 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04002877 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07002878 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002879 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07002880 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002881 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002882 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04002883 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04002884 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002885 } finally {
2886 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04002887 }
2888 }
2889
2890 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002891 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002892 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002893 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04002894 }
2895 }
2896
2897 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02002898 public void requestInterruptionFilterFromListener(INotificationListener token,
2899 int interruptionFilter) throws RemoteException {
2900 final long identity = Binder.clearCallingIdentity();
2901 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002902 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002903 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2904 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02002905 updateInterruptionFilterLocked();
2906 }
2907 } finally {
2908 Binder.restoreCallingIdentity(identity);
2909 }
2910 }
2911
2912 @Override
2913 public int getInterruptionFilterFromListener(INotificationListener token)
2914 throws RemoteException {
2915 synchronized (mNotificationLight) {
2916 return mInterruptionFilter;
2917 }
2918 }
2919
2920 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02002921 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2922 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002923 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02002924 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2925 if (info == null) return;
2926 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2927 }
2928 }
2929
2930 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002931 public int getZenMode() {
2932 return mZenModeHelper.getZenMode();
2933 }
2934
2935 @Override
John Spurlock056c5192014-04-20 21:52:01 -04002936 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002937 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04002938 return mZenModeHelper.getConfig();
2939 }
2940
2941 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002942 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002943 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05002944 final long identity = Binder.clearCallingIdentity();
2945 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002946 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05002947 } finally {
2948 Binder.restoreCallingIdentity(identity);
2949 }
2950 }
2951
2952 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002953 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002954 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05002955 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002956 }
2957
2958 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002959 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2960 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002961 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002962 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002963 }
2964
2965 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002966 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002967 throws RemoteException {
2968 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2969 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2970 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2971 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002972 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002973
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002974 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2975 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002976 }
2977
2978 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002979 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002980 throws RemoteException {
2981 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2982 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2983 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2984 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2985 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002986
Julia Reynolds361e82d32016-02-26 18:19:49 -05002987 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002988 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002989 }
2990
2991 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002992 public boolean removeAutomaticZenRule(String id) throws RemoteException {
2993 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002994 // Verify that they can modify zen rules.
2995 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2996
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002997 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002998 }
2999
3000 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05003001 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
3002 Preconditions.checkNotNull(packageName, "Package name is null");
3003 enforceSystemOrSystemUI("removeAutomaticZenRules");
3004
3005 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
3006 }
3007
3008 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05003009 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
3010 Preconditions.checkNotNull(owner, "Owner is null");
3011 enforceSystemOrSystemUI("getRuleInstanceCount");
3012
3013 return mZenModeHelper.getCurrentInstanceCount(owner);
3014 }
3015
3016 @Override
John Spurlock80774932015-05-07 17:38:50 -04003017 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
3018 enforcePolicyAccess(pkg, "setInterruptionFilter");
3019 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
3020 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
3021 final long identity = Binder.clearCallingIdentity();
3022 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04003023 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04003024 } finally {
3025 Binder.restoreCallingIdentity(identity);
3026 }
3027 }
3028
3029 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04003030 public void notifyConditions(final String pkg, IConditionProvider provider,
3031 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04003032 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3033 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04003034 mHandler.post(new Runnable() {
3035 @Override
3036 public void run() {
3037 mConditionProviders.notifyConditions(pkg, info, conditions);
3038 }
3039 });
John Spurlocke77bb362014-04-26 10:24:59 -04003040 }
3041
Julia Reynolds38e6ca42016-08-08 08:38:09 -04003042 @Override
3043 public void requestUnbindProvider(IConditionProvider provider) {
3044 long identity = Binder.clearCallingIdentity();
3045 try {
3046 // allow bound services to disable themselves
3047 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3048 info.getOwner().setComponentState(info.component, false);
3049 } finally {
3050 Binder.restoreCallingIdentity(identity);
3051 }
3052 }
3053
3054 @Override
3055 public void requestBindProvider(ComponentName component) {
3056 checkCallerIsSystemOrSameApp(component.getPackageName());
3057 long identity = Binder.clearCallingIdentity();
3058 try {
3059 mConditionProviders.setComponentState(component, true);
3060 } finally {
3061 Binder.restoreCallingIdentity(identity);
3062 }
3063 }
3064
John Spurlocke77bb362014-04-26 10:24:59 -04003065 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003066 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04003067 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
3068 message);
John Spurlock7340fc82014-04-24 18:50:12 -04003069 }
3070
Julia Reynolds48034f82016-03-09 10:15:16 -05003071 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
3072 try {
3073 checkCallerIsSystemOrSameApp(pkg);
3074 } catch (SecurityException e) {
3075 getContext().enforceCallingPermission(
3076 android.Manifest.permission.STATUS_BAR_SERVICE,
3077 message);
3078 }
3079 }
3080
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003081 private void enforcePolicyAccess(int uid, String method) {
3082 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3083 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3084 return;
3085 }
3086 boolean accessAllowed = false;
3087 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
3088 final int packageCount = packages.length;
3089 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003090 if (mConditionProviders.isPackageOrComponentAllowed(
3091 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003092 accessAllowed = true;
3093 }
3094 }
3095 if (!accessAllowed) {
3096 Slog.w(TAG, "Notification policy access denied calling " + method);
3097 throw new SecurityException("Notification policy access denied");
3098 }
3099 }
3100
John Spurlock80774932015-05-07 17:38:50 -04003101 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04003102 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3103 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3104 return;
3105 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04003106 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003107 if (!checkPolicyAccess(pkg)) {
3108 Slog.w(TAG, "Notification policy access denied calling " + method);
3109 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04003110 }
3111 }
3112
John Spurlock80774932015-05-07 17:38:50 -04003113 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003114 return mConditionProviders.isPackageOrComponentAllowed(
3115 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04003116 }
3117
3118 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003119 try {
Jason Parks50322ff2018-03-27 10:23:33 -05003120 int uid = getContext().getPackageManager().getPackageUidAsUser(pkg,
3121 UserHandle.getCallingUserId());
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003122 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
3123 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
3124 -1, true)) {
3125 return true;
3126 }
3127 } catch (NameNotFoundException e) {
3128 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003129 }
Jason Parks50322ff2018-03-27 10:23:33 -05003130 return checkPackagePolicyAccess(pkg)
3131 || mListeners.isComponentEnabledForPackage(pkg)
3132 || (mDpm != null &&
3133 mDpm.isActiveAdminWithPolicy(Binder.getCallingUid(),
3134 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER));
John Spurlock1fc476d2015-04-14 16:05:20 -04003135 }
3136
John Spurlock7340fc82014-04-24 18:50:12 -04003137 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08003138 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003139 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04003140 final DumpFilter filter = DumpFilter.parseFromArguments(args);
Kweku Adams887f09c2017-11-13 17:12:20 -08003141 if (filter.stats) {
Chris Wrene4b38802015-07-07 15:54:19 -04003142 dumpJson(pw, filter);
Kweku Adams887f09c2017-11-13 17:12:20 -08003143 } else if (filter.proto) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003144 dumpProto(fd, filter);
Vishnu Naire3e4d252018-03-01 11:26:57 -08003145 } else if (filter.criticalPriority) {
3146 dumpNotificationRecords(pw, filter);
Chris Wrene4b38802015-07-07 15:54:19 -04003147 } else {
3148 dumpImpl(pw, filter);
3149 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003150 }
John Spurlockb4782522014-08-22 14:54:46 -04003151
3152 @Override
3153 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07003154 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04003155 }
John Spurlock2b122f42014-08-27 16:29:47 -04003156
3157 @Override
3158 public boolean matchesCallFilter(Bundle extras) {
3159 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02003160 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003161 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02003162 extras,
3163 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
3164 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
3165 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04003166 }
John Spurlock530052a2014-11-30 16:26:19 -05003167
3168 @Override
3169 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003170 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04003171 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05003172 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003173
Christopher Tatef9767d62015-04-08 14:35:43 -07003174 // Backup/restore interface
3175 @Override
3176 public byte[] getBackupPayload(int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003177 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003178 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003179 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003180 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003181 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
3182 return null;
3183 }
songjinshi9bf22712017-02-04 10:47:45 +08003184 synchronized(mPolicyFile) {
3185 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
3186 try {
3187 writePolicyXml(baos, true /*forBackup*/);
3188 return baos.toByteArray();
3189 } catch (IOException e) {
3190 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
3191 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003192 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003193 return null;
3194 }
3195
3196 @Override
3197 public void applyRestore(byte[] payload, int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003198 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003199 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
3200 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
3201 if (payload == null) {
3202 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
3203 return;
3204 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003205 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003206 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003207 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
3208 return;
3209 }
songjinshi9bf22712017-02-04 10:47:45 +08003210 synchronized(mPolicyFile) {
3211 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
3212 try {
3213 readPolicyXml(bais, true /*forRestore*/);
3214 savePolicyFile();
3215 } catch (NumberFormatException | XmlPullParserException | IOException e) {
3216 Slog.w(TAG, "applyRestore: error reading payload", e);
3217 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003218 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003219 }
3220
John Spurlock1fc476d2015-04-14 16:05:20 -04003221 @Override
John Spurlock80774932015-05-07 17:38:50 -04003222 public boolean isNotificationPolicyAccessGranted(String pkg) {
3223 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04003224 }
3225
3226 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05003227 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
3228 enforceSystemOrSystemUIOrSamePackage(pkg,
3229 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003230 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003231 }
3232
3233 @Override
John Spurlock80774932015-05-07 17:38:50 -04003234 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
3235 throws RemoteException {
Julia Reynolds92febc32017-10-26 11:30:31 -04003236 setNotificationPolicyAccessGrantedForUser(
3237 pkg, getCallingUserHandle().getIdentifier(), granted);
3238 }
3239
3240 @Override
3241 public void setNotificationPolicyAccessGrantedForUser(
3242 String pkg, int userId, boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003243 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003244 final long identity = Binder.clearCallingIdentity();
3245 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003246 if (mAllowedManagedServicePackages.test(pkg)) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003247 mConditionProviders.setPackageOrComponentEnabled(
Julia Reynolds92febc32017-10-26 11:30:31 -04003248 pkg, userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003249
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003250 getContext().sendBroadcastAsUser(new Intent(
3251 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3252 .setPackage(pkg)
3253 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003254 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003255 savePolicyFile();
3256 }
3257 } finally {
3258 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003259 }
John Spurlock80774932015-05-07 17:38:50 -04003260 }
3261
3262 @Override
3263 public Policy getNotificationPolicy(String pkg) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003264 final long identity = Binder.clearCallingIdentity();
3265 try {
3266 return mZenModeHelper.getNotificationPolicy();
3267 } finally {
3268 Binder.restoreCallingIdentity(identity);
3269 }
3270 }
3271
Beverly6697eff2017-12-14 15:00:27 -05003272 /**
3273 * Sets the notification policy. Apps that target API levels below
Beverly98ef61b2018-02-15 10:36:28 -05003274 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
Beverlyd6964762018-02-16 14:07:03 -05003275 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3276 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3277 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
Beverly6697eff2017-12-14 15:00:27 -05003278 */
John Spurlock1fc476d2015-04-14 16:05:20 -04003279 @Override
John Spurlock80774932015-05-07 17:38:50 -04003280 public void setNotificationPolicy(String pkg, Policy policy) {
3281 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04003282 final long identity = Binder.clearCallingIdentity();
3283 try {
Beverly6697eff2017-12-14 15:00:27 -05003284 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3285 0, UserHandle.getUserId(MY_UID));
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003286 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
Beverly6697eff2017-12-14 15:00:27 -05003287
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06003288 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
Beverly98ef61b2018-02-15 10:36:28 -05003289 int priorityCategories = policy.priorityCategories;
3290 // ignore alarm and media values from new policy
3291 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
Beverlyd6964762018-02-16 14:07:03 -05003292 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3293 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003294 // use user-designated values
Beverlyd6964762018-02-16 14:07:03 -05003295 priorityCategories |= currPolicy.priorityCategories
3296 & Policy.PRIORITY_CATEGORY_ALARMS;
3297 priorityCategories |= currPolicy.priorityCategories
3298 & Policy.PRIORITY_CATEGORY_MEDIA;
3299 priorityCategories |= currPolicy.priorityCategories
3300 & Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003301
Beverly6697eff2017-12-14 15:00:27 -05003302 policy = new Policy(priorityCategories,
3303 policy.priorityCallSenders, policy.priorityMessageSenders,
3304 policy.suppressedVisualEffects);
3305 }
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003306 int newVisualEffects = calculateSuppressedVisualEffects(
3307 policy, currPolicy, applicationInfo.targetSdkVersion);
3308 policy = new Policy(policy.priorityCategories,
3309 policy.priorityCallSenders, policy.priorityMessageSenders,
3310 newVisualEffects);
Beverly5e073222018-03-08 10:36:25 -05003311 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
John Spurlock1fc476d2015-04-14 16:05:20 -04003312 mZenModeHelper.setNotificationPolicy(policy);
Beverly6697eff2017-12-14 15:00:27 -05003313 } catch (RemoteException e) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003314 } finally {
3315 Binder.restoreCallingIdentity(identity);
3316 }
3317 }
Chris Wren51017d02015-12-15 15:34:46 -05003318
3319 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003320 public List<String> getEnabledNotificationListenerPackages() {
3321 checkCallerIsSystem();
3322 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3323 }
3324
3325 @Override
3326 public List<ComponentName> getEnabledNotificationListeners(int userId) {
3327 checkCallerIsSystem();
3328 return mListeners.getAllowedComponents(userId);
3329 }
3330
3331 @Override
3332 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3333 Preconditions.checkNotNull(listener);
3334 checkCallerIsSystemOrSameApp(listener.getPackageName());
3335 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3336 getCallingUserHandle().getIdentifier());
3337 }
3338
3339 @Override
3340 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3341 int userId) {
3342 Preconditions.checkNotNull(listener);
3343 checkCallerIsSystem();
3344 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3345 userId);
3346 }
3347
3348 @Override
3349 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3350 Preconditions.checkNotNull(assistant);
3351 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003352 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04003353 getCallingUserHandle().getIdentifier());
3354 }
3355
3356 @Override
3357 public void setNotificationListenerAccessGranted(ComponentName listener,
3358 boolean granted) throws RemoteException {
3359 setNotificationListenerAccessGrantedForUser(
3360 listener, getCallingUserHandle().getIdentifier(), granted);
3361 }
3362
3363 @Override
3364 public void setNotificationAssistantAccessGranted(ComponentName assistant,
3365 boolean granted) throws RemoteException {
3366 setNotificationAssistantAccessGrantedForUser(
3367 assistant, getCallingUserHandle().getIdentifier(), granted);
3368 }
3369
3370 @Override
3371 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3372 boolean granted) throws RemoteException {
3373 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04003374 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003375 final long identity = Binder.clearCallingIdentity();
3376 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003377 if (mAllowedManagedServicePackages.test(listener.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003378 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3379 userId, false, granted);
3380 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3381 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003382
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003383 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds92febc32017-10-26 11:30:31 -04003384 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003385 .setPackage(listener.getPackageName())
3386 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003387 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003388
3389 savePolicyFile();
3390 }
3391 } finally {
3392 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003393 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003394 }
3395
3396 @Override
3397 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3398 int userId, boolean granted) throws RemoteException {
3399 Preconditions.checkNotNull(assistant);
Julia Reynolds0d217642017-08-11 11:26:04 -04003400 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003401 final long identity = Binder.clearCallingIdentity();
3402 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003403 if (mAllowedManagedServicePackages.test(assistant.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003404 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
3405 userId, false, granted);
3406 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
3407 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003408
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003409 getContext().sendBroadcastAsUser(new Intent(
3410 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3411 .setPackage(assistant.getPackageName())
3412 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003413 UserHandle.of(userId), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003414
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003415 savePolicyFile();
3416 }
3417 } finally {
3418 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003419 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003420 }
3421
3422 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003423 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
3424 Adjustment adjustment) throws RemoteException {
3425 final long identity = Binder.clearCallingIdentity();
3426 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003427 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003428 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003429 int N = mEnqueuedNotifications.size();
3430 for (int i = 0; i < N; i++) {
3431 final NotificationRecord n = mEnqueuedNotifications.get(i);
3432 if (Objects.equals(adjustment.getKey(), n.getKey())
3433 && Objects.equals(adjustment.getUser(), n.getUserId())) {
3434 applyAdjustment(n, adjustment);
3435 break;
3436 }
3437 }
3438 }
3439 } finally {
3440 Binder.restoreCallingIdentity(identity);
3441 }
3442 }
3443
3444 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003445 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003446 Adjustment adjustment) throws RemoteException {
Chris Wren51017d02015-12-15 15:34:46 -05003447 final long identity = Binder.clearCallingIdentity();
3448 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003449 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003450 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003451 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3452 applyAdjustment(n, adjustment);
Chris Wren51017d02015-12-15 15:34:46 -05003453 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003454 mRankingHandler.requestSort();
Julia Reynoldse46bb372016-03-17 11:05:58 -04003455 } finally {
3456 Binder.restoreCallingIdentity(identity);
3457 }
3458 }
3459
3460 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003461 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003462 List<Adjustment> adjustments) throws RemoteException {
3463
3464 final long identity = Binder.clearCallingIdentity();
3465 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003466 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003467 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003468 for (Adjustment adjustment : adjustments) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003469 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3470 applyAdjustment(n, adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003471 }
3472 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003473 mRankingHandler.requestSort();
Chris Wren51017d02015-12-15 15:34:46 -05003474 } finally {
3475 Binder.restoreCallingIdentity(identity);
3476 }
3477 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003478
3479 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04003480 public void updateNotificationChannelGroupFromPrivilegedListener(
3481 INotificationListener token, String pkg, UserHandle user,
3482 NotificationChannelGroup group) throws RemoteException {
3483 Preconditions.checkNotNull(user);
3484 verifyPrivilegedListener(token, user);
3485 createNotificationChannelGroup(
3486 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
3487 savePolicyFile();
3488 }
3489
3490 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003491 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003492 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003493 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003494 Preconditions.checkNotNull(pkg);
3495 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003496
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003497 verifyPrivilegedListener(token, user);
3498 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003499 }
3500
3501 @Override
3502 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003503 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3504 Preconditions.checkNotNull(pkg);
3505 Preconditions.checkNotNull(user);
3506 verifyPrivilegedListener(token, user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003507
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003508 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
3509 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003510 }
3511
3512 @Override
3513 public ParceledListSlice<NotificationChannelGroup>
3514 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003515 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3516 Preconditions.checkNotNull(pkg);
3517 Preconditions.checkNotNull(user);
3518 verifyPrivilegedListener(token, user);
3519
3520 List<NotificationChannelGroup> groups = new ArrayList<>();
3521 groups.addAll(mRankingHelper.getNotificationChannelGroups(
3522 pkg, getUidForPackageAndUser(pkg, user)));
3523 return new ParceledListSlice<>(groups);
3524 }
3525
3526 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003527 ManagedServiceInfo info;
3528 synchronized (mNotificationLock) {
3529 info = mListeners.checkServiceTokenLocked(token);
3530 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003531 if (!hasCompanionDevice(info)) {
3532 throw new SecurityException(info + " does not have access");
3533 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003534 if (!info.enabledAndUserMatches(user.getIdentifier())) {
3535 throw new SecurityException(info + " does not have access");
3536 }
3537 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003538
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003539 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3540 int uid = 0;
3541 long identity = Binder.clearCallingIdentity();
3542 try {
3543 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3544 } finally {
3545 Binder.restoreCallingIdentity(identity);
3546 }
3547 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003548 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003549
3550 @Override
3551 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3552 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3553 throws RemoteException {
3554 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3555 }
John Spurlock1fc476d2015-04-14 16:05:20 -04003556 };
John Spurlocka4294292014-03-24 18:02:32 -04003557
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003558 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3559 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003560 return;
3561 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003562 if (adjustment.getSignals() != null) {
3563 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003564 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003565 }
3566 }
3567
Julia Reynolds88860ce2017-06-01 16:55:49 -04003568 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003569 void addAutogroupKeyLocked(String key) {
3570 NotificationRecord r = mNotificationsByKey.get(key);
3571 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003572 return;
3573 }
Julia Reynolds51710712017-07-19 13:48:07 -04003574 if (r.sbn.getOverrideGroupKey() == null) {
3575 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3576 EventLogTags.writeNotificationAutogrouped(key);
3577 mRankingHandler.requestSort();
3578 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003579 }
3580
Julia Reynolds88860ce2017-06-01 16:55:49 -04003581 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003582 void removeAutogroupKeyLocked(String key) {
3583 NotificationRecord r = mNotificationsByKey.get(key);
3584 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003585 return;
3586 }
Julia Reynolds51710712017-07-19 13:48:07 -04003587 if (r.sbn.getOverrideGroupKey() != null) {
3588 addAutoGroupAdjustment(r, null);
3589 EventLogTags.writeNotificationUnautogrouped(key);
3590 mRankingHandler.requestSort();
3591 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003592 }
3593
3594 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3595 Bundle signals = new Bundle();
3596 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3597 Adjustment adjustment =
3598 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3599 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003600 }
3601
3602 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04003603 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04003604 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3605 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3606 if (summaries != null && summaries.containsKey(pkg)) {
3607 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003608 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04003609 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04003610 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003611 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003612 }
3613 }
3614 }
3615
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003616 @GuardedBy("mNotificationLock")
3617 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3618 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3619 return summaries != null && summaries.containsKey(sbn.getPackageName());
3620 }
3621
Julia Reynoldse46bb372016-03-17 11:05:58 -04003622 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04003623 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3624 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003625 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003626 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3627 if (notificationRecord == null) {
3628 // The notification could have been cancelled again already. A successive
3629 // adjustment will post a summary if needed.
3630 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003631 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003632 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3633 userId = adjustedSbn.getUser().getIdentifier();
3634 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3635 if (summaries == null) {
3636 summaries = new ArrayMap<>();
3637 }
3638 mAutobundledSummaries.put(userId, summaries);
3639 if (!summaries.containsKey(pkg)) {
3640 // Add summary
3641 final ApplicationInfo appInfo =
3642 adjustedSbn.getNotification().extras.getParcelable(
3643 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3644 final Bundle extras = new Bundle();
3645 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003646 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04003647 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003648 new Notification.Builder(getContext(), channelId)
3649 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04003650 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04003651 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04003652 .setGroup(GroupHelper.AUTOGROUP_KEY)
3653 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3654 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3655 .setColor(adjustedSbn.getNotification().color)
3656 .setLocalOnly(true)
3657 .build();
3658 summaryNotification.extras.putAll(extras);
3659 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3660 if (appIntent != null) {
3661 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3662 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3663 }
3664 final StatusBarNotification summarySbn =
3665 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003666 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003667 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04003668 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3669 adjustedSbn.getInitialPid(), summaryNotification,
3670 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3671 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05003672 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003673 notificationRecord.getChannel());
Rohan Shah590e1b22018-04-10 23:48:47 -04003674 summaryRecord.setIsAppImportanceLocked(
3675 notificationRecord.getIsAppImportanceLocked());
Julia Reynolds8f488d32016-10-14 10:59:01 -04003676 summaries.put(pkg, summarySbn.getKey());
3677 }
3678 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003679 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04003680 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003681 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04003682 }
3683 }
3684
John Spurlock32fe4c62014-10-02 12:16:02 -04003685 private String disableNotificationEffects(NotificationRecord record) {
3686 if (mDisableNotificationEffects) {
3687 return "booleanState";
3688 }
3689 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3690 return "listenerHints";
3691 }
3692 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3693 return "callState";
3694 }
3695 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04003696 };
3697
Kweku Adams887f09c2017-11-13 17:12:20 -08003698 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
Chris Wrene4b38802015-07-07 15:54:19 -04003699 JSONObject dump = new JSONObject();
3700 try {
3701 dump.put("service", "Notification Manager");
Chris Wrenacf424a2016-03-15 12:48:55 -04003702 dump.put("bans", mRankingHelper.dumpBansJson(filter));
3703 dump.put("ranking", mRankingHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003704 dump.put("stats", mUsageStats.dumpJson(filter));
Julia Reynoldsd373d782017-03-03 13:32:57 -05003705 dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003706 } catch (JSONException e) {
3707 e.printStackTrace();
3708 }
3709 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04003710 }
3711
Kweku Adams887f09c2017-11-13 17:12:20 -08003712 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003713 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3714 synchronized (mNotificationLock) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003715 int N = mNotificationList.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003716 for (int i = 0; i < N; i++) {
3717 final NotificationRecord nr = mNotificationList.get(i);
3718 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3719 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3720 NotificationRecordProto.POSTED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003721 }
3722 N = mEnqueuedNotifications.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003723 for (int i = 0; i < N; i++) {
3724 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3725 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3726 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3727 NotificationRecordProto.ENQUEUED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003728 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003729 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3730 N = snoozed.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003731 for (int i = 0; i < N; i++) {
3732 final NotificationRecord nr = snoozed.get(i);
3733 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3734 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3735 NotificationRecordProto.SNOOZED);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003736 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003737
Kweku Adams93304b62017-09-20 17:03:00 -07003738 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3739 mZenModeHelper.dump(proto);
3740 for (ComponentName suppressor : mEffectsSuppressors) {
Kweku Adams99546332018-01-24 17:03:50 -08003741 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
Kweku Adams93304b62017-09-20 17:03:00 -07003742 }
3743 proto.end(zenLog);
3744
3745 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
3746 mListeners.dump(proto, filter);
3747 proto.end(listenersToken);
3748
3749 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
3750
3751 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
3752 long effectsToken = proto.start(
3753 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
3754
3755 proto.write(
3756 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
3757 final ArraySet<ManagedServiceInfo> listeners =
3758 mListenersDisablingEffects.valueAt(i);
3759 for (int j = 0; j < listeners.size(); j++) {
3760 final ManagedServiceInfo listener = listeners.valueAt(i);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08003761 listener.writeToProto(proto, ListenersDisablingEffectsProto.LISTENERS, null);
Kweku Adams93304b62017-09-20 17:03:00 -07003762 }
3763
3764 proto.end(effectsToken);
3765 }
3766
3767 long assistantsToken = proto.start(
3768 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
3769 mAssistants.dump(proto, filter);
3770 proto.end(assistantsToken);
3771
3772 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
3773 mConditionProviders.dump(proto, filter);
3774 proto.end(conditionsToken);
Kweku Adams62b42242017-09-25 12:54:02 -07003775
3776 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
3777 mRankingHelper.dump(proto, filter);
3778 proto.end(rankingToken);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003779 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003780
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003781 proto.flush();
3782 }
3783
Vishnu Naire3e4d252018-03-01 11:26:57 -08003784 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
3785 synchronized (mNotificationLock) {
3786 int N;
3787 N = mNotificationList.size();
3788 if (N > 0) {
3789 pw.println(" Notification List:");
3790 for (int i = 0; i < N; i++) {
3791 final NotificationRecord nr = mNotificationList.get(i);
3792 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3793 nr.dump(pw, " ", getContext(), filter.redact);
3794 }
3795 pw.println(" ");
3796 }
3797 }
3798 }
3799
Kweku Adams887f09c2017-11-13 17:12:20 -08003800 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
John Spurlock25e2d242014-06-27 13:58:23 -04003801 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04003802 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003803 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04003804 }
3805 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08003806 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003807 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003808
John Spurlock50806fc2014-07-15 10:22:02 -04003809 if (!zenOnly) {
3810 synchronized (mToastQueue) {
3811 N = mToastQueue.size();
3812 if (N > 0) {
3813 pw.println(" Toast Queue:");
3814 for (int i=0; i<N; i++) {
3815 mToastQueue.get(i).dump(pw, " ", filter);
3816 }
3817 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003818 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003819 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003820 }
3821
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003822 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04003823 if (!zenOnly) {
Vishnu Naire3e4d252018-03-01 11:26:57 -08003824 // Priority filters are only set when called via bugreport. If set
3825 // skip sections that are part of the critical section.
3826 if (!filter.normalPriority) {
3827 dumpNotificationRecords(pw, filter);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003828 }
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003829 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003830 N = mLights.size();
3831 if (N > 0) {
3832 pw.println(" Lights List:");
3833 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05003834 if (i == N - 1) {
3835 pw.print(" > ");
3836 } else {
3837 pw.print(" ");
3838 }
3839 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04003840 }
3841 pw.println(" ");
3842 }
John Spurlockcb566aa2014-08-03 22:58:28 -04003843 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
Julia Reynolds54369232018-07-03 10:43:35 -04003844 pw.println(" mHasLight=" + mHasLight);
John Spurlockcb566aa2014-08-03 22:58:28 -04003845 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05003846 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3847 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003848 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04003849 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04003850 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04003851 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04003852 }
3853 pw.println(" mArchive=" + mArchive.toString());
3854 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003855 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04003856 while (iter.hasNext()) {
3857 final StatusBarNotification sbn = iter.next();
3858 if (filter != null && !filter.matches(sbn)) continue;
3859 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003860 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04003861 if (iter.hasNext()) pw.println(" ...");
3862 break;
3863 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003864 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003865
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003866 if (!zenOnly) {
3867 N = mEnqueuedNotifications.size();
3868 if (N > 0) {
3869 pw.println(" Enqueued Notification List:");
3870 for (int i = 0; i < N; i++) {
3871 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3872 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3873 nr.dump(pw, " ", getContext(), filter.redact);
3874 }
3875 pw.println(" ");
3876 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003877
3878 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003879 }
3880 }
3881
John Spurlock50806fc2014-07-15 10:22:02 -04003882 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04003883 pw.println("\n Ranking Config:");
3884 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04003885
John Spurlock50806fc2014-07-15 10:22:02 -04003886 pw.println("\n Notification listeners:");
3887 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003888 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3889 pw.print(" mListenersDisablingEffects: (");
3890 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04003891 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003892 final int hint = mListenersDisablingEffects.keyAt(i);
3893 if (i > 0) pw.print(';');
3894 pw.print("hint[" + hint + "]:");
3895
3896 final ArraySet<ManagedServiceInfo> listeners =
3897 mListenersDisablingEffects.valueAt(i);
3898 final int listenerSize = listeners.size();
3899
3900 for (int j = 0; j < listenerSize; j++) {
3901 if (i > 0) pw.print(',');
3902 final ManagedServiceInfo listener = listeners.valueAt(i);
Julia Reynolds1f580572018-04-27 14:48:36 -04003903 if (listener != null) {
3904 pw.print(listener.component);
3905 }
Bryce Lee7219ada2016-04-08 10:54:23 -07003906 }
John Spurlock1fa865f2014-07-21 14:56:39 -04003907 }
3908 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05003909 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003910 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04003911 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003912
Julia Reynolds520df6e2017-02-13 09:05:10 -05003913 if (!filter.filtered || zenOnly) {
3914 pw.println("\n Zen Mode:");
3915 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3916 mZenModeHelper.dump(pw, " ");
3917
3918 pw.println("\n Zen Log:");
3919 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003920 }
3921
John Spurlocke77bb362014-04-26 10:24:59 -04003922 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04003923 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02003924
3925 pw.println("\n Group summaries:");
3926 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3927 NotificationRecord r = entry.getValue();
3928 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3929 if (mNotificationsByKey.get(r.getKey()) != r) {
3930 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04003931 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02003932 }
3933 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003934
3935 if (!zenOnly) {
3936 pw.println("\n Usage Stats:");
3937 mUsageStats.dump(pw, " ", filter);
3938 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003939 }
3940 }
3941
Adam Lesinski182f73f2013-12-05 16:48:06 -08003942 /**
3943 * The private API only accessible to the system process.
3944 */
3945 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3946 @Override
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04003947 public NotificationChannel getNotificationChannel(String pkg, int uid, String
3948 channelId) {
3949 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
3950 }
3951
3952 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003953 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003954 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003955 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003956 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003957 }
Christoph Studer365e4c32014-09-18 20:35:36 +02003958
3959 @Override
3960 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3961 int userId) {
3962 checkCallerIsSystem();
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003963 mHandler.post(new Runnable() {
3964 @Override
3965 public void run() {
3966 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003967 removeForegroundServiceFlagByListLocked(
3968 mEnqueuedNotifications, pkg, notificationId, userId);
3969 removeForegroundServiceFlagByListLocked(
3970 mNotificationList, pkg, notificationId, userId);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003971 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003972 }
3973 });
3974 }
3975
Julia Reynolds88860ce2017-06-01 16:55:49 -04003976 @GuardedBy("mNotificationLock")
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003977 private void removeForegroundServiceFlagByListLocked(
Julia Reynolds88860ce2017-06-01 16:55:49 -04003978 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3979 int userId) {
3980 NotificationRecord r = findNotificationByListLocked(
3981 notificationList, pkg, null, notificationId, userId);
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003982 if (r == null) {
3983 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02003984 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003985 StatusBarNotification sbn = r.sbn;
3986 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3987 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3988 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3989 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3990 sbn.getNotification().flags =
Julia Reynoldse5c60452018-04-30 14:41:36 -04003991 (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003992 mRankingHelper.sort(mNotificationList);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06003993 mListeners.notifyPostedLocked(r, r);
Christoph Studer365e4c32014-09-18 20:35:36 +02003994 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003995 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003996
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003997 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04003998 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003999 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04004000 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08004001 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
4002 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04004003 }
John Spurlock7340fc82014-04-24 18:50:12 -04004004 checkCallerIsSystemOrSameApp(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004005
Scott Greenwald9b05c612013-06-25 23:44:05 -04004006 final int userId = ActivityManager.handleIncomingUser(callingPid,
4007 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
Jeff Sharkey65c4a2b2012-09-25 17:22:27 -07004008 final UserHandle user = new UserHandle(userId);
Dianne Hackborn41203752012-08-31 14:05:51 -07004009
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004010 if (pkg == null || notification == null) {
4011 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
4012 + " id=" + id + " notification=" + notification);
4013 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004014
4015 // The system can post notifications for any package, let us resolve that.
4016 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
4017
Julia Reynoldse46bb372016-03-17 11:05:58 -04004018 // Fix the notification as best we can.
4019 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004020 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06004021 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
Julia Reynoldse0d711f2017-09-01 08:50:47 -04004022 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
Julia Reynoldse071abd2017-03-22 10:52:11 -04004023 Notification.addFieldsFromContext(ai, notification);
Julia Reynolds4db59552017-06-30 13:34:01 -04004024
4025 int canColorize = mPackageManagerClient.checkPermission(
4026 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
4027 if (canColorize == PERMISSION_GRANTED) {
4028 notification.flags |= Notification.FLAG_CAN_COLORIZE;
4029 } else {
4030 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
4031 }
4032
Julia Reynoldse46bb372016-03-17 11:05:58 -04004033 } catch (NameNotFoundException e) {
4034 Slog.e(TAG, "Cannot create a context for sending app", e);
4035 return;
4036 }
4037
Chris Wren888b7a82016-06-17 15:47:19 -04004038 mUsageStats.registerEnqueuedByApp(pkg);
4039
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004040 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04004041 String channelId = notification.getChannelId();
4042 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
4043 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05004044 }
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004045 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004046 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004047 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004048 final String noChannelStr = "No Channel found for "
4049 + "pkg=" + pkg
4050 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04004051 + ", id=" + id
4052 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004053 + ", opPkg=" + opPkg
4054 + ", callingUid=" + callingUid
4055 + ", userId=" + userId
4056 + ", incomingUserId=" + incomingUserId
4057 + ", notificationUid=" + notificationUid
4058 + ", notification=" + notification;
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004059 Log.e(TAG, noChannelStr);
Beverly5d4564b2018-04-10 20:09:23 -04004060 boolean appNotificationsOff = mRankingHelper.getImportance(pkg, notificationUid)
4061 == NotificationManager.IMPORTANCE_NONE;
4062
4063 if (!appNotificationsOff) {
4064 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
4065 "Failed to post notification on channel \"" + channelId + "\"\n" +
4066 "See log for more details");
4067 }
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004068 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004069 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004070
Chris Wrena61f1792016-08-04 11:24:42 -04004071 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004072 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004073 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004074 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Rohan Shah590e1b22018-04-10 23:48:47 -04004075 r.setIsAppImportanceLocked(mRankingHelper.getIsAppImportanceLocked(pkg, callingUid));
Chris Wrena61f1792016-08-04 11:24:42 -04004076
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004077 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4078 final boolean fgServiceShown = channel.isFgServiceShown();
4079 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
4080 || !fgServiceShown)
4081 && (r.getImportance() == IMPORTANCE_MIN
4082 || r.getImportance() == IMPORTANCE_NONE)) {
4083 // Increase the importance of foreground service notifications unless the user had
4084 // an opinion otherwise (and the channel hasn't yet shown a fg service).
4085 if (TextUtils.isEmpty(channelId)
4086 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4087 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
4088 } else {
4089 channel.setImportance(IMPORTANCE_LOW);
4090 if (!fgServiceShown) {
4091 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
4092 channel.setFgServiceShown(true);
4093 }
4094 mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
4095 r.updateNotificationChannel(channel);
4096 }
4097 } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
4098 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4099 channel.setFgServiceShown(true);
Julia Reynolds8617e4e2017-09-18 16:52:37 -04004100 r.updateNotificationChannel(channel);
4101 }
4102 }
4103
Julia Reynolds5e702192017-08-18 09:22:40 -04004104 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
4105 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004106 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07004107 }
4108
Felipe Lemedd85da62016-06-28 11:29:54 -07004109 // Whitelist pending intents.
4110 if (notification.allPendingIntents != null) {
4111 final int intentCount = notification.allPendingIntents.size();
4112 if (intentCount > 0) {
4113 final ActivityManagerInternal am = LocalServices
4114 .getService(ActivityManagerInternal.class);
4115 final long duration = LocalServices.getService(
4116 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
4117 for (int i = 0; i < intentCount; i++) {
4118 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4119 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07004120 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4121 WHITELIST_TOKEN, duration);
Felipe Lemedd85da62016-06-28 11:29:54 -07004122 }
4123 }
4124 }
4125 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07004126
Chris Wren47633422016-01-22 09:56:59 -05004127 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004128 }
4129
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04004130 private void doChannelWarningToast(CharSequence toastText) {
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04004131 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04004132 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04004133 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4134 if (warningEnabled) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04004135 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
Geoffrey Pitsch5bdddbd2017-05-26 10:50:05 -04004136 Toast.LENGTH_SHORT);
Geoffrey Pitschd34c1872017-05-04 16:02:15 -04004137 toast.show();
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004138 }
4139 }
4140
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004141 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
4142 // The system can post notifications on behalf of any package it wants
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004143 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004144 try {
4145 return getContext().getPackageManager()
4146 .getPackageUidAsUser(opPackageName, userId);
4147 } catch (NameNotFoundException e) {
4148 /* ignore */
4149 }
4150 }
4151 return callingUid;
4152 }
4153
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004154 /**
4155 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4156 *
4157 * Has side effects.
4158 */
4159 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04004160 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004161 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004162 final boolean isSystemNotification =
4163 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004164 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
4165
4166 // Limit the number of notifications that any given package except the android
4167 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
4168 if (!isSystemNotification && !isNotificationFromListener) {
4169 synchronized (mNotificationLock) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004170 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
4171 // Ephemeral apps have some special constraints for notifications.
4172 // They are not allowed to create new notifications however they are allowed to
4173 // update notifications created by the system (e.g. a foreground service
4174 // notification).
4175 throw new SecurityException("Instant app " + pkg
4176 + " cannot create notifications");
4177 }
4178
4179 // rate limit updates that aren't completed progress notifications
4180 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04004181 && !r.getNotification().hasCompletedProgress()
4182 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004183
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004184 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
4185 if (appEnqueueRate > mMaxPackageEnqueueRate) {
4186 mUsageStats.registerOverRateQuota(pkg);
4187 final long now = SystemClock.elapsedRealtime();
4188 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
4189 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04004190 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004191 mLastOverRateLogTime = now;
4192 }
4193 return false;
4194 }
4195 }
4196
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004197 // limit the number of outstanding notificationrecords an app can have
4198 int count = getNotificationCountLocked(pkg, userId, id, tag);
4199 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
4200 mUsageStats.registerOverCountQuota(pkg);
4201 Slog.e(TAG, "Package has already posted or enqueued " + count
4202 + " notifications. Not showing more. package=" + pkg);
4203 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004204 }
4205 }
4206 }
4207
4208 // snoozed apps
4209 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05004210 MetricsLogger.action(r.getLogMaker()
4211 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
4212 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004213 if (DBG) {
4214 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
4215 }
4216 mSnoozeHelper.update(userId, r);
4217 savePolicyFile();
4218 return false;
4219 }
4220
4221
4222 // blocked apps
4223 if (isBlocked(r, mUsageStats)) {
4224 return false;
4225 }
4226
4227 return true;
4228 }
4229
Andreas Gampea36dc622018-02-05 17:19:22 -08004230 @GuardedBy("mNotificationLock")
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004231 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
4232 String excludedTag) {
4233 int count = 0;
4234 final int N = mNotificationList.size();
4235 for (int i = 0; i < N; i++) {
4236 final NotificationRecord existing = mNotificationList.get(i);
4237 if (existing.sbn.getPackageName().equals(pkg)
4238 && existing.sbn.getUserId() == userId) {
4239 if (existing.sbn.getId() == excludedId
4240 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
4241 continue;
4242 }
4243 count++;
4244 }
4245 }
4246 final int M = mEnqueuedNotifications.size();
4247 for (int i = 0; i < M; i++) {
4248 final NotificationRecord existing = mEnqueuedNotifications.get(i);
4249 if (existing.sbn.getPackageName().equals(pkg)
4250 && existing.sbn.getUserId() == userId) {
4251 count++;
4252 }
4253 }
4254 return count;
4255 }
4256
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004257 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
4258 final String pkg = r.sbn.getPackageName();
4259 final int callingUid = r.sbn.getUid();
4260
4261 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
4262 if (isPackageSuspended) {
4263 Slog.e(TAG, "Suppressing notification from package due to package "
4264 + "suspended by administrator.");
4265 usageStats.registerSuspendedByAdmin(r);
4266 return isPackageSuspended;
4267 }
Julia Reynolds4da79702017-06-01 11:06:10 -04004268 final boolean isBlocked =
Julia Reynolds005c8b92017-08-24 10:35:53 -04004269 mRankingHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
4270 || mRankingHelper.getImportance(pkg, callingUid)
4271 == NotificationManager.IMPORTANCE_NONE
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04004272 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004273 if (isBlocked) {
4274 Slog.e(TAG, "Suppressing notification from package by user request.");
4275 usageStats.registerBlocked(r);
4276 }
4277 return isBlocked;
4278 }
4279
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004280 protected class SnoozeNotificationRunnable implements Runnable {
4281 private final String mKey;
4282 private final long mDuration;
4283 private final String mSnoozeCriterionId;
4284
4285 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
4286 mKey = key;
4287 mDuration = duration;
4288 mSnoozeCriterionId = snoozeCriterionId;
4289 }
4290
4291 @Override
4292 public void run() {
4293 synchronized (mNotificationLock) {
4294 final NotificationRecord r = findNotificationByKeyLocked(mKey);
4295 if (r != null) {
4296 snoozeLocked(r);
4297 }
4298 }
4299 }
4300
Julia Reynolds88860ce2017-06-01 16:55:49 -04004301 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004302 void snoozeLocked(NotificationRecord r) {
4303 if (r.sbn.isGroup()) {
4304 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
4305 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
4306 if (r.getNotification().isGroupSummary()) {
4307 // snooze summary and all children
4308 for (int i = 0; i < groupNotifications.size(); i++) {
4309 snoozeNotificationLocked(groupNotifications.get(i));
4310 }
4311 } else {
4312 // if there is a valid summary for this group, and we are snoozing the only
4313 // child, also snooze the summary
4314 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
4315 if (groupNotifications.size() != 2) {
4316 snoozeNotificationLocked(r);
4317 } else {
4318 // snooze summary and the one child
4319 for (int i = 0; i < groupNotifications.size(); i++) {
4320 snoozeNotificationLocked(groupNotifications.get(i));
4321 }
4322 }
4323 } else {
4324 snoozeNotificationLocked(r);
4325 }
4326 }
4327 } else {
4328 // just snooze the one notification
4329 snoozeNotificationLocked(r);
4330 }
4331 }
4332
Julia Reynolds88860ce2017-06-01 16:55:49 -04004333 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004334 void snoozeNotificationLocked(NotificationRecord r) {
4335 MetricsLogger.action(r.getLogMaker()
4336 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4337 .setType(MetricsEvent.TYPE_CLOSE)
Chris Wren21a2e722017-10-02 17:44:53 -04004338 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
4339 mDuration)
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004340 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4341 mSnoozeCriterionId == null ? 0 : 1));
Julia Reynolds0839c022017-06-15 15:24:01 -04004342 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004343 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004344 updateLightsLocked();
4345 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004346 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004347 mSnoozeHelper.snooze(r);
4348 } else {
4349 mSnoozeHelper.snooze(r, mDuration);
4350 }
Julia Reynolds503ed942017-10-04 16:04:56 -04004351 r.recordSnoozed();
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004352 savePolicyFile();
4353 }
4354 }
4355
Julia Reynoldsbaff4002016-12-15 11:34:26 -05004356 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05004357 private final NotificationRecord r;
4358 private final int userId;
4359
4360 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
4361 this.userId = userId;
4362 this.r = r;
4363 };
4364
4365 @Override
4366 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004367 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05004368 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05004369 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05004370
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004371 final StatusBarNotification n = r.sbn;
4372 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
4373 NotificationRecord old = mNotificationsByKey.get(n.getKey());
4374 if (old != null) {
4375 // Retain ranking information from previous record
4376 r.copyRankingInformation(old);
4377 }
4378
4379 final int callingUid = n.getUid();
4380 final int callingPid = n.getInitialPid();
4381 final Notification notification = n.getNotification();
4382 final String pkg = n.getPackageName();
4383 final int id = n.getId();
4384 final String tag = n.getTag();
4385
4386 // Handle grouped notifications and bail out early if we
4387 // can to avoid extracting signals.
4388 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
4389
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004390 // if this is a group child, unsnooze parent summary
4391 if (n.isGroup() && notification.isGroupChild()) {
4392 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
4393 }
4394
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004395 // This conditional is a dirty hack to limit the logging done on
4396 // behalf of the download manager without affecting other apps.
4397 if (!pkg.equals("com.android.providers.downloads")
4398 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
4399 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05004400 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004401 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05004402 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004403 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
4404 pkg, id, tag, userId, notification.toString(),
4405 enqueueStatus);
4406 }
Chris Wren6676dab2016-12-21 18:26:27 -05004407
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004408 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05004409
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004410 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004411 if (mAssistants.isEnabled()) {
4412 mAssistants.onNotificationEnqueued(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004413 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004414 DELAY_FOR_ASSISTANT_TIME);
4415 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004416 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004417 }
4418 }
4419 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004420 }
4421
Beverly5a20a5e2018-03-06 15:02:44 -05004422 @GuardedBy("mNotificationLock")
4423 private boolean isPackageSuspendedLocked(NotificationRecord r) {
4424 final String pkg = r.sbn.getPackageName();
4425 final int callingUid = r.sbn.getUid();
4426
4427 return isPackageSuspendedForUser(pkg, callingUid);
4428 }
4429
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004430 protected class PostNotificationRunnable implements Runnable {
4431 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004432
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004433 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004434 this.key = key;
4435 }
4436
4437 @Override
4438 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004439 synchronized (mNotificationLock) {
4440 try {
4441 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004442 int N = mEnqueuedNotifications.size();
4443 for (int i = 0; i < N; i++) {
4444 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4445 if (Objects.equals(key, enqueued.getKey())) {
4446 r = enqueued;
4447 break;
Chris Wren6676dab2016-12-21 18:26:27 -05004448 }
Chris Wren6676dab2016-12-21 18:26:27 -05004449 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004450 if (r == null) {
4451 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
4452 return;
4453 }
Beverly5a20a5e2018-03-06 15:02:44 -05004454
4455 r.setHidden(isPackageSuspendedLocked(r));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004456 NotificationRecord old = mNotificationsByKey.get(key);
4457 final StatusBarNotification n = r.sbn;
4458 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05004459 int index = indexOfNotificationLocked(n.getKey());
4460 if (index < 0) {
4461 mNotificationList.add(r);
4462 mUsageStats.registerPostedByApp(r);
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004463 r.setInterruptive(isVisuallyInterruptive(null, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004464 } else {
4465 old = mNotificationList.get(index);
4466 mNotificationList.set(index, r);
4467 mUsageStats.registerUpdatedByApp(r, old);
4468 // Make sure we don't lose the foreground service state.
4469 notification.flags |=
Julia Reynoldse5c60452018-04-30 14:41:36 -04004470 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
Chris Wren6676dab2016-12-21 18:26:27 -05004471 r.isUpdate = true;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04004472 r.setTextChanged(isVisuallyInterruptive(old, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004473 }
4474
4475 mNotificationsByKey.put(n.getKey(), r);
4476
4477 // Ensure if this is a foreground service that the proper additional
4478 // flags are set.
Julia Reynoldse5c60452018-04-30 14:41:36 -04004479 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
Chris Wren6676dab2016-12-21 18:26:27 -05004480 notification.flags |= Notification.FLAG_ONGOING_EVENT
4481 | Notification.FLAG_NO_CLEAR;
4482 }
4483
4484 applyZenModeLocked(r);
4485 mRankingHelper.sort(mNotificationList);
4486
4487 if (notification.getSmallIcon() != null) {
4488 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06004489 mListeners.notifyPostedLocked(r, old);
Julia Reynolds8aebf352017-06-26 11:35:33 -04004490 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
4491 mHandler.post(new Runnable() {
4492 @Override
4493 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04004494 mGroupHelper.onNotificationPosted(
4495 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04004496 }
4497 });
4498 }
Chris Wren6676dab2016-12-21 18:26:27 -05004499 } else {
4500 Slog.e(TAG, "Not posting notification without small icon: " + notification);
4501 if (old != null && !old.isCanceled) {
Beverly5a20a5e2018-03-06 15:02:44 -05004502 mListeners.notifyRemovedLocked(r,
Julia Reynolds503ed942017-10-04 16:04:56 -04004503 NotificationListenerService.REASON_ERROR, null);
Chris Wren6676dab2016-12-21 18:26:27 -05004504 mHandler.post(new Runnable() {
4505 @Override
4506 public void run() {
4507 mGroupHelper.onNotificationRemoved(n);
4508 }
4509 });
4510 }
4511 // ATTENTION: in a future release we will bail out here
4512 // so that we do not play sounds, show lights, etc. for invalid
4513 // notifications
4514 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
4515 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05004516 }
Chris Wren47633422016-01-22 09:56:59 -05004517
Beverly5a20a5e2018-03-06 15:02:44 -05004518 if (!r.isHidden()) {
4519 buzzBeepBlinkLocked(r);
4520 }
Julia Reynolds1fac86e2018-03-07 08:30:37 -05004521 maybeRecordInterruptionLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004522 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004523 int N = mEnqueuedNotifications.size();
4524 for (int i = 0; i < N; i++) {
4525 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4526 if (Objects.equals(key, enqueued.getKey())) {
4527 mEnqueuedNotifications.remove(i);
4528 break;
4529 }
4530 }
Chris Wren6676dab2016-12-21 18:26:27 -05004531 }
Chris Wren47633422016-01-22 09:56:59 -05004532 }
4533 }
4534 }
4535
Christoph Studer265c1052014-07-23 17:14:33 +02004536 /**
Julia Reynolds7217dc92018-03-07 12:12:09 -05004537 * If the notification differs enough visually, consider it a new interruptive notification.
4538 */
4539 @GuardedBy("mNotificationLock")
4540 @VisibleForTesting
4541 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
Julia Reynolds6b302d02018-06-19 15:39:23 -04004542 // Ignore summary updates because we don't display most of the information.
4543 if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
4544 if (DEBUG_INTERRUPTIVENESS) {
4545 Log.v(TAG, "INTERRUPTIVENESS: "
4546 + r.getKey() + " is not interruptive: summary");
4547 }
4548 return false;
4549 }
4550
Dan Sandler7d67bd42018-05-15 14:06:38 -04004551 if (old == null) {
4552 if (DEBUG_INTERRUPTIVENESS) {
4553 Log.v(TAG, "INTERRUPTIVENESS: "
4554 + r.getKey() + " is interruptive: new notification");
4555 }
4556 return true;
4557 }
4558
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004559 if (r == null) {
4560 if (DEBUG_INTERRUPTIVENESS) {
4561 Log.v(TAG, "INTERRUPTIVENESS: "
4562 + r.getKey() + " is not interruptive: null");
4563 }
4564 return false;
4565 }
4566
Julia Reynolds7217dc92018-03-07 12:12:09 -05004567 Notification oldN = old.sbn.getNotification();
4568 Notification newN = r.sbn.getNotification();
Dan Sandler7d67bd42018-05-15 14:06:38 -04004569
Julia Reynolds7217dc92018-03-07 12:12:09 -05004570 if (oldN.extras == null || newN.extras == null) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004571 if (DEBUG_INTERRUPTIVENESS) {
4572 Log.v(TAG, "INTERRUPTIVENESS: "
4573 + r.getKey() + " is not interruptive: no extras");
4574 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004575 return false;
4576 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004577
4578 // Ignore visual interruptions from foreground services because users
4579 // consider them one 'session'. Count them for everything else.
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004580 if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004581 if (DEBUG_INTERRUPTIVENESS) {
4582 Log.v(TAG, "INTERRUPTIVENESS: "
4583 + r.getKey() + " is not interruptive: foreground service");
4584 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004585 return false;
4586 }
4587
Dan Sandler7d67bd42018-05-15 14:06:38 -04004588 final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
4589 final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
4590 if (!Objects.equals(oldTitle, newTitle)) {
4591 if (DEBUG_INTERRUPTIVENESS) {
4592 Log.v(TAG, "INTERRUPTIVENESS: "
4593 + r.getKey() + " is interruptive: changed title");
4594 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)",
4595 oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
4596 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)",
4597 newTitle, newTitle.getClass(), newTitle.hashCode()));
4598 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004599 return true;
4600 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004601 // Do not compare Spannables (will always return false); compare unstyled Strings
4602 final String oldText = String.valueOf(oldN.extras.get(Notification.EXTRA_TEXT));
4603 final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT));
4604 if (!Objects.equals(oldText, newText)) {
4605 if (DEBUG_INTERRUPTIVENESS) {
4606 Log.v(TAG, "INTERRUPTIVENESS: "
4607 + r.getKey() + " is interruptive: changed text");
4608 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)",
4609 oldText, oldText.getClass(), oldText.hashCode()));
4610 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)",
4611 newText, newText.getClass(), newText.hashCode()));
4612 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004613 return true;
4614 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004615 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
4616 if (DEBUG_INTERRUPTIVENESS) {
4617 Log.v(TAG, "INTERRUPTIVENESS: "
4618 + r.getKey() + " is interruptive: completed progress");
4619 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004620 return true;
4621 }
4622 // Actions
4623 if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004624 if (DEBUG_INTERRUPTIVENESS) {
4625 Log.v(TAG, "INTERRUPTIVENESS: "
4626 + r.getKey() + " is interruptive: changed actions");
4627 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004628 return true;
4629 }
4630
4631 try {
4632 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
4633 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
4634
4635 // Style based comparisons
4636 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004637 if (DEBUG_INTERRUPTIVENESS) {
4638 Log.v(TAG, "INTERRUPTIVENESS: "
4639 + r.getKey() + " is interruptive: styles differ");
4640 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004641 return true;
4642 }
4643
4644 // Remote views
4645 if (Notification.areRemoteViewsChanged(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004646 if (DEBUG_INTERRUPTIVENESS) {
4647 Log.v(TAG, "INTERRUPTIVENESS: "
4648 + r.getKey() + " is interruptive: remoteviews differ");
4649 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004650 return true;
4651 }
4652 } catch (Exception e) {
4653 Slog.w(TAG, "error recovering builder", e);
4654 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004655
Julia Reynolds7217dc92018-03-07 12:12:09 -05004656 return false;
4657 }
4658
4659 /**
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05004660 * Keeps the last 5 packages that have notified, by user.
4661 */
4662 @GuardedBy("mNotificationLock")
4663 @VisibleForTesting
4664 protected void logRecentLocked(NotificationRecord r) {
4665 if (r.isUpdate) {
4666 return;
4667 }
4668 ArrayList<NotifyingApp> recentAppsForUser =
4669 mRecentApps.getOrDefault(r.getUser().getIdentifier(), new ArrayList<>(6));
4670 NotifyingApp na = new NotifyingApp()
4671 .setPackage(r.sbn.getPackageName())
4672 .setUid(r.sbn.getUid())
4673 .setLastNotified(r.sbn.getPostTime());
4674 // A new notification gets an app moved to the front of the list
4675 for (int i = recentAppsForUser.size() - 1; i >= 0; i--) {
4676 NotifyingApp naExisting = recentAppsForUser.get(i);
4677 if (na.getPackage().equals(naExisting.getPackage())
4678 && na.getUid() == naExisting.getUid()) {
4679 recentAppsForUser.remove(i);
4680 break;
4681 }
4682 }
4683 // time is always increasing, so always add to the front of the list
4684 recentAppsForUser.add(0, na);
4685 if (recentAppsForUser.size() > 5) {
4686 recentAppsForUser.remove(recentAppsForUser.size() -1);
4687 }
4688 mRecentApps.put(r.getUser().getIdentifier(), recentAppsForUser);
4689 }
4690
4691 /**
Christoph Studer265c1052014-07-23 17:14:33 +02004692 * Ensures that grouped notification receive their special treatment.
4693 *
4694 * <p>Cancels group children if the new notification causes a group to lose
4695 * its summary.</p>
4696 *
4697 * <p>Updates mSummaryByGroupKey.</p>
4698 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004699 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02004700 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
4701 int callingUid, int callingPid) {
4702 StatusBarNotification sbn = r.sbn;
4703 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07004704 if (n.isGroupSummary() && !sbn.isAppGroup()) {
4705 // notifications without a group shouldn't be a summary, otherwise autobundling can
4706 // lead to bugs
4707 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
4708 }
4709
Christoph Studer265c1052014-07-23 17:14:33 +02004710 String group = sbn.getGroupKey();
4711 boolean isSummary = n.isGroupSummary();
4712
4713 Notification oldN = old != null ? old.sbn.getNotification() : null;
4714 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
4715 boolean oldIsSummary = old != null && oldN.isGroupSummary();
4716
4717 if (oldIsSummary) {
4718 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
4719 if (removedSummary != old) {
4720 String removedKey =
4721 removedSummary != null ? removedSummary.getKey() : "<null>";
4722 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
4723 ", removed=" + removedKey);
4724 }
4725 }
4726 if (isSummary) {
4727 mSummaryByGroupKey.put(group, r);
4728 }
4729
4730 // Clear out group children of the old notification if the update
4731 // causes the group summary to go away. This happens when the old
4732 // notification was a summary and the new one isn't, or when the old
4733 // notification was a summary and its group key changed.
4734 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04004735 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
4736 null);
Christoph Studer265c1052014-07-23 17:14:33 +02004737 }
4738 }
4739
Chris Wren93bb8b82016-03-29 14:35:05 -04004740 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004741 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05004742 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04004743 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05004744 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4745 REQUEST_CODE_TIMEOUT,
4746 new Intent(ACTION_NOTIFICATION_TIMEOUT)
4747 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4748 .appendPath(record.getKey()).build())
4749 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4750 .putExtra(EXTRA_KEY, record.getKey()),
4751 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05004752 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04004753 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05004754 }
4755 }
4756
4757 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004758 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04004759 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04004760 boolean buzz = false;
4761 boolean beep = false;
4762 boolean blink = false;
4763
Chris Wrena3446562014-06-03 18:11:47 -04004764 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04004765 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04004766
4767 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04004768 final boolean aboveThreshold =
4769 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04004770
4771 // Remember if this notification already owns the notification channels.
4772 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4773 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04004774 // These are set inside the conditional if the notification is allowed to make noise.
4775 boolean hasValidVibrate = false;
4776 boolean hasValidSound = false;
Julia Reynolds94187562017-10-10 13:58:49 -04004777 boolean sentAccessibilityEvent = false;
4778 // If the notification will appear in the status bar, it should send an accessibility
4779 // event
4780 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4781 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4782 sentAccessibilityEvent = true;
4783 }
Chris Wrena3446562014-06-03 18:11:47 -04004784
Julia Reynolds76c096d2017-06-19 08:16:04 -04004785 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004786
Julia Reynolds76c096d2017-06-19 08:16:04 -04004787 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004788 Uri soundUri = record.getSound();
4789 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4790 long[] vibration = record.getVibration();
4791 // Demote sound to vibration if vibration missing & phone in vibration mode.
4792 if (vibration == null
4793 && hasValidSound
4794 && (mAudioManager.getRingerModeInternal()
Julia Reynolds85896572017-09-20 12:54:52 -04004795 == AudioManager.RINGER_MODE_VIBRATE)
4796 && mAudioManager.getStreamVolume(
4797 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004798 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04004799 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004800 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01004801
Julia Reynolds76c096d2017-06-19 08:16:04 -04004802 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
Julia Reynolds76c096d2017-06-19 08:16:04 -04004803 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004804 if (!sentAccessibilityEvent) {
4805 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4806 sentAccessibilityEvent = true;
4807 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004808 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04004809 if (hasValidSound) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004810 if (mInCall) {
4811 playInCallNotification();
4812 beep = true;
4813 } else {
4814 beep = playSound(record, soundUri);
4815 }
Seungho Lee2ca1aec2018-12-09 19:27:36 +09004816 if(beep) {
4817 mSoundNotificationKey = key;
4818 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004819 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004820
Julia Reynolds7c96b582017-05-25 12:35:36 -04004821 final boolean ringerModeSilent =
4822 mAudioManager.getRingerModeInternal()
4823 == AudioManager.RINGER_MODE_SILENT;
4824 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004825 buzz = playVibration(record, vibration, hasValidSound);
Seungho Lee2ca1aec2018-12-09 19:27:36 +09004826 if(buzz) {
4827 mVibrateNotificationKey = key;
4828 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004829 }
Chris Wrena3446562014-06-03 18:11:47 -04004830 }
4831 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004832 }
4833 // If a notification is updated to remove the actively playing sound or vibrate,
4834 // cancel that feedback now
4835 if (wasBeep && !hasValidSound) {
4836 clearSoundLocked();
4837 }
4838 if (wasBuzz && !hasValidVibrate) {
4839 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04004840 }
4841
4842 // light
4843 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04004844 boolean wasShowLights = mLights.remove(key);
Julia Reynolds54369232018-07-03 10:43:35 -04004845 if (canShowLightsLocked(record, aboveThreshold)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04004846 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04004847 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04004848 if (mUseAttentionLight) {
4849 mAttentionLight.pulse();
4850 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004851 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04004852 } else if (wasShowLights) {
4853 updateLightsLocked();
4854 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004855 if (buzz || beep || blink) {
Julia Reynolds54369232018-07-03 10:43:35 -04004856 // Ignore summary updates because we don't display most of the information.
4857 if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) {
4858 if (DEBUG_INTERRUPTIVENESS) {
4859 Log.v(TAG, "INTERRUPTIVENESS: "
4860 + record.getKey() + " is not interruptive: summary");
4861 }
4862 } else {
4863 if (DEBUG_INTERRUPTIVENESS) {
4864 Log.v(TAG, "INTERRUPTIVENESS: "
4865 + record.getKey() + " is interruptive: alerted");
4866 }
4867 record.setInterruptive(true);
4868 }
Julia Reynolds445cfa82017-05-08 15:41:45 -04004869 MetricsLogger.action(record.getLogMaker()
4870 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4871 .setType(MetricsEvent.TYPE_OPEN)
4872 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4873 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04004874 }
Chris Wrena3446562014-06-03 18:11:47 -04004875 }
4876
Julia Reynolds88860ce2017-06-01 16:55:49 -04004877 @GuardedBy("mNotificationLock")
Julia Reynolds54369232018-07-03 10:43:35 -04004878 boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
4879 // device lacks light
4880 if (!mHasLight) {
4881 return false;
4882 }
4883 // user turned lights off globally
4884 if (!mNotificationPulseEnabled) {
4885 return false;
4886 }
4887 // the notification/channel has no light
4888 if (record.getLight() == null) {
4889 return false;
4890 }
4891 // unimportant notification
4892 if (!aboveThreshold) {
4893 return false;
4894 }
4895 // suppressed due to DND
4896 if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
4897 return false;
4898 }
4899 // Suppressed because it's a silent update
4900 final Notification notification = record.getNotification();
4901 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4902 return false;
4903 }
4904 // Suppressed because another notification in its group handles alerting
4905 if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
4906 return false;
4907 }
4908 // not if in call or the screen's on
4909 if (mInCall || mScreenOn) {
4910 return false;
4911 }
4912
4913 return true;
4914 }
4915
4916 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004917 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04004918 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004919 final Notification notification = record.getNotification();
Julia Reynolds54369232018-07-03 10:43:35 -04004920 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004921 return true;
4922 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004923
Julia Reynolds76c096d2017-06-19 08:16:04 -04004924 // muted by listener
4925 final String disableEffects = disableNotificationEffects(record);
4926 if (disableEffects != null) {
4927 ZenLog.traceDisableEffects(record, disableEffects);
4928 return true;
4929 }
4930
4931 // suppressed due to DND
4932 if (record.isIntercepted()) {
4933 return true;
4934 }
4935
4936 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004937 if (record.sbn.isGroup()) {
Julia Reynolds79dfdd62018-04-17 15:36:33 -04004938 if (notification.suppressAlertingDueToGrouping()) {
4939 return true;
4940 }
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004941 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004942
Julia Reynolds65b85cf2017-07-20 09:19:20 -04004943 // Suppressed for being too recently noisy
4944 final String pkg = record.sbn.getPackageName();
4945 if (mUsageStats.isAlertRateLimited(pkg)) {
4946 Slog.e(TAG, "Muting recently noisy " + record.getKey());
4947 return true;
4948 }
4949
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004950 return false;
4951 }
4952
Julia Reynolds0c299d42016-11-15 14:37:04 -05004953 private boolean playSound(final NotificationRecord record, Uri soundUri) {
4954 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
Jean-Michel Triviec2bb182018-03-23 18:04:00 -07004955 // play notifications if there is no user of exclusive audio focus
4956 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
4957 // VIBRATE ringer mode)
4958 if (!mAudioManager.isAudioFocusExclusive()
4959 && (mAudioManager.getStreamVolume(
4960 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05004961 final long identity = Binder.clearCallingIdentity();
4962 try {
4963 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4964 if (player != null) {
4965 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4966 + " with attributes " + record.getAudioAttributes());
4967 player.playAsync(soundUri, record.sbn.getUser(), looping,
4968 record.getAudioAttributes());
4969 return true;
4970 }
4971 } catch (RemoteException e) {
4972 } finally {
4973 Binder.restoreCallingIdentity(identity);
4974 }
4975 }
4976 return false;
4977 }
4978
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004979 private boolean playVibration(final NotificationRecord record, long[] vibration,
4980 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004981 // Escalate privileges so we can use the vibrator even if the
4982 // notifying app does not have the VIBRATE permission.
4983 long identity = Binder.clearCallingIdentity();
4984 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004985 final VibrationEffect effect;
4986 try {
4987 final boolean insistent =
4988 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4989 effect = VibrationEffect.createWaveform(
4990 vibration, insistent ? 0 : -1 /*repeatIndex*/);
4991 } catch (IllegalArgumentException e) {
4992 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4993 Arrays.toString(vibration));
4994 return false;
4995 }
4996 if (delayVibForSound) {
4997 new Thread(() -> {
4998 // delay the vibration by the same amount as the notification sound
4999 final int waitMs = mAudioManager.getFocusRampTimeMs(
5000 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
5001 record.getAudioAttributes());
5002 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
5003 try {
5004 Thread.sleep(waitMs);
5005 } catch (InterruptedException e) { }
Seungho Lee0e97ae62018-10-31 21:49:09 +09005006
5007 // Notifications might be canceled before it actually vibrates due to waitMs,
5008 // so need to check the notification still valide for vibrate.
5009 synchronized (mNotificationLock) {
5010 if (mNotificationsByKey.get(record.getKey()) != null) {
5011 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
5012 effect, record.getAudioAttributes());
5013 } else {
5014 Slog.e(TAG, "No vibration for canceled notification : " + record.getKey());
5015 }
5016 }
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005017 }).start();
5018 } else {
5019 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
5020 effect, record.getAudioAttributes());
5021 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005022 return true;
5023 } finally{
5024 Binder.restoreCallingIdentity(identity);
5025 }
5026 }
5027
Julia Reynolds7c96b582017-05-25 12:35:36 -04005028 private boolean isNotificationForCurrentUser(NotificationRecord record) {
5029 final int currentUser;
5030 final long token = Binder.clearCallingIdentity();
5031 try {
5032 currentUser = ActivityManager.getCurrentUser();
5033 } finally {
5034 Binder.restoreCallingIdentity(token);
5035 }
5036 return (record.getUserId() == UserHandle.USER_ALL ||
5037 record.getUserId() == currentUser ||
5038 mUserProfiles.isCurrentProfile(record.getUserId()));
5039 }
5040
Beverly5d463b62017-07-26 14:13:40 -04005041 protected void playInCallNotification() {
Marta Białka39c992f2011-03-10 10:27:24 +01005042 new Thread() {
5043 @Override
5044 public void run() {
Beverly5d463b62017-07-26 14:13:40 -04005045 final long identity = Binder.clearCallingIdentity();
Marta Białka39c992f2011-03-10 10:27:24 +01005046 try {
Beverly5d463b62017-07-26 14:13:40 -04005047 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5048 if (player != null) {
luochaojiang50e5273c2018-04-16 16:55:03 +08005049 if (mCallNotificationToken != null) {
5050 player.stop(mCallNotificationToken);
5051 }
5052 mCallNotificationToken = new Binder();
5053 player.play(mCallNotificationToken, mInCallNotificationUri,
Beverly5d463b62017-07-26 14:13:40 -04005054 mInCallNotificationAudioAttributes,
5055 mInCallNotificationVolume, false);
Marta Białka39c992f2011-03-10 10:27:24 +01005056 }
Beverly5d463b62017-07-26 14:13:40 -04005057 } catch (RemoteException e) {
5058 } finally {
5059 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01005060 }
5061 }
5062 }.start();
5063 }
5064
Julia Reynolds88860ce2017-06-01 16:55:49 -04005065 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005066 void showNextToastLocked() {
5067 ToastRecord record = mToastQueue.get(0);
5068 while (record != null) {
5069 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
5070 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005071 record.callback.show(record.token);
Robert Carr997427342018-02-28 18:06:10 -08005072 scheduleDurationReachedLocked(record);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005073 return;
5074 } catch (RemoteException e) {
5075 Slog.w(TAG, "Object died trying to show notification " + record.callback
5076 + " in package " + record.pkg);
5077 // remove it from the list and let the process die
5078 int index = mToastQueue.indexOf(record);
5079 if (index >= 0) {
5080 mToastQueue.remove(index);
5081 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005082 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005083 if (mToastQueue.size() > 0) {
5084 record = mToastQueue.get(0);
5085 } else {
5086 record = null;
5087 }
5088 }
5089 }
5090 }
5091
Julia Reynolds88860ce2017-06-01 16:55:49 -04005092 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005093 void cancelToastLocked(int index) {
5094 ToastRecord record = mToastQueue.get(index);
5095 try {
5096 record.callback.hide();
5097 } catch (RemoteException e) {
5098 Slog.w(TAG, "Object died trying to hide notification " + record.callback
5099 + " in package " + record.pkg);
5100 // don't worry about this, we're about to remove it from
5101 // the list anyway
5102 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005103
5104 ToastRecord lastToast = mToastQueue.remove(index);
Robert Carr997427342018-02-28 18:06:10 -08005105
5106 mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
5107 DEFAULT_DISPLAY);
5108 // We passed 'false' for 'removeWindows' so that the client has time to stop
5109 // rendering (as hide above is a one-way message), otherwise we could crash
5110 // a client which was actively using a surface made from the token. However
5111 // we need to schedule a timeout to make sure the token is eventually killed
5112 // one way or another.
5113 scheduleKillTokenTimeout(lastToast.token);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005114
5115 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005116 if (mToastQueue.size() > 0) {
5117 // Show the next one. If the callback fails, this will remove
5118 // it from the list, so don't assume that the list hasn't changed
5119 // after this point.
5120 showNextToastLocked();
5121 }
5122 }
5123
Robert Carr997427342018-02-28 18:06:10 -08005124 void finishTokenLocked(IBinder t) {
5125 mHandler.removeCallbacksAndMessages(t);
5126 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
5127 // remaining surfaces as either the client has called finishToken indicating
5128 // it has successfully removed the views, or the client has timed out
5129 // at which point anything goes.
5130 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */,
5131 DEFAULT_DISPLAY);
5132 }
5133
Julia Reynolds88860ce2017-06-01 16:55:49 -04005134 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08005135 private void scheduleDurationReachedLocked(ToastRecord r)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005136 {
5137 mHandler.removeCallbacksAndMessages(r);
Robert Carr997427342018-02-28 18:06:10 -08005138 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005139 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
5140 mHandler.sendMessageDelayed(m, delay);
5141 }
5142
Robert Carr997427342018-02-28 18:06:10 -08005143 private void handleDurationReached(ToastRecord record)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005144 {
5145 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
5146 synchronized (mToastQueue) {
5147 int index = indexOfToastLocked(record.pkg, record.callback);
5148 if (index >= 0) {
5149 cancelToastLocked(index);
5150 }
5151 }
5152 }
5153
Julia Reynolds88860ce2017-06-01 16:55:49 -04005154 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08005155 private void scheduleKillTokenTimeout(IBinder token)
5156 {
5157 mHandler.removeCallbacksAndMessages(token);
5158 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, token);
Robert Carr3406d462018-03-15 16:19:07 -07005159 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
Robert Carr997427342018-02-28 18:06:10 -08005160 }
5161
5162 private void handleKillTokenTimeout(IBinder token)
5163 {
5164 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + token);
5165 synchronized (mToastQueue) {
5166 finishTokenLocked(token);
5167 }
5168 }
5169
5170 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005171 int indexOfToastLocked(String pkg, ITransientNotification callback)
5172 {
5173 IBinder cbak = callback.asBinder();
5174 ArrayList<ToastRecord> list = mToastQueue;
5175 int len = list.size();
5176 for (int i=0; i<len; i++) {
5177 ToastRecord r = list.get(i);
Beverly Tai98efc792018-06-11 14:50:36 +00005178 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08005179 return i;
5180 }
5181 }
5182 return -1;
5183 }
5184
Julia Reynolds88860ce2017-06-01 16:55:49 -04005185 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005186 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005187 {
5188 int toastCount = 0; // toasts from this pid
5189 ArrayList<ToastRecord> list = mToastQueue;
5190 int N = list.size();
5191 for (int i=0; i<N; i++) {
5192 ToastRecord r = list.get(i);
5193 if (r.pid == pid) {
5194 toastCount++;
5195 }
5196 }
5197 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07005198 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08005199 } catch (RemoteException e) {
5200 // Shouldn't happen.
5201 }
5202 }
5203
Chris Wrenf9536642014-04-17 10:01:54 -04005204 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005205 if (!(message.obj instanceof RankingReconsideration)) return;
5206 RankingReconsideration recon = (RankingReconsideration) message.obj;
5207 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04005208 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005209 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005210 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
5211 if (record == null) {
5212 return;
Chris Wrenf9536642014-04-17 10:01:54 -04005213 }
Chris Wren333a61c2014-05-28 16:40:57 -04005214 int indexBefore = findNotificationRecordIndexLocked(record);
5215 boolean interceptBefore = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005216 float contactAffinityBefore = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005217 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04005218 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04005219 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04005220 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04005221 int indexAfter = findNotificationRecordIndexLocked(record);
5222 boolean interceptAfter = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005223 float contactAffinityAfter = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005224 int visibilityAfter = record.getPackageVisibilityOverride();
5225 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
5226 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005227 if (interceptBefore && !interceptAfter
5228 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
Chris Wrena3446562014-06-03 18:11:47 -04005229 buzzBeepBlinkLocked(record);
5230 }
Chris Wrenf9536642014-04-17 10:01:54 -04005231 }
Chris Wren333a61c2014-05-28 16:40:57 -04005232 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005233 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04005234 }
5235 }
5236
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005237 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04005238 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005239 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04005240 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005241 // Any field that can change via one of the extractors needs to be added here.
5242 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005243 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05005244 boolean[] showBadges = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005245 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
5246 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
5247 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
5248 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Julia Reynolds503ed942017-10-04 16:04:56 -04005249 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005250 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
Chris Wren54bbef42014-07-09 18:37:56 -04005251 for (int i = 0; i < N; i++) {
5252 final NotificationRecord r = mNotificationList.get(i);
5253 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005254 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05005255 showBadges[i] = r.canShowBadge();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005256 channelBefore.add(r.getChannel());
5257 groupKeyBefore.add(r.getGroupKey());
5258 overridePeopleBefore.add(r.getPeopleOverride());
5259 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Julia Reynolds503ed942017-10-04 16:04:56 -04005260 userSentimentBefore.add(r.getUserSentiment());
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005261 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
Chris Wren54bbef42014-07-09 18:37:56 -04005262 mRankingHelper.extractSignals(r);
5263 }
Chris Wren19a02b02015-12-22 10:34:22 -05005264 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04005265 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005266 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005267 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05005268 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005269 || showBadges[i] != r.canShowBadge()
5270 || !Objects.equals(channelBefore.get(i), r.getChannel())
5271 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
5272 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
Julia Reynolds503ed942017-10-04 16:04:56 -04005273 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005274 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
5275 || !Objects.equals(suppressVisuallyBefore.get(i),
5276 r.getSuppressedVisualEffects())) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005277 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04005278 return;
5279 }
5280 }
5281 }
5282 }
5283
Julia Reynolds88860ce2017-06-01 16:55:49 -04005284 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005285 private void recordCallerLocked(NotificationRecord record) {
5286 if (mZenModeHelper.isCall(record)) {
5287 mZenModeHelper.recordCaller(record);
5288 }
5289 }
5290
Christoph Studerd5092bc2014-07-03 17:47:58 +02005291 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04005292 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005293 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02005294 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005295 if (record.isIntercepted()) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05005296 record.setSuppressedVisualEffects(
5297 mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
Julia Reynolds445cfa82017-05-08 15:41:45 -04005298 } else {
5299 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005300 }
Chris Wren333a61c2014-05-28 16:40:57 -04005301 }
5302
Julia Reynolds88860ce2017-06-01 16:55:49 -04005303 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04005304 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04005305 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04005306 }
5307
Chris Wrenf9536642014-04-17 10:01:54 -04005308 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005309 synchronized (mNotificationLock) {
Beverly5a20a5e2018-03-06 15:02:44 -05005310 mListeners.notifyRankingUpdateLocked(null);
Chris Wrenf9536642014-04-17 10:01:54 -04005311 }
5312 }
5313
John Spurlockd8afe3c2014-08-01 14:04:07 -04005314 private void scheduleListenerHintsChanged(int state) {
5315 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
5316 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04005317 }
5318
Christoph Studer85a384b2014-08-27 20:16:15 +02005319 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
5320 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
5321 mHandler.obtainMessage(
5322 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
5323 listenerInterruptionFilter,
5324 0).sendToTarget();
5325 }
5326
John Spurlockd8afe3c2014-08-01 14:04:07 -04005327 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005328 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005329 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005330 }
5331 }
5332
Christoph Studer85a384b2014-08-27 20:16:15 +02005333 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005334 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02005335 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
5336 }
5337 }
5338
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005339 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08005340 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005341 public WorkerHandler(Looper looper) {
5342 super(looper);
5343 }
5344
Adam Lesinski182f73f2013-12-05 16:48:06 -08005345 @Override
5346 public void handleMessage(Message msg)
5347 {
5348 switch (msg.what)
5349 {
Robert Carr997427342018-02-28 18:06:10 -08005350 case MESSAGE_DURATION_REACHED:
5351 handleDurationReached((ToastRecord)msg.obj);
5352 break;
5353 case MESSAGE_FINISH_TOKEN_TIMEOUT:
5354 handleKillTokenTimeout((IBinder)msg.obj);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005355 break;
John Spurlock056c5192014-04-20 21:52:01 -04005356 case MESSAGE_SAVE_POLICY_FILE:
5357 handleSavePolicyFile();
5358 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005359 case MESSAGE_SEND_RANKING_UPDATE:
5360 handleSendRankingUpdate();
5361 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04005362 case MESSAGE_LISTENER_HINTS_CHANGED:
5363 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04005364 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02005365 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
5366 handleListenerInterruptionFilterChanged(msg.arg1);
5367 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005368 }
5369 }
5370
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005371 protected void scheduleSendRankingUpdate() {
5372 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
5373 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
5374 sendMessage(m);
5375 }
5376 }
5377
Chris Wrenf9536642014-04-17 10:01:54 -04005378 }
5379
Chris Wren51017d02015-12-15 15:34:46 -05005380 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04005381 {
Chris Wren51017d02015-12-15 15:34:46 -05005382 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04005383 super(looper);
5384 }
5385
5386 @Override
5387 public void handleMessage(Message msg) {
5388 switch (msg.what) {
5389 case MESSAGE_RECONSIDER_RANKING:
5390 handleRankingReconsideration(msg);
5391 break;
Chris Wren51017d02015-12-15 15:34:46 -05005392 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005393 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04005394 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08005395 }
5396 }
Chris Wren51017d02015-12-15 15:34:46 -05005397
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005398 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05005399 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05005400 Message msg = Message.obtain();
5401 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05005402 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05005403 }
5404
5405 public void requestReconsideration(RankingReconsideration recon) {
5406 Message m = Message.obtain(this,
5407 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
5408 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
5409 sendMessageDelayed(m, delay);
5410 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08005411 }
5412
Adam Lesinski182f73f2013-12-05 16:48:06 -08005413 // Notifications
5414 // ============================================================================
5415 static int clamp(int x, int low, int high) {
5416 return (x < low) ? low : ((x > high) ? high : x);
5417 }
5418
5419 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
Eugene Suslad4128ec2017-12-04 19:48:41 +00005420 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07005421 return;
5422 }
5423
5424 AccessibilityEvent event =
5425 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
5426 event.setPackageName(packageName);
5427 event.setClassName(Notification.class.getName());
5428 event.setParcelableData(notification);
5429 CharSequence tickerText = notification.tickerText;
5430 if (!TextUtils.isEmpty(tickerText)) {
5431 event.getText().add(tickerText);
5432 }
5433
Julia Reynolds94187562017-10-10 13:58:49 -04005434 mAccessibilityManager.sendAccessibilityEvent(event);
svetoslavganov75986cf2009-05-14 22:28:01 -07005435 }
5436
Julia Reynolds0839c022017-06-15 15:24:01 -04005437 /**
5438 * Removes all NotificationsRecords with the same key as the given notification record
5439 * from both lists. Do not call this method while iterating over either list.
5440 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005441 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04005442 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
5443 // Remove from both lists, either list could have a separate Record for what is
5444 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005445 boolean wasPosted = false;
5446 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04005447 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
5448 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005449 mNotificationList.remove(recordInList);
5450 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005451 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005452 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005453 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005454 != null) {
5455 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005456 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005457 return wasPosted;
5458 }
5459
5460 @GuardedBy("mNotificationLock")
5461 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04005462 boolean wasPosted, String listenerName) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005463 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName);
5464 }
5465
5466 @GuardedBy("mNotificationLock")
5467 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
5468 int rank, int count, boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04005469 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005470
5471 // Record caller.
5472 recordCallerLocked(r);
5473
Julia Reynolds503ed942017-10-04 16:04:56 -04005474 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
5475 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
5476 }
5477
Joe Onorato46439ce2010-11-19 13:56:21 -08005478 // tell the app
5479 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005480 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08005481 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005482 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08005483 } catch (PendingIntent.CanceledException ex) {
5484 // do nothing - there's no relevant way to recover, and
5485 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04005486 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08005487 }
5488 }
5489 }
5490
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005491 // Only cancel these if this notification actually got to be posted.
5492 if (wasPosted) {
5493 // status bar
5494 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005495 if (reason != REASON_SNOOZED) {
5496 r.isCanceled = true;
5497 }
Beverly5a20a5e2018-03-06 15:02:44 -05005498 mListeners.notifyRemovedLocked(r, reason, r.getStats());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005499 mHandler.post(new Runnable() {
5500 @Override
5501 public void run() {
5502 mGroupHelper.onNotificationRemoved(r.sbn);
5503 }
5504 });
5505 }
5506
5507 // sound
5508 if (canceledKey.equals(mSoundNotificationKey)) {
5509 mSoundNotificationKey = null;
5510 final long identity = Binder.clearCallingIdentity();
5511 try {
5512 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5513 if (player != null) {
5514 player.stopAsync();
5515 }
5516 } catch (RemoteException e) {
5517 } finally {
5518 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04005519 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005521
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005522 // vibrate
5523 if (canceledKey.equals(mVibrateNotificationKey)) {
5524 mVibrateNotificationKey = null;
5525 long identity = Binder.clearCallingIdentity();
5526 try {
5527 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005528 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005529 finally {
5530 Binder.restoreCallingIdentity(identity);
5531 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005532 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005533
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005534 // light
5535 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005536 }
5537
Christoph Studer546bec82014-03-14 12:17:12 +01005538 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04005539 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01005540 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005541 case REASON_CANCEL:
5542 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005543 case REASON_LISTENER_CANCEL:
5544 case REASON_LISTENER_CANCEL_ALL:
5545 mUsageStats.registerDismissedByUser(r);
5546 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05005547 case REASON_APP_CANCEL:
5548 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005549 mUsageStats.registerRemovedByApp(r);
5550 break;
Christoph Studer546bec82014-03-14 12:17:12 +01005551 }
5552
Christoph Studer265c1052014-07-23 17:14:33 +02005553 String groupKey = r.getGroupKey();
5554 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005555 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02005556 mSummaryByGroupKey.remove(groupKey);
5557 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04005558 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
5559 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
5560 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04005561 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005562
Daniel Sandler23d7c702013-03-07 16:32:06 -05005563 // Save it for users of getHistoricalNotifications()
5564 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02005565
Chris Wren6650e572015-05-15 17:19:25 -04005566 final long now = System.currentTimeMillis();
Dieter Hsud39f0d52018-04-14 02:08:30 +08005567 final LogMaker logMaker = r.getLogMaker(now)
Chris Wren9eb5e102017-01-26 13:15:06 -05005568 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
5569 .setType(MetricsEvent.TYPE_DISMISS)
Dieter Hsud39f0d52018-04-14 02:08:30 +08005570 .setSubtype(reason);
5571 if (rank != -1 && count != -1) {
5572 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
5573 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
5574 }
5575 MetricsLogger.action(logMaker);
Chris Wrene6ddb8a2015-05-27 15:21:00 -04005576 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Dieter Hsud39f0d52018-04-14 02:08:30 +08005577 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
5578 rank, count, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005579 }
5580
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005581 @VisibleForTesting
5582 void updateUriPermissions(@Nullable NotificationRecord newRecord,
5583 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) {
5584 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey();
5585 if (DBG) Slog.d(TAG, key + ": updating permissions");
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005586
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005587 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null;
5588 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null;
5589
5590 // Shortcut when no Uris involved
5591 if (newUris == null && oldUris == null) {
5592 return;
5593 }
5594
5595 // Inherit any existing owner
5596 IBinder permissionOwner = null;
5597 if (newRecord != null && permissionOwner == null) {
5598 permissionOwner = newRecord.permissionOwner;
5599 }
5600 if (oldRecord != null && permissionOwner == null) {
5601 permissionOwner = oldRecord.permissionOwner;
5602 }
5603
5604 // If we have Uris to grant, but no owner yet, go create one
5605 if (newUris != null && permissionOwner == null) {
5606 try {
5607 if (DBG) Slog.d(TAG, key + ": creating owner");
5608 permissionOwner = mAm.newUriPermissionOwner("NOTIF:" + key);
5609 } catch (RemoteException ignored) {
5610 // Ignored because we're in same process
5611 }
5612 }
5613
5614 // If we have no Uris to grant, but an existing owner, go destroy it
5615 if (newUris == null && permissionOwner != null) {
5616 final long ident = Binder.clearCallingIdentity();
5617 try {
5618 if (DBG) Slog.d(TAG, key + ": destroying owner");
5619 mAm.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
5620 UserHandle.getUserId(oldRecord.getUid()));
5621 permissionOwner = null;
5622 } catch (RemoteException ignored) {
5623 // Ignored because we're in same process
5624 } finally {
5625 Binder.restoreCallingIdentity(ident);
5626 }
5627 }
5628
5629 // Grant access to new Uris
5630 if (newUris != null && permissionOwner != null) {
5631 for (int i = 0; i < newUris.size(); i++) {
5632 final Uri uri = newUris.valueAt(i);
5633 if (oldUris == null || !oldUris.contains(uri)) {
5634 if (DBG) Slog.d(TAG, key + ": granting " + uri);
5635 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
5636 targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005637 }
5638 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005639 }
5640
5641 // Revoke access to old Uris
5642 if (oldUris != null && permissionOwner != null) {
5643 for (int i = 0; i < oldUris.size(); i++) {
5644 final Uri uri = oldUris.valueAt(i);
5645 if (newUris == null || !newUris.contains(uri)) {
5646 if (DBG) Slog.d(TAG, key + ": revoking " + uri);
5647 revokeUriPermission(permissionOwner, uri, oldRecord.getUid());
5648 }
5649 }
5650 }
5651
5652 if (newRecord != null) {
5653 newRecord.permissionOwner = permissionOwner;
5654 }
5655 }
5656
5657 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg,
5658 int targetUserId) {
5659 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5660
5661 final long ident = Binder.clearCallingIdentity();
5662 try {
5663 mAm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
5664 ContentProvider.getUriWithoutUserId(uri),
5665 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5666 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
5667 targetUserId);
5668 } catch (RemoteException ignored) {
5669 // Ignored because we're in same process
5670 } finally {
5671 Binder.restoreCallingIdentity(ident);
5672 }
5673 }
5674
5675 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUid) {
5676 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5677
5678 final long ident = Binder.clearCallingIdentity();
5679 try {
5680 mAm.revokeUriPermissionFromOwner(owner,
5681 ContentProvider.getUriWithoutUserId(uri),
5682 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5683 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
5684 } catch (RemoteException ignored) {
5685 // Ignored because we're in same process
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005686 } finally {
5687 Binder.restoreCallingIdentity(ident);
5688 }
5689 }
5690
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005691 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07005692 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005693 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005694 */
John Spurlocke6a7d932014-03-13 12:29:00 -04005695 void cancelNotification(final int callingUid, final int callingPid,
5696 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005697 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04005698 final int userId, final int reason, final ManagedServiceInfo listener) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005699 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
5700 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
5701 }
5702
5703 /**
5704 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
5705 * and none of the {@code mustNotHaveFlags}.
5706 */
5707 void cancelNotification(final int callingUid, final int callingPid,
5708 final String pkg, final String tag, final int id,
5709 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
5710 final int userId, final int reason, int rank, int count, final ManagedServiceInfo listener) {
Beverly5a20a5e2018-03-06 15:02:44 -05005711
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005712 // In enqueueNotificationInternal notifications are added by scheduling the
5713 // work on the worker handler. Hence, we also schedule the cancel on this
5714 // handler to avoid a scenario where an add notification call followed by a
5715 // remove notification call ends up in not removing the notification.
5716 mHandler.post(new Runnable() {
5717 @Override
5718 public void run() {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005719 String listenerName = listener == null ? null : listener.component.toShortString();
Chris Wrenbddb5bc2015-03-04 08:47:46 -08005720 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
5721 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005722
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005723 synchronized (mNotificationLock) {
5724 // Look for the notification, searching both the posted and enqueued lists.
5725 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
5726 if (r != null) {
5727 // The notification was found, check if it should be removed.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005728
Christoph Studer546bec82014-03-14 12:17:12 +01005729 // Ideally we'd do this in the caller of this method. However, that would
5730 // require the caller to also find the notification.
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005731 if (reason == REASON_CLICK) {
Christoph Studer546bec82014-03-14 12:17:12 +01005732 mUsageStats.registerClickedByUser(r);
5733 }
5734
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005735 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
5736 return;
5737 }
5738 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
5739 return;
5740 }
5741
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005742 // Cancel the notification.
Julia Reynolds0839c022017-06-15 15:24:01 -04005743 boolean wasPosted = removeFromNotificationListsLocked(r);
Dieter Hsud39f0d52018-04-14 02:08:30 +08005744 cancelNotificationLocked(r, sendDelete, reason, rank, count, wasPosted, listenerName);
Christoph Studer265c1052014-07-23 17:14:33 +02005745 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005746 sendDelete, null);
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005747 updateLightsLocked();
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005748 } else {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005749 // No notification was found, assume that it is snoozed and cancel it.
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005750 if (reason != REASON_SNOOZED) {
5751 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
5752 if (wasSnoozed) {
5753 savePolicyFile();
5754 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005755 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005756 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005757 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005758 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005759 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005760 }
5761
5762 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07005763 * Determine whether the userId applies to the notification in question, either because
5764 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
5765 */
5766 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
5767 return
5768 // looking for USER_ALL notifications? match everything
5769 userId == UserHandle.USER_ALL
5770 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005771 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07005772 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005773 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07005774 }
5775
5776 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005777 * Determine whether the userId applies to the notification in question, either because
5778 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01005779 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005780 */
Kenny Guy2a764942014-04-02 13:29:20 +01005781 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00005782 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04005783 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005784 }
5785
5786 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05005787 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005788 * {@code mustHaveFlags}.
5789 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005790 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005791 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005792 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005793 mHandler.post(new Runnable() {
5794 @Override
5795 public void run() {
5796 String listenerName = listener == null ? null : listener.component.toShortString();
5797 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5798 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
5799 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005800
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005801 // Why does this parameter exist? Do we actually want to execute the above if doit
5802 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005803 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005804 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005805 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005806
5807 synchronized (mNotificationLock) {
5808 FlagChecker flagChecker = (int flags) -> {
5809 if ((flags & mustHaveFlags) != mustHaveFlags) {
5810 return false;
5811 }
5812 if ((flags & mustNotHaveFlags) != 0) {
5813 return false;
5814 }
5815 return true;
5816 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005817 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5818 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
5819 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005820 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005821 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5822 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
5823 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005824 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005825 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005826 }
5827 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005828 });
5829 }
5830
5831 private interface FlagChecker {
5832 // Returns false if these flags do not pass the defined flag test.
5833 public boolean apply(int flags);
5834 }
5835
Julia Reynolds88860ce2017-06-01 16:55:49 -04005836 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005837 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
5838 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
5839 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005840 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005841 ArrayList<NotificationRecord> canceledNotifications = null;
5842 for (int i = notificationList.size() - 1; i >= 0; --i) {
5843 NotificationRecord r = notificationList.get(i);
5844 if (includeCurrentProfiles) {
5845 if (!notificationMatchesCurrentProfiles(r, userId)) {
5846 continue;
5847 }
5848 } else if (!notificationMatchesUserId(r, userId)) {
5849 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005850 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005851 // Don't remove notifications to all, if there's no package name specified
5852 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
5853 continue;
5854 }
5855 if (!flagChecker.apply(r.getFlags())) {
5856 continue;
5857 }
5858 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
5859 continue;
5860 }
5861 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
5862 continue;
5863 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005864 if (canceledNotifications == null) {
5865 canceledNotifications = new ArrayList<>();
5866 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005867 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005868 mNotificationsByKey.remove(r.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005869 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04005870 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005871 }
5872 if (canceledNotifications != null) {
5873 final int M = canceledNotifications.size();
5874 for (int i = 0; i < M; i++) {
5875 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005876 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005877 }
5878 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005879 }
5880 }
5881
Julia Reynolds50989772017-02-23 14:32:16 -05005882 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005883 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05005884 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005885 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05005886 return;
5887 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05005888
Julia Reynolds79672302017-01-12 08:30:16 -05005889 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05005890 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
5891 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05005892 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005893 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005894 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005895 }
5896
5897 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
5898 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005899 if (DBG) {
5900 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
5901 }
Julia Reynolds79672302017-01-12 08:30:16 -05005902 mSnoozeHelper.repost(key);
5903 savePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005904 }
5905
Julia Reynolds88860ce2017-06-01 16:55:49 -04005906 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07005907 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005908 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005909 mHandler.post(new Runnable() {
5910 @Override
5911 public void run() {
5912 synchronized (mNotificationLock) {
5913 String listenerName =
5914 listener == null ? null : listener.component.toShortString();
5915 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5916 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01005917
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005918 FlagChecker flagChecker = (int flags) -> {
5919 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
5920 != 0) {
5921 return false;
5922 }
5923 return true;
5924 };
5925
5926 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5927 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
5928 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005929 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005930 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5931 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
5932 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04005933 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005934 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00005935 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005936 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005937 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005938 }
5939
Christoph Studere4ef156b2014-07-04 18:41:57 +02005940 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04005941 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02005942 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005943 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005944 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02005945 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005946 return;
5947 }
5948
5949 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02005950
5951 if (pkg == null) {
5952 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
5953 return;
5954 }
5955
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005956 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005957 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005958 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005959 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005960 }
5961
Julia Reynolds88860ce2017-06-01 16:55:49 -04005962 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005963 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
5964 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005965 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005966 final String pkg = parentNotification.sbn.getPackageName();
5967 final int userId = parentNotification.getUserId();
5968 final int reason = REASON_GROUP_SUMMARY_CANCELED;
5969 for (int i = notificationList.size() - 1; i >= 0; i--) {
5970 final NotificationRecord childR = notificationList.get(i);
5971 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04005972 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005973 childR.getGroupKey().equals(parentNotification.getGroupKey())
Julia Reynoldse5c60452018-04-30 14:41:36 -04005974 && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
Beverly40239d92017-07-07 10:20:41 -04005975 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02005976 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
5977 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04005978 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005979 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04005980 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005981 }
5982 }
5983 }
5984
Julia Reynolds88860ce2017-06-01 16:55:49 -04005985 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005986 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005987 {
The Android Open Source Project10592532009-03-18 17:39:46 -07005988 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05005989 NotificationRecord ledNotification = null;
5990 while (ledNotification == null && !mLights.isEmpty()) {
5991 final String owner = mLights.get(mLights.size() - 1);
5992 ledNotification = mNotificationsByKey.get(owner);
5993 if (ledNotification == null) {
5994 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
5995 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005996 }
5997 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005998
Mike Lockwood63b5ad92011-08-30 09:55:30 -04005999 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05006000 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05006001 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07006002 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006003 NotificationRecord.Light light = ledNotification.getLight();
6004 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05006005 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006006 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
6007 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05006008 }
The Android Open Source Project10592532009-03-18 17:39:46 -07006009 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006010 }
6011
Julia Reynolds88860ce2017-06-01 16:55:49 -04006012 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006013 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
6014 String groupKey, int userId) {
6015 List<NotificationRecord> records = new ArrayList<>();
6016 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
6017 records.addAll(
6018 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
6019 return records;
6020 }
6021
6022
Julia Reynolds88860ce2017-06-01 16:55:49 -04006023 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006024 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
6025 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
6026 List<NotificationRecord> records = new ArrayList<>();
6027 final int len = list.size();
6028 for (int i = 0; i < len; i++) {
6029 NotificationRecord r = list.get(i);
6030 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
6031 && r.sbn.getPackageName().equals(pkg)) {
6032 records.add(r);
6033 }
6034 }
6035 return records;
6036 }
6037
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006038 // Searches both enqueued and posted notifications by key.
6039 // TODO: need to combine a bunch of these getters with slightly different behavior.
6040 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04006041 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006042 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006043 NotificationRecord r;
6044 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
6045 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006046 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006047 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
6048 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006049 }
6050 return null;
6051 }
6052
Julia Reynolds88860ce2017-06-01 16:55:49 -04006053 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006054 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006055 NotificationRecord r;
6056 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
6057 return r;
6058 }
6059 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
6060 != null) {
6061 return r;
6062 }
6063 return null;
6064 }
6065
Julia Reynolds88860ce2017-06-01 16:55:49 -04006066 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006067 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006068 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006069 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006070 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006071 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01006072 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
6073 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006074 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006075 }
6076 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006077 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006078 }
6079
Julia Reynolds88860ce2017-06-01 16:55:49 -04006080 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006081 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04006082 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006083 final int N = list.size();
6084 for (int i = 0; i < N; i++) {
6085 if (key.equals(list.get(i).getKey())) {
6086 return list.get(i);
6087 }
6088 }
6089 return null;
6090 }
6091
Julia Reynolds88860ce2017-06-01 16:55:49 -04006092 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02006093 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02006094 final int N = mNotificationList.size();
6095 for (int i = 0; i < N; i++) {
6096 if (key.equals(mNotificationList.get(i).getKey())) {
6097 return i;
6098 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02006099 }
Christoph Studerc5115552014-06-12 20:22:31 +02006100 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02006101 }
6102
Beverly5a20a5e2018-03-06 15:02:44 -05006103 @VisibleForTesting
6104 protected void hideNotificationsForPackages(String[] pkgs) {
6105 synchronized (mNotificationLock) {
6106 List<String> pkgList = Arrays.asList(pkgs);
6107 List<NotificationRecord> changedNotifications = new ArrayList<>();
6108 int numNotifications = mNotificationList.size();
6109 for (int i = 0; i < numNotifications; i++) {
6110 NotificationRecord rec = mNotificationList.get(i);
6111 if (pkgList.contains(rec.sbn.getPackageName())) {
6112 rec.setHidden(true);
6113 changedNotifications.add(rec);
6114 }
6115 }
6116
6117 mListeners.notifyHiddenLocked(changedNotifications);
6118 }
6119 }
6120
6121 @VisibleForTesting
6122 protected void unhideNotificationsForPackages(String[] pkgs) {
6123 synchronized (mNotificationLock) {
6124 List<String> pkgList = Arrays.asList(pkgs);
6125 List<NotificationRecord> changedNotifications = new ArrayList<>();
6126 int numNotifications = mNotificationList.size();
6127 for (int i = 0; i < numNotifications; i++) {
6128 NotificationRecord rec = mNotificationList.get(i);
6129 if (pkgList.contains(rec.sbn.getPackageName())) {
6130 rec.setHidden(false);
6131 changedNotifications.add(rec);
6132 }
6133 }
6134
6135 mListeners.notifyUnhiddenLocked(changedNotifications);
6136 }
6137 }
6138
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006139 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006140 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006141 updateLightsLocked();
6142 }
6143 }
John Spurlocke677d712014-02-13 12:52:19 -05006144
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006145 protected boolean isCallingUidSystem() {
6146 final int uid = Binder.getCallingUid();
6147 return uid == Process.SYSTEM_UID;
6148 }
6149
6150 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04006151 final int appid = UserHandle.getAppId(uid);
6152 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
6153 }
John Spurlockb408e8e2014-04-23 21:12:45 -04006154
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006155 // TODO: Most calls should probably move to isCallerSystem.
6156 protected boolean isCallerSystemOrPhone() {
6157 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04006158 }
6159
Julia Reynoldsb852e562017-06-06 16:14:18 -04006160 private void checkCallerIsSystemOrShell() {
6161 if (Binder.getCallingUid() == Process.SHELL_UID) {
6162 return;
6163 }
6164 checkCallerIsSystem();
6165 }
6166
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006167 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006168 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006169 return;
6170 }
6171 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
6172 }
6173
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006174 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006175 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006176 return;
6177 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04006178 checkCallerIsSameApp(pkg);
6179 }
6180
Chad Brubaker6b68f102017-01-27 13:39:00 -08006181 private boolean isCallerInstantApp(String pkg) {
6182 // System is always allowed to act for ephemeral apps.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006183 if (isCallerSystemOrPhone()) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08006184 return false;
6185 }
6186
6187 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
6188
6189 try {
6190 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
6191 UserHandle.getCallingUserId());
6192 if (ai == null) {
6193 throw new SecurityException("Unknown package " + pkg);
6194 }
6195 return ai.isInstantApp();
6196 } catch (RemoteException re) {
6197 throw new SecurityException("Unknown package " + pkg, re);
6198 }
6199
6200 }
6201
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006202 private void checkCallerIsSameApp(String pkg) {
John Spurlock7340fc82014-04-24 18:50:12 -04006203 final int uid = Binder.getCallingUid();
6204 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006205 ApplicationInfo ai = mPackageManager.getApplicationInfo(
John Spurlock7340fc82014-04-24 18:50:12 -04006206 pkg, 0, UserHandle.getCallingUserId());
Dan Sandler09afc2e2014-07-18 14:29:20 -04006207 if (ai == null) {
6208 throw new SecurityException("Unknown package " + pkg);
6209 }
John Spurlock7340fc82014-04-24 18:50:12 -04006210 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006211 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04006212 + pkg + " which is owned by uid " + ai.uid);
6213 }
6214 } catch (RemoteException re) {
6215 throw new SecurityException("Unknown package " + pkg + "\n" + re);
6216 }
6217 }
6218
John Spurlock32fe4c62014-10-02 12:16:02 -04006219 private static String callStateToString(int state) {
6220 switch (state) {
6221 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
6222 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
6223 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
6224 default: return "CALL_STATE_UNKNOWN_" + state;
6225 }
6226 }
6227
6228 private void listenForCallState() {
6229 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
6230 @Override
6231 public void onCallStateChanged(int state, String incomingNumber) {
6232 if (mCallState == state) return;
6233 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
6234 mCallState = state;
6235 }
6236 }, PhoneStateListener.LISTEN_CALL_STATE);
6237 }
6238
Christoph Studer05ad4822014-05-16 14:16:03 +02006239 /**
6240 * Generates a NotificationRankingUpdate from 'sbns', considering only
6241 * notifications visible to the given listener.
6242 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006243 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04006244 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04006245 final int N = mNotificationList.size();
6246 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02006247 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05006248 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04006249 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006250 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006251 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05006252 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006253 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05006254 Bundle overridePeople = new Bundle();
6255 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006256 Bundle showBadge = new Bundle();
Julia Reynolds503ed942017-10-04 16:04:56 -04006257 Bundle userSentiment = new Bundle();
Beverly5a20a5e2018-03-06 15:02:44 -05006258 Bundle hidden = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04006259 for (int i = 0; i < N; i++) {
6260 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02006261 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006262 continue;
6263 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006264 final String key = record.sbn.getKey();
6265 keys.add(key);
6266 importance.add(record.getImportance());
6267 if (record.getImportanceExplanation() != null) {
6268 explanation.putCharSequence(key, record.getImportanceExplanation());
6269 }
Chris Wren333a61c2014-05-28 16:40:57 -04006270 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006271 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006272
Christoph Studer05ad4822014-05-16 14:16:03 +02006273 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006274 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006275 if (record.getPackageVisibilityOverride()
6276 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006277 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006278 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04006279 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05006280 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05006281 overridePeople.putStringArrayList(key, record.getPeopleOverride());
6282 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05006283 showBadge.putBoolean(key, record.canShowBadge());
Julia Reynolds503ed942017-10-04 16:04:56 -04006284 userSentiment.putInt(key, record.getUserSentiment());
Beverly5a20a5e2018-03-06 15:02:44 -05006285 hidden.putBoolean(key, record.isHidden());
Christoph Studer05ad4822014-05-16 14:16:03 +02006286 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006287 final int M = keys.size();
6288 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02006289 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05006290 int[] importanceAr = new int[M];
6291 for (int i = 0; i < M; i++) {
6292 importanceAr[i] = importance.get(i);
6293 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006294 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05006295 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Beverly5a20a5e2018-03-06 15:02:44 -05006296 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden);
Christoph Studer05ad4822014-05-16 14:16:03 +02006297 }
6298
Julia Reynoldsda781472017-04-12 09:41:16 -04006299 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006300 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04006301 mCompanionManager = getCompanionManager();
6302 }
6303 // Companion mgr doesn't exist on all device types
6304 if (mCompanionManager == null) {
6305 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006306 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006307 long identity = Binder.clearCallingIdentity();
6308 try {
6309 List<String> associations = mCompanionManager.getAssociations(
6310 info.component.getPackageName(), info.userid);
6311 if (!ArrayUtils.isEmpty(associations)) {
6312 return true;
6313 }
6314 } catch (SecurityException se) {
6315 // Not a privileged listener
6316 } catch (RemoteException re) {
6317 Slog.e(TAG, "Cannot reach companion device service", re);
6318 } catch (Exception e) {
6319 Slog.e(TAG, "Cannot verify listener " + info, e);
6320 } finally {
6321 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006322 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006323 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006324 }
6325
Julia Reynolds727a7282017-04-13 10:54:01 -04006326 protected ICompanionDeviceManager getCompanionManager() {
6327 return ICompanionDeviceManager.Stub.asInterface(
6328 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
6329 }
6330
Christoph Studercef37cf2014-07-25 14:18:17 +02006331 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
6332 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
6333 return false;
6334 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07006335 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02006336 return true;
6337 }
6338
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00006339 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Beverly2be7a052018-03-27 11:37:58 -04006340 final long identity = Binder.clearCallingIdentity();
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006341 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006342 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006343 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006344 } catch (RemoteException re) {
6345 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00006346 } catch (IllegalArgumentException ex) {
6347 // Package not found.
6348 return false;
Beverly2be7a052018-03-27 11:37:58 -04006349 } finally {
6350 Binder.restoreCallingIdentity(identity);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006351 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006352 }
6353
Kristian Monsen30f59b22018-04-09 10:27:16 +02006354 @VisibleForTesting
6355 boolean canUseManagedServices(String pkg) {
6356 boolean canUseManagedServices = !mActivityManager.isLowRamDevice()
Julia Reynoldse1816412017-10-24 10:39:11 -04006357 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
Kristian Monsen30f59b22018-04-09 10:27:16 +02006358
6359 for (String whitelisted : getContext().getResources().getStringArray(
6360 R.array.config_allowedManagedServicesOnLowRamDevices)) {
6361 if (whitelisted.equals(pkg)) {
6362 canUseManagedServices = true;
6363 }
6364 }
6365
6366 return canUseManagedServices;
Julia Reynoldse1816412017-10-24 10:39:11 -04006367 }
6368
Chris Wren47633422016-01-22 09:56:59 -05006369 private class TrimCache {
6370 StatusBarNotification heavy;
6371 StatusBarNotification sbnClone;
6372 StatusBarNotification sbnCloneLight;
6373
6374 TrimCache(StatusBarNotification sbn) {
6375 heavy = sbn;
6376 }
6377
6378 StatusBarNotification ForListener(ManagedServiceInfo info) {
6379 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
6380 if (sbnCloneLight == null) {
6381 sbnCloneLight = heavy.cloneLight();
6382 }
6383 return sbnCloneLight;
6384 } else {
6385 if (sbnClone == null) {
6386 sbnClone = heavy.clone();
6387 }
6388 return sbnClone;
6389 }
6390 }
6391 }
6392
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006393 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006394 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05006395
Julia Reynolds7380d872018-01-12 10:28:26 -05006396 public NotificationAssistants(Context context, Object lock, UserProfiles up,
6397 IPackageManager pm) {
6398 super(context, lock, up, pm);
Chris Wren51017d02015-12-15 15:34:46 -05006399 }
6400
6401 @Override
6402 protected Config getConfig() {
6403 Config c = new Config();
Julia Reynolds503ed942017-10-04 16:04:56 -04006404 c.caption = "notification assistant";
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006405 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006406 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006407 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
6408 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05006409 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006410 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05006411 return c;
6412 }
6413
6414 @Override
6415 protected IInterface asInterface(IBinder binder) {
6416 return INotificationListener.Stub.asInterface(binder);
6417 }
6418
6419 @Override
6420 protected boolean checkType(IInterface service) {
6421 return service instanceof INotificationListener;
6422 }
6423
6424 @Override
6425 protected void onServiceAdded(ManagedServiceInfo info) {
6426 mListeners.registerGuestService(info);
6427 }
6428
6429 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006430 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05006431 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
6432 mListeners.unregisterService(removed.service, removed.userid);
6433 }
Chris Wren47633422016-01-22 09:56:59 -05006434
Julia Reynoldsef934fd2018-02-01 14:39:17 -05006435 @Override
6436 public void onUserUnlocked(int user) {
6437 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
6438 rebindServices(true);
6439 }
6440
Chris Wren47633422016-01-22 09:56:59 -05006441 public void onNotificationEnqueued(final NotificationRecord r) {
6442 final StatusBarNotification sbn = r.sbn;
6443 TrimCache trimCache = new TrimCache(sbn);
6444
Chris Wren47633422016-01-22 09:56:59 -05006445 // There should be only one, but it's a list, so while we enforce
6446 // singularity elsewhere, we keep it general here, to avoid surprises.
Julia Reynolds00314d92017-04-14 10:01:24 -04006447 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
Chris Wren47633422016-01-22 09:56:59 -05006448 boolean sbnVisible = isVisibleToListener(sbn, info);
6449 if (!sbnVisible) {
6450 continue;
6451 }
6452
Chris Wren47633422016-01-22 09:56:59 -05006453 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006454 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05006455 @Override
6456 public void run() {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006457 notifyEnqueued(info, sbnToPost);
Chris Wren47633422016-01-22 09:56:59 -05006458 }
6459 });
6460 }
6461 }
6462
6463 private void notifyEnqueued(final ManagedServiceInfo info,
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006464 final StatusBarNotification sbn) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006465 final INotificationListener assistant = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05006466 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6467 try {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006468 assistant.onNotificationEnqueued(sbnHolder);
Chris Wren47633422016-01-22 09:56:59 -05006469 } catch (RemoteException ex) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006470 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Chris Wren47633422016-01-22 09:56:59 -05006471 }
6472 }
6473
Julia Reynolds79672302017-01-12 08:30:16 -05006474 /**
6475 * asynchronously notify the assistant that a notification has been snoozed until a
6476 * context
6477 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006478 @GuardedBy("mNotificationLock")
Julia Reynolds79672302017-01-12 08:30:16 -05006479 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
6480 final String snoozeCriterionId) {
6481 TrimCache trimCache = new TrimCache(sbn);
Julia Reynolds00314d92017-04-14 10:01:24 -04006482 for (final ManagedServiceInfo info : getServices()) {
Julia Reynolds503ed942017-10-04 16:04:56 -04006483 boolean sbnVisible = isVisibleToListener(sbn, info);
6484 if (!sbnVisible) {
6485 continue;
6486 }
Julia Reynolds79672302017-01-12 08:30:16 -05006487 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
6488 mHandler.post(new Runnable() {
6489 @Override
6490 public void run() {
6491 final INotificationListener assistant =
6492 (INotificationListener) info.service;
6493 StatusBarNotificationHolder sbnHolder
6494 = new StatusBarNotificationHolder(sbnToPost);
6495 try {
6496 assistant.onNotificationSnoozedUntilContext(
6497 sbnHolder, snoozeCriterionId);
6498 } catch (RemoteException ex) {
6499 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
6500 }
6501 }
6502 });
6503 }
6504 }
6505
Chris Wren47633422016-01-22 09:56:59 -05006506 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04006507 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05006508 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006509
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04006510 protected void ensureAssistant() {
6511 final List<UserInfo> activeUsers = mUm.getUsers(true);
6512 for (UserInfo userInfo : activeUsers) {
6513 int userId = userInfo.getUserHandle().getIdentifier();
6514 if (getAllowedPackages(userId).isEmpty()) {
6515 Slog.d(TAG, "Approving default notification assistant for user " + userId);
6516 readDefaultAssistant(userId);
6517 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006518 }
6519 }
Chris Wren51017d02015-12-15 15:34:46 -05006520 }
6521
John Spurlock7340fc82014-04-24 18:50:12 -04006522 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006523 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04006524
Christoph Studerb82bc782014-08-20 14:29:43 +02006525 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
6526
Julia Reynoldsb852e562017-06-06 16:14:18 -04006527 public NotificationListeners(IPackageManager pm) {
6528 super(getContext(), mNotificationLock, mUserProfiles, pm);
6529
John Spurlock7340fc82014-04-24 18:50:12 -04006530 }
6531
6532 @Override
Amith Yamasanie1fb58d2018-09-05 18:52:35 -07006533 protected int getBindFlags() {
6534 // Most of the same flags as the base, but also add BIND_ADJUST_BELOW_PERCEPTIBLE
6535 // because too many 3P apps could be kept in memory as notification listeners and
6536 // cause extreme memory pressure.
6537 // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation.
6538 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
6539 | BIND_ADJUST_BELOW_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
6540 }
6541
6542 @Override
John Spurlock7340fc82014-04-24 18:50:12 -04006543 protected Config getConfig() {
6544 Config c = new Config();
6545 c.caption = "notification listener";
6546 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006547 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04006548 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
6549 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
6550 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
6551 c.clientLabel = R.string.notification_listener_binding_label;
6552 return c;
6553 }
6554
6555 @Override
6556 protected IInterface asInterface(IBinder binder) {
6557 return INotificationListener.Stub.asInterface(binder);
6558 }
6559
6560 @Override
Chris Wren51017d02015-12-15 15:34:46 -05006561 protected boolean checkType(IInterface service) {
6562 return service instanceof INotificationListener;
6563 }
6564
6565 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04006566 public void onServiceAdded(ManagedServiceInfo info) {
6567 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04006568 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006569 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04006570 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006571 }
John Spurlock7340fc82014-04-24 18:50:12 -04006572 try {
Chris Wren333a61c2014-05-28 16:40:57 -04006573 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04006574 } catch (RemoteException e) {
6575 // we tried
6576 }
6577 }
6578
John Spurlock1fa865f2014-07-21 14:56:39 -04006579 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006580 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04006581 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07006582 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006583 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01006584 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04006585 }
Christoph Studerb82bc782014-08-20 14:29:43 +02006586 mLightTrimListeners.remove(removed);
6587 }
6588
Julia Reynolds88860ce2017-06-01 16:55:49 -04006589 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02006590 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
6591 if (trim == TRIM_LIGHT) {
6592 mLightTrimListeners.add(info);
6593 } else {
6594 mLightTrimListeners.remove(info);
6595 }
6596 }
6597
6598 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
6599 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04006600 }
6601
John Spurlock7340fc82014-04-24 18:50:12 -04006602 /**
6603 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02006604 *
6605 * <p>
6606 * Also takes care of removing a notification that has been visible to a listener before,
6607 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04006608 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006609 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006610 public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
6611 notifyPostedLocked(r, old, true);
Beverly5a20a5e2018-03-06 15:02:44 -05006612 }
6613
6614 /**
6615 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
6616 * targetting <= O_MR1
6617 */
6618 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006619 private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
Beverly5a20a5e2018-03-06 15:02:44 -05006620 boolean notifyAllListeners) {
Christoph Studerb82bc782014-08-20 14:29:43 +02006621 // Lazily initialized snapshots of the notification.
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006622 StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006623 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Chris Wren47633422016-01-22 09:56:59 -05006624 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02006625
Julia Reynolds00314d92017-04-14 10:01:24 -04006626 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02006627 boolean sbnVisible = isVisibleToListener(sbn, info);
6628 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
6629 // This notification hasn't been and still isn't visible -> ignore.
6630 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006631 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04006632 }
Beverly5a20a5e2018-03-06 15:02:44 -05006633
6634 // 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
7067 : Intent.ACTION_PACKAGES_UNSUSPENDED;
7068 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}