blob: 8d581df2c43e7dacbe24077aace69fa6fa000717 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Adam Lesinski182f73f2013-12-05 16:48:06 -080017package com.android.server.notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Beverly58b24532018-10-02 09:08:23 -040019import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
Julia Reynoldse5c60452018-04-30 14:41:36 -040020import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
Julia Reynoldsfc9767b2018-01-22 17:45:16 -050021import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050022import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
23import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
Julia Reynolds8617e4e2017-09-18 16:52:37 -040024import static android.app.NotificationManager.IMPORTANCE_LOW;
Julia Reynolds7c96b582017-05-25 12:35:36 -040025import static android.app.NotificationManager.IMPORTANCE_MIN;
Julia Reynolds85769912016-10-25 09:08:57 -040026import static android.app.NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -050027import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
28import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
29import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
30import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
31import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
32import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
33import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
34import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
35import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
36import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
Amith Yamasanie5bfeee2018-09-05 18:52:35 -070037import static android.content.Context.BIND_ADJUST_BELOW_PERCEPTIBLE;
38import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
39import static android.content.Context.BIND_AUTO_CREATE;
40import static android.content.Context.BIND_FOREGROUND_SERVICE;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -050041import static android.content.pm.PackageManager.FEATURE_LEANBACK;
42import static android.content.pm.PackageManager.FEATURE_TELEVISION;
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -040043import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
44import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
Julia Reynolds4db59552017-06-30 13:34:01 -040045import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Vishnu Naire3e4d252018-03-01 11:26:57 -080046import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
47import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
Julia Reynolds88a879f2017-07-26 17:06:46 -040048import static android.os.UserHandle.USER_NULL;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040049import static android.os.UserHandle.USER_SYSTEM;
Julia Reynolds73ed76b2017-04-04 17:04:38 -040050import static android.service.notification.NotificationListenerService
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050051 .HINT_HOST_DISABLE_CALL_EFFECTS;
52import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
53import static android.service.notification.NotificationListenerService
54 .HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
55import static android.service.notification.NotificationListenerService
Julia Reynolds73ed76b2017-04-04 17:04:38 -040056 .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
57import static android.service.notification.NotificationListenerService
58 .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
59import static android.service.notification.NotificationListenerService
60 .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050061import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
62import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040063import static android.service.notification.NotificationListenerService.REASON_CANCEL;
64import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050065import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040066import static android.service.notification.NotificationListenerService.REASON_CLICK;
67import static android.service.notification.NotificationListenerService.REASON_ERROR;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050068import static android.service.notification.NotificationListenerService
69 .REASON_GROUP_SUMMARY_CANCELED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050070import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
71import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
72import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
73import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
74import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
75import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
76import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
Julia Reynolds2a128742016-11-28 14:29:25 -050077import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050078import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
79import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
Christoph Studerb82bc782014-08-20 14:29:43 +020080import static android.service.notification.NotificationListenerService.TRIM_FULL;
81import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
Wale Ogunwaleac2561e2016-11-01 15:43:46 -070082import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
svetoslavganov75986cf2009-05-14 22:28:01 -070083
Vishnu Naire3e4d252018-03-01 11:26:57 -080084import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
85import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
86import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
87
Chris Wren51017d02015-12-15 15:34:46 -050088import android.Manifest;
Julia Reynoldsa78cdff2017-04-26 10:19:25 -040089import android.annotation.NonNull;
Wei Liu97e56662016-03-04 10:52:33 -080090import android.annotation.Nullable;
Dianne Hackborn41203752012-08-31 14:05:51 -070091import android.app.ActivityManager;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070092import android.app.ActivityManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -050093import android.app.AlarmManager;
John Spurlock7340fc82014-04-24 18:50:12 -040094import android.app.AppGlobals;
Daniel Sandler4a900ac2013-01-30 14:04:10 -050095import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040096import android.app.AutomaticZenRule;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097import android.app.IActivityManager;
98import android.app.INotificationManager;
99import android.app.ITransientNotification;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700100import android.app.IUriGrantsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101import android.app.Notification;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400102import android.app.NotificationChannel;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500103import android.app.NotificationChannelGroup;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500104import android.app.NotificationManager;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500105import android.app.NotificationManager.Policy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106import android.app.PendingIntent;
107import android.app.StatusBarManager;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700108import android.app.UriGrantsManager;
Jason Parks50322ff2018-03-27 10:23:33 -0500109import android.app.admin.DeviceAdminInfo;
110import android.app.admin.DevicePolicyManagerInternal;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500111import android.app.backup.BackupManager;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700112import android.app.usage.UsageEvents;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700113import android.app.usage.UsageStatsManagerInternal;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400114import android.companion.ICompanionDeviceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import android.content.BroadcastReceiver;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700116import android.content.ComponentName;
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400117import android.content.ContentProvider;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700118import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119import android.content.Context;
120import android.content.Intent;
121import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -0400122import android.content.pm.ApplicationInfo;
Kenny Guy70058402014-10-28 20:45:06 +0000123import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124import android.content.pm.PackageManager;
125import android.content.pm.PackageManager.NameNotFoundException;
Christoph Studercee44ba2014-05-20 18:36:43 +0200126import android.content.pm.ParceledListSlice;
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400127import android.content.pm.UserInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700129import android.database.ContentObserver;
Beverly5d463b62017-07-26 14:13:40 -0400130import android.media.AudioAttributes;
svetoslavganov75986cf2009-05-14 22:28:01 -0700131import android.media.AudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500132import android.media.AudioManagerInternal;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700133import android.media.IRingtonePlayer;
Kenny Guy23991102018-04-05 21:18:38 +0100134import android.metrics.LogMaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136import android.os.Binder;
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -0400137import android.os.Build;
John Spurlock2b122f42014-08-27 16:29:47 -0400138import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -0400139import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140import android.os.Handler;
Chris Wrenf9536642014-04-17 10:01:54 -0400141import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142import android.os.IBinder;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800143import android.os.IDeviceIdleController;
John Spurlock7340fc82014-04-24 18:50:12 -0400144import android.os.IInterface;
Chris Wrenf9536642014-04-17 10:01:54 -0400145import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700147import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -0700148import android.os.RemoteException;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400149import android.os.ResultReceiver;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400150import android.os.ServiceManager;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400151import android.os.ShellCallback;
152import android.os.ShellCommand;
Chris Wrenc8673a82016-05-17 17:11:29 -0400153import android.os.SystemClock;
Selim Cinekb5605e52015-02-20 18:21:41 +0100154import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700155import android.os.UserHandle;
Michael Wright71216972017-01-31 18:33:54 +0000156import android.os.VibrationEffect;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500157import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158import android.provider.Settings;
Julia Reynoldse46bb372016-03-17 11:05:58 -0400159import android.service.notification.Adjustment;
Chris Wren333a61c2014-05-28 16:40:57 -0400160import android.service.notification.Condition;
John Spurlock7340fc82014-04-24 18:50:12 -0400161import android.service.notification.IConditionProvider;
Chris Wren333a61c2014-05-28 16:40:57 -0400162import android.service.notification.INotificationListener;
Griff Hazen84a00ea2014-09-02 17:10:47 -0700163import android.service.notification.IStatusBarNotificationHolder;
Kweku Adams93304b62017-09-20 17:03:00 -0700164import android.service.notification.ListenersDisablingEffectsProto;
Julia Reynolds77b2cc92016-11-08 14:41:09 -0500165import android.service.notification.NotificationAssistantService;
John Spurlock7340fc82014-04-24 18:50:12 -0400166import android.service.notification.NotificationListenerService;
Christoph Studer05ad4822014-05-16 14:16:03 +0200167import android.service.notification.NotificationRankingUpdate;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500168import android.service.notification.NotificationRecordProto;
169import android.service.notification.NotificationServiceDumpProto;
Julia Reynolds503ed942017-10-04 16:04:56 -0400170import android.service.notification.NotificationStats;
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500171import android.service.notification.NotifyingApp;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500172import android.service.notification.SnoozeCriterion;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700173import android.service.notification.StatusBarNotification;
John Spurlock056c5192014-04-20 21:52:01 -0400174import android.service.notification.ZenModeConfig;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500175import android.service.notification.ZenModeProto;
John Spurlock32fe4c62014-10-02 12:16:02 -0400176import android.telephony.PhoneStateListener;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500177import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -0700178import android.text.TextUtils;
John Spurlocka4294292014-03-24 18:02:32 -0400179import android.util.ArrayMap;
John Spurlock1fa865f2014-07-21 14:56:39 -0400180import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700181import android.util.AtomicFile;
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400182import android.util.IntArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -0800184import android.util.Slog;
Bryce Lee7219ada2016-04-08 10:54:23 -0700185import android.util.SparseArray;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400186import android.util.Xml;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500187import android.util.proto.ProtoOutputStream;
svetoslavganov75986cf2009-05-14 22:28:01 -0700188import android.view.accessibility.AccessibilityEvent;
189import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190import android.widget.Toast;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000191
Scott Greenwald9a05b312013-06-28 00:37:54 -0400192import com.android.internal.R;
Julia Reynolds88860ce2017-06-01 16:55:49 -0400193import com.android.internal.annotations.GuardedBy;
Chris Wren93bb8b82016-03-29 14:35:05 -0400194import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -0500195import com.android.internal.logging.MetricsLogger;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500196import com.android.internal.logging.nano.MetricsProto;
Chris Wren9eb5e102017-01-26 13:15:06 -0500197import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Beverly70dcd002018-03-29 17:09:16 -0400198import com.android.internal.notification.SystemNotificationChannels;
Eugene Suslaa25d17f2017-08-24 11:28:08 -0700199import com.android.internal.os.BackgroundThread;
Chris Wrend1dbc922015-06-19 17:51:16 -0400200import com.android.internal.statusbar.NotificationVisibility;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400201import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600202import com.android.internal.util.DumpUtils;
John Spurlock056c5192014-04-20 21:52:01 -0400203import com.android.internal.util.FastXmlSerializer;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400204import com.android.internal.util.Preconditions;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400205import com.android.internal.util.XmlUtils;
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700206import com.android.server.DeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800207import com.android.server.EventLogTags;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700208import com.android.server.LocalServices;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800209import com.android.server.SystemService;
210import com.android.server.lights.Light;
211import com.android.server.lights.LightsManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400212import com.android.server.notification.ManagedServices.ManagedServiceInfo;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500213import com.android.server.notification.ManagedServices.UserProfiles;
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400214import com.android.server.pm.PackageManagerService;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700215import com.android.server.policy.PhoneWindowManager;
John Spurlockb408e8e2014-04-23 21:12:45 -0400216import com.android.server.statusbar.StatusBarManagerInternal;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700217import com.android.server.uri.UriGrantsManagerInternal;
Adrian Roose99bc052017-11-20 17:55:31 +0100218import com.android.server.wm.WindowManagerInternal;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800219
John Spurlockb408e8e2014-04-23 21:12:45 -0400220import libcore.io.IoUtils;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000221
Chris Wrene4b38802015-07-07 15:54:19 -0400222import org.json.JSONException;
223import org.json.JSONObject;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700224import org.xmlpull.v1.XmlPullParser;
225import org.xmlpull.v1.XmlPullParserException;
John Spurlock056c5192014-04-20 21:52:01 -0400226import org.xmlpull.v1.XmlSerializer;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700227
John Spurlock35ef0a62015-05-28 11:24:10 -0400228import java.io.ByteArrayInputStream;
229import java.io.ByteArrayOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400230import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400232import java.io.FileNotFoundException;
John Spurlock056c5192014-04-20 21:52:01 -0400233import java.io.FileOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400234import java.io.IOException;
John Spurlock35ef0a62015-05-28 11:24:10 -0400235import java.io.InputStream;
236import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100238import java.nio.charset.StandardCharsets;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500239import java.util.ArrayDeque;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240import java.util.ArrayList;
Michael Wrightbc4d0d92017-03-23 18:57:57 +0000241import java.util.Arrays;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500242import java.util.Iterator;
John Spurlock7c74f782015-06-04 13:01:42 -0400243import java.util.List;
Christoph Studer265c1052014-07-23 17:14:33 +0200244import java.util.Map.Entry;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500245import java.util.Objects;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400246import java.util.Set;
Chris Wren51017d02015-12-15 15:34:46 -0500247import java.util.concurrent.TimeUnit;
Kristian Monsen30f59b22018-04-09 10:27:16 +0200248import java.util.function.Predicate;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400249
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400250/** {@hide} */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800251public class NotificationManagerService extends SystemService {
252 static final String TAG = "NotificationService";
Christoph Studer1f32c652014-11-26 15:32:20 +0100253 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Selim Cinek40412492015-12-08 18:03:22 -0800254 public static final boolean ENABLE_CHILD_NOTIFICATIONS
255 = SystemProperties.getBoolean("debug.child_notifs", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256
Dan Sandler7d67bd42018-05-15 14:06:38 -0400257 static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
258 "debug.notification.interruptiveness", false);
259
Adam Lesinski182f73f2013-12-05 16:48:06 -0800260 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
Julia Reynolds6ad0aec2017-07-05 08:47:03 -0400261 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
Joe Onoratobd73d012010-06-04 11:44:54 -0700262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 // message codes
Robert Carr997427342018-02-28 18:06:10 -0800264 static final int MESSAGE_DURATION_REACHED = 2;
John Spurlock056c5192014-04-20 21:52:01 -0400265 static final int MESSAGE_SAVE_POLICY_FILE = 3;
Chris Wren51017d02015-12-15 15:34:46 -0500266 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
267 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
268 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
Robert Carr997427342018-02-28 18:06:10 -0800269 static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
Chris Wren51017d02015-12-15 15:34:46 -0500270
271 // ranking thread messages
272 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
273 private static final int MESSAGE_RANKING_SORT = 1001;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700275 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800276 static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800277
Robert Carr3406d462018-03-15 16:19:07 -0700278 // 1 second past the ANR timeout.
279 static final int FINISH_TOKEN_TIMEOUT = 11 * 1000;
280
Adam Lesinski182f73f2013-12-05 16:48:06 -0800281 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
Christoph Studer265c1052014-07-23 17:14:33 +0200282
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500283 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
284
Adam Lesinski182f73f2013-12-05 16:48:06 -0800285 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286
Adam Lesinski182f73f2013-12-05 16:48:06 -0800287 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler526fa0e2012-12-04 14:51:50 -0500288
Adam Lesinski182f73f2013-12-05 16:48:06 -0800289 static final boolean ENABLE_BLOCKED_TOASTS = true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400290
Christoph Studer12aeda82014-09-23 19:08:56 +0200291 // When #matchesCallFilter is called from the ringer, wait at most
292 // 3s to resolve the contacts. This timeout is required since
293 // ContactsProvider might take a long time to start up.
294 //
295 // Return STARRED_CONTACT when the timeout is hit in order to avoid
296 // missed calls in ZEN mode "Important".
297 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
298 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
299 ValidateNotificationPeople.STARRED_CONTACT;
300
Christoph Studer265c1052014-07-23 17:14:33 +0200301 /** notification_enqueue status value for a newly enqueued notification. */
302 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
303
304 /** notification_enqueue status value for an existing notification. */
305 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
306
307 /** notification_enqueue status value for an ignored notification. */
308 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
Chris Wrenc8673a82016-05-17 17:11:29 -0400309 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
Christoph Studer265c1052014-07-23 17:14:33 +0200310
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500311 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
312
Julia Reynolds2a128742016-11-28 14:29:25 -0500313 private static final String ACTION_NOTIFICATION_TIMEOUT =
314 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
315 private static final int REQUEST_CODE_TIMEOUT = 1;
316 private static final String SCHEME_TIMEOUT = "timeout";
317 private static final String EXTRA_KEY = "key";
318
Adam Lesinski182f73f2013-12-05 16:48:06 -0800319 private IActivityManager mAm;
Julia Reynolds68263d12017-06-21 14:21:19 -0400320 private ActivityManager mActivityManager;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500321 private IPackageManager mPackageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500322 private PackageManager mPackageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800323 AudioManager mAudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500324 AudioManagerInternal mAudioManagerInternal;
Wei Liu97e56662016-03-04 10:52:33 -0800325 @Nullable StatusBarManagerInternal mStatusBar;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800326 Vibrator mVibrator;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700327 private WindowManagerInternal mWindowManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -0500328 private AlarmManager mAlarmManager;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400329 private ICompanionDeviceManager mCompanionManager;
Julia Reynolds94187562017-10-10 13:58:49 -0400330 private AccessibilityManager mAccessibilityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800331 private IDeviceIdleController mDeviceIdleController;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700332 private IUriGrantsManager mUgm;
333 private UriGrantsManagerInternal mUgmInternal;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 final IBinder mForegroundToken = new Binder();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400336 private WorkerHandler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400337 private final HandlerThread mRankingThread = new HandlerThread("ranker",
338 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339
Adam Lesinski182f73f2013-12-05 16:48:06 -0800340 private Light mNotificationLight;
341 Light mAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800342
Daniel Sandleredbb3802012-11-13 20:49:47 -0800343 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400344 private boolean mUseAttentionLight;
Julia Reynolds28149f62018-07-03 10:43:35 -0400345 boolean mHasLight = true;
346 boolean mLightEnabled;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800347 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800348
John Spurlockd8afe3c2014-08-01 14:04:07 -0400349 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400350 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500351 private String mSoundNotificationKey;
352 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353
Julia Reynolds4703bac2018-09-12 10:39:30 -0400354 private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects =
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400355 new SparseArray<>();
356 private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400357 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500358 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400359
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500360 // for enabling and disabling notification pulse behavior
Julia Reynolds28149f62018-07-03 10:43:35 -0400361 boolean mScreenOn = true;
Beverly5d463b62017-07-26 14:13:40 -0400362 protected boolean mInCall = false;
Julia Reynolds28149f62018-07-03 10:43:35 -0400363 boolean mNotificationPulseEnabled;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500364
Beverly5d463b62017-07-26 14:13:40 -0400365 private Uri mInCallNotificationUri;
366 private AudioAttributes mInCallNotificationAudioAttributes;
367 private float mInCallNotificationVolume;
luochaojiang50e5273c2018-04-16 16:55:03 +0800368 private Binder mCallNotificationToken = null;
Marta Białka39c992f2011-03-10 10:27:24 +0100369
Daniel Sandler09a247e2013-02-14 10:24:17 -0500370 // used as a mutex for access to all active notifications & listeners
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500371 final Object mNotificationLock = new Object();
Julia Reynolds0839c022017-06-15 15:24:01 -0400372 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400373 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400374 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400375 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400376 @GuardedBy("mNotificationLock")
Chris Wren6676dab2016-12-21 18:26:27 -0500377 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400378 @GuardedBy("mNotificationLock")
Julia Reynoldseae43fb2016-05-09 12:42:58 -0400379 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400380 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
Christoph Studer265c1052014-07-23 17:14:33 +0200381 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500382 final ArrayMap<Integer, ArrayList<NotifyingApp>> mRecentApps = new ArrayMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383
Chris Wren6054e612014-11-25 17:16:46 -0500384 // The last key in this list owns the hardware.
385 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700386
Adam Lesinski182f73f2013-12-05 16:48:06 -0800387 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700388 private UsageStatsManagerInternal mAppUsageStats;
Jason Parks50322ff2018-03-27 10:23:33 -0500389 private DevicePolicyManagerInternal mDpm;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500390
Griff Hazen9f637d12014-06-10 11:13:51 -0700391 private Archive mArchive;
392
John Spurlock21258a32015-05-27 18:22:55 -0400393 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400394 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400395
Daniel Sandler0da673f2012-04-11 12:33:16 -0400396 private static final int DB_VERSION = 1;
397
John Spurlock21258a32015-05-27 18:22:55 -0400398 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400399 private static final String ATTR_VERSION = "version";
400
Chris Wren54bbef42014-07-09 18:37:56 -0400401 private RankingHelper mRankingHelper;
Aaron Heuckrothe5bec152018-07-09 16:26:09 -0400402 private PreferencesHelper mPreferencesHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400403
John Spurlockb408e8e2014-04-23 21:12:45 -0400404 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400405 private NotificationListeners mListeners;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400406 private NotificationAssistants mAssistants;
John Spurlock7340fc82014-04-24 18:50:12 -0400407 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200408 private NotificationUsageStats mUsageStats;
Christoph Studer546bec82014-03-14 12:17:12 +0100409
John Spurlocke6a7d932014-03-13 12:29:00 -0400410 private static final int MY_UID = Process.myUid();
411 private static final int MY_PID = Process.myPid();
Dianne Hackborn98305522017-05-05 17:53:53 -0700412 private static final IBinder WHITELIST_TOKEN = new Binder();
Chris Wren51017d02015-12-15 15:34:46 -0500413 private RankingHandler mRankingHandler;
Chris Wrenc8673a82016-05-17 17:11:29 -0400414 private long mLastOverRateLogTime;
Chris Wren763a9bb2016-05-31 17:14:12 -0400415 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
John Spurlocke6a7d932014-03-13 12:29:00 -0400416
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400417 private SnoozeHelper mSnoozeHelper;
Julia Reynolds8f488d32016-10-14 10:59:01 -0400418 private GroupHelper mGroupHelper;
Adora Zhang48dd614a82018-06-25 19:18:41 -0700419 private int mAutoGroupAtCount;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -0500420 private boolean mIsTelevision;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400421
Kenny Guy23991102018-04-05 21:18:38 +0100422 private MetricsLogger mMetricsLogger;
Kristian Monsen30f59b22018-04-09 10:27:16 +0200423 private Predicate<String> mAllowedManagedServicePackages;
Kenny Guy23991102018-04-05 21:18:38 +0100424
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500425 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700426 final int mBufferSize;
427 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500428
Griff Hazen9f637d12014-06-10 11:13:51 -0700429 public Archive(int size) {
430 mBufferSize = size;
431 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500432 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700433
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400434 public String toString() {
435 final StringBuilder sb = new StringBuilder();
436 final int N = mBuffer.size();
437 sb.append("Archive (");
438 sb.append(N);
439 sb.append(" notification");
440 sb.append((N==1)?")":"s)");
441 return sb.toString();
442 }
443
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500444 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700445 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500446 mBuffer.removeFirst();
447 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400448
449 // We don't want to store the heavy bits of the notification in the archive,
450 // but other clients in the system process might be using the object, so we
451 // store a (lightened) copy.
452 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500453 }
454
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500455 public Iterator<StatusBarNotification> descendingIterator() {
456 return mBuffer.descendingIterator();
457 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500458
459 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700460 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500461 final StatusBarNotification[] a
462 = new StatusBarNotification[Math.min(count, mBuffer.size())];
463 Iterator<StatusBarNotification> iter = descendingIterator();
464 int i=0;
465 while (iter.hasNext() && i < count) {
466 a[i++] = iter.next();
467 }
468 return a;
469 }
470
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500471 }
472
Julia Reynolds88a879f2017-07-26 17:06:46 -0400473 protected void readDefaultApprovedServices(int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400474 String defaultListenerAccess = getContext().getResources().getString(
475 com.android.internal.R.string.config_defaultListenerAccessPackages);
476 if (defaultListenerAccess != null) {
477 for (String whitelisted :
478 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
479 // Gather all notification listener components for candidate pkgs.
480 Set<ComponentName> approvedListeners =
481 mListeners.queryPackageForServices(whitelisted,
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400482 MATCH_DIRECT_BOOT_AWARE
483 | MATCH_DIRECT_BOOT_UNAWARE, userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400484 for (ComponentName cn : approvedListeners) {
485 try {
486 getBinderService().setNotificationListenerAccessGrantedForUser(cn,
487 userId, true);
488 } catch (RemoteException e) {
489 e.printStackTrace();
490 }
491 }
492 }
493 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500494
Julia Reynoldsb852e562017-06-06 16:14:18 -0400495 String defaultDndAccess = getContext().getResources().getString(
496 com.android.internal.R.string.config_defaultDndAccessPackages);
Edward Savage-Jones36a89422018-07-19 12:23:58 +0200497 if (defaultDndAccess != null) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400498 for (String whitelisted :
499 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
500 try {
501 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
502 } catch (RemoteException e) {
503 e.printStackTrace();
504 }
505 }
506 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500507
508 readDefaultAssistant(userId);
509 }
510
511 protected void readDefaultAssistant(int userId) {
512 String defaultAssistantAccess = getContext().getResources().getString(
513 com.android.internal.R.string.config_defaultAssistantAccessPackage);
514 if (defaultAssistantAccess != null) {
515 // Gather all notification assistant components for candidate pkg. There should
516 // only be one
517 Set<ComponentName> approvedAssistants =
518 mAssistants.queryPackageForServices(defaultAssistantAccess,
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400519 MATCH_DIRECT_BOOT_AWARE
520 | MATCH_DIRECT_BOOT_UNAWARE, userId);
Julia Reynolds7380d872018-01-12 10:28:26 -0500521 for (ComponentName cn : approvedAssistants) {
522 try {
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400523 getBinderService().setNotificationAssistantAccessGrantedForUser(
524 cn, userId, true);
Julia Reynolds7380d872018-01-12 10:28:26 -0500525 } catch (RemoteException e) {
526 e.printStackTrace();
527 }
528 }
529 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400530 }
531
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400532 void readPolicyXml(InputStream stream, boolean forRestore)
John Spurlock35ef0a62015-05-28 11:24:10 -0400533 throws XmlPullParserException, NumberFormatException, IOException {
534 final XmlPullParser parser = Xml.newPullParser();
535 parser.setInput(stream, StandardCharsets.UTF_8.name());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400536 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
537 boolean migratedManagedServices = false;
538 int outerDepth = parser.getDepth();
539 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
540 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
541 mZenModeHelper.readXml(parser, forRestore);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -0400542 } else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){
543 mPreferencesHelper.readXml(parser, forRestore);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400544 }
Kristian Monsen30f59b22018-04-09 10:27:16 +0200545 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
546 mListeners.readXml(parser, mAllowedManagedServicePackages);
547 migratedManagedServices = true;
548 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
549 mAssistants.readXml(parser, mAllowedManagedServicePackages);
550 migratedManagedServices = true;
551 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
552 mConditionProviders.readXml(parser, mAllowedManagedServicePackages);
553 migratedManagedServices = true;
Julia Reynolds68263d12017-06-21 14:21:19 -0400554 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400555 }
556
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400557 if (!migratedManagedServices) {
558 mListeners.migrateToXml();
559 mAssistants.migrateToXml();
560 mConditionProviders.migrateToXml();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400561 savePolicyFile();
John Spurlock35ef0a62015-05-28 11:24:10 -0400562 }
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400563
564 mAssistants.ensureAssistant();
John Spurlock35ef0a62015-05-28 11:24:10 -0400565 }
566
John Spurlock056c5192014-04-20 21:52:01 -0400567 private void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400568 if (DBG) Slog.d(TAG, "loadPolicyFile");
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500569 synchronized (mPolicyFile) {
Daniel Sandler0da673f2012-04-11 12:33:16 -0400570
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400571 InputStream infile = null;
John Spurlock056c5192014-04-20 21:52:01 -0400572 try {
573 infile = mPolicyFile.openRead();
John Spurlock35ef0a62015-05-28 11:24:10 -0400574 readPolicyXml(infile, false /*forRestore*/);
John Spurlock056c5192014-04-20 21:52:01 -0400575 } catch (FileNotFoundException e) {
576 // No data yet
Julia Reynoldsb852e562017-06-06 16:14:18 -0400577 // Load default managed services approvals
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400578 readDefaultApprovedServices(USER_SYSTEM);
John Spurlock056c5192014-04-20 21:52:01 -0400579 } catch (IOException e) {
580 Log.wtf(TAG, "Unable to read notification policy", e);
581 } catch (NumberFormatException e) {
582 Log.wtf(TAG, "Unable to parse notification policy", e);
583 } catch (XmlPullParserException e) {
584 Log.wtf(TAG, "Unable to parse notification policy", e);
585 } finally {
586 IoUtils.closeQuietly(infile);
587 }
588 }
589 }
590
591 public void savePolicyFile() {
592 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
593 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
594 }
595
596 private void handleSavePolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400597 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400598 synchronized (mPolicyFile) {
599 final FileOutputStream stream;
600 try {
601 stream = mPolicyFile.startWrite();
602 } catch (IOException e) {
603 Slog.w(TAG, "Failed to save policy file", e);
604 return;
605 }
606
607 try {
John Spurlock35ef0a62015-05-28 11:24:10 -0400608 writePolicyXml(stream, false /*forBackup*/);
John Spurlock056c5192014-04-20 21:52:01 -0400609 mPolicyFile.finishWrite(stream);
610 } catch (IOException e) {
611 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
612 mPolicyFile.failWrite(stream);
Daniel Sandler0da673f2012-04-11 12:33:16 -0400613 }
614 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400615 BackupManager.dataChanged(getContext().getPackageName());
616 }
617
618 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
619 final XmlSerializer out = new FastXmlSerializer();
620 out.setOutput(stream, StandardCharsets.UTF_8.name());
621 out.startDocument(null, true);
622 out.startTag(null, TAG_NOTIFICATION_POLICY);
623 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
Beverly4e2f76c2018-03-16 15:43:49 -0400624 mZenModeHelper.writeXml(out, forBackup, null);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -0400625 mPreferencesHelper.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400626 mListeners.writeXml(out, forBackup);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400627 mAssistants.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400628 mConditionProviders.writeXml(out, forBackup);
John Spurlock35ef0a62015-05-28 11:24:10 -0400629 out.endTag(null, TAG_NOTIFICATION_POLICY);
630 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400631 }
632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 private static final class ToastRecord
634 {
635 final int pid;
636 final String pkg;
Beverly Taia7ed0ab2018-06-11 14:50:36 +0000637 final ITransientNotification callback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 int duration;
Jeff Chang48ecef42018-08-09 16:31:59 +0800639 int displayId;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700640 Binder token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700642 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
Jeff Chang48ecef42018-08-09 16:31:59 +0800643 Binder token, int displayId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644 this.pid = pid;
645 this.pkg = pkg;
646 this.callback = callback;
647 this.duration = duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700648 this.token = token;
Jeff Chang48ecef42018-08-09 16:31:59 +0800649 this.displayId = displayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 }
651
652 void update(int duration) {
653 this.duration = duration;
654 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800655
John Spurlock25e2d242014-06-27 13:58:23 -0400656 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
657 if (filter != null && !filter.matches(pkg)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 pw.println(prefix + this);
659 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800660
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 @Override
662 public final String toString()
663 {
664 return "ToastRecord{"
665 + Integer.toHexString(System.identityHashCode(this))
666 + " pkg=" + pkg
667 + " callback=" + callback
668 + " duration=" + duration;
669 }
670 }
671
Beverly40239d92017-07-07 10:20:41 -0400672 @VisibleForTesting
673 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674
Adam Lesinski182f73f2013-12-05 16:48:06 -0800675 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 public void onSetDisabled(int status) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500677 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400678 mDisableNotificationEffects =
679 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
John Spurlock32fe4c62014-10-02 12:16:02 -0400680 if (disableNotificationEffects(null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 // cancel whatever's going on
682 long identity = Binder.clearCallingIdentity();
683 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800684 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700685 if (player != null) {
686 player.stopAsync();
687 }
688 } catch (RemoteException e) {
689 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 Binder.restoreCallingIdentity(identity);
691 }
692
693 identity = Binder.clearCallingIdentity();
694 try {
695 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700696 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 Binder.restoreCallingIdentity(identity);
698 }
699 }
700 }
701 }
702
Adam Lesinski182f73f2013-12-05 16:48:06 -0800703 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400704 public void onClearAll(int callingUid, int callingPid, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500705 synchronized (mNotificationLock) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400706 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
Kenny Guya263e4e2014-03-03 18:24:03 +0000707 /*includeCurrentProfiles*/ true);
Adam Lesinskie8240262014-03-26 16:01:00 -0700708 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 }
710
Adam Lesinski182f73f2013-12-05 16:48:06 -0800711 @Override
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400712 public void onNotificationClick(int callingUid, int callingPid, String key,
713 NotificationVisibility nv) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800714 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500715 synchronized (mNotificationLock) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200716 NotificationRecord r = mNotificationsByKey.get(key);
717 if (r == null) {
718 Log.w(TAG, "No notification with key: " + key);
719 return;
720 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400721 final long now = System.currentTimeMillis();
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400722 MetricsLogger.action(r.getItemLogMaker()
Dieter Hsud39f0d52018-04-14 02:08:30 +0800723 .setType(MetricsEvent.TYPE_ACTION)
724 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
725 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400726 EventLogTags.writeNotificationClicked(key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800727 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
728 nv.rank, nv.count);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400729
Christoph Studer03b87a22014-04-30 17:33:27 +0200730 StatusBarNotification sbn = r.sbn;
731 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
732 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400733 FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
Dieter Hsud39f0d52018-04-14 02:08:30 +0800734 REASON_CLICK, nv.rank, nv.count, null);
735 nv.recycle();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800736 reportUserInteraction(r);
Christoph Studer03b87a22014-04-30 17:33:27 +0200737 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 }
739
Adam Lesinski182f73f2013-12-05 16:48:06 -0800740 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200741 public void onNotificationActionClick(int callingUid, int callingPid, String key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800742 int actionIndex, NotificationVisibility nv) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800743 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500744 synchronized (mNotificationLock) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200745 NotificationRecord r = mNotificationsByKey.get(key);
746 if (r == null) {
747 Log.w(TAG, "No notification with key: " + key);
748 return;
749 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400750 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500751 MetricsLogger.action(r.getLogMaker(now)
752 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
753 .setType(MetricsEvent.TYPE_ACTION)
Dieter Hsud39f0d52018-04-14 02:08:30 +0800754 .setSubtype(actionIndex)
755 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
756 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400757 EventLogTags.writeNotificationActionClicked(key, actionIndex,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800758 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
759 nv.rank, nv.count);
760 nv.recycle();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800761 reportUserInteraction(r);
Christoph Studer4da84cd2014-10-21 17:24:20 +0200762 }
763 }
764
765 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400766 public void onNotificationClear(int callingUid, int callingPid,
Julia Reynolds503ed942017-10-04 16:04:56 -0400767 String pkg, String tag, int id, int userId, String key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800768 @NotificationStats.DismissalSurface int dismissalSurface,
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400769 @NotificationStats.DismissalSentiment int dismissalSentiment,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800770 NotificationVisibility nv) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400771 synchronized (mNotificationLock) {
772 NotificationRecord r = mNotificationsByKey.get(key);
773 if (r != null) {
774 r.recordDismissalSurface(dismissalSurface);
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400775 r.recordDismissalSentiment(dismissalSentiment);
Julia Reynolds503ed942017-10-04 16:04:56 -0400776 }
777 }
John Spurlocke6a7d932014-03-13 12:29:00 -0400778 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400779 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800780 true, userId, REASON_CANCEL, nv.rank, nv.count,null);
781 nv.recycle();
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400782 }
783
Adam Lesinski182f73f2013-12-05 16:48:06 -0800784 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400785 public void onPanelRevealed(boolean clearEffects, int items) {
Chris Wren9eb5e102017-01-26 13:15:06 -0500786 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Chris Wren621933f2017-06-14 15:59:03 -0400787 MetricsLogger.histogram(getContext(), "note_load", items);
Chris Wrenb659c4f2015-06-25 17:12:27 -0400788 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100789 if (clearEffects) {
790 clearEffects();
791 }
792 }
793
794 @Override
795 public void onPanelHidden() {
Chris Wren9eb5e102017-01-26 13:15:06 -0500796 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Christoph Studer1f32c652014-11-26 15:32:20 +0100797 EventLogTags.writeNotificationPanelHidden();
798 }
799
800 @Override
801 public void clearEffects() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500802 synchronized (mNotificationLock) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100803 if (DBG) Slog.d(TAG, "clearEffects");
Chris Wren93bb8b82016-03-29 14:35:05 -0400804 clearSoundLocked();
805 clearVibrateLocked();
806 clearLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 }
808 }
Joe Onorato005847b2010-06-04 16:08:02 -0400809
Adam Lesinski182f73f2013-12-05 16:48:06 -0800810 @Override
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400811 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag,
812 int id, int uid, int initialPid, String message, int userId) {
John Spurlocke6a7d932014-03-13 12:29:00 -0400813 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400814 REASON_ERROR, null);
Joe Onorato005847b2010-06-04 16:08:02 -0400815 }
John Spurlocke677d712014-02-13 12:52:19 -0500816
817 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400818 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
819 NotificationVisibility[] noLongerVisibleKeys) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500820 synchronized (mNotificationLock) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400821 for (NotificationVisibility nv : newlyVisibleKeys) {
822 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200823 if (r == null) continue;
Amith Yamasani803eab692017-11-09 17:47:04 -0800824 if (!r.isSeen()) {
825 // Report to usage stats that notification was made visible
826 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
827 reportSeen(r);
Kenny Guy23991102018-04-05 21:18:38 +0100828
829 // If the newly visible notification has smart replies
830 // then log that the user has seen them.
831 if (r.getNumSmartRepliesAdded() > 0
832 && !r.hasSeenSmartReplies()) {
833 r.setSeenSmartReplies(true);
834 LogMaker logMaker = r.getLogMaker()
835 .setCategory(MetricsEvent.SMART_REPLY_VISIBLE)
836 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT,
837 r.getNumSmartRepliesAdded());
838 mMetricsLogger.write(logMaker);
839 }
Amith Yamasani803eab692017-11-09 17:47:04 -0800840 }
Dieter Hsud39f0d52018-04-14 02:08:30 +0800841 r.setVisibility(true, nv.rank, nv.count);
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400842 maybeRecordInterruptionLocked(r);
Chris Wrend1dbc922015-06-19 17:51:16 -0400843 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200844 }
845 // Note that we might receive this event after notifications
846 // have already left the system, e.g. after dismissing from the
847 // shade. Hence not finding notifications in
848 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400849 for (NotificationVisibility nv : noLongerVisibleKeys) {
850 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200851 if (r == null) continue;
Dieter Hsud39f0d52018-04-14 02:08:30 +0800852 r.setVisibility(false, nv.rank, nv.count);
Chris Wrend1dbc922015-06-19 17:51:16 -0400853 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200854 }
855 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200856 }
Chris Wren78403d72014-07-28 10:23:24 +0100857
858 @Override
859 public void onNotificationExpansionChanged(String key,
860 boolean userAction, boolean expanded) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500861 synchronized (mNotificationLock) {
Chris Wren78403d72014-07-28 10:23:24 +0100862 NotificationRecord r = mNotificationsByKey.get(key);
863 if (r != null) {
864 r.stats.onExpansionChanged(userAction, expanded);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400865 final long now = System.currentTimeMillis();
Chris Wrenf7342712017-09-14 10:55:55 -0400866 if (userAction) {
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400867 MetricsLogger.action(r.getItemLogMaker()
Chris Wrenf7342712017-09-14 10:55:55 -0400868 .setType(expanded ? MetricsEvent.TYPE_DETAIL
869 : MetricsEvent.TYPE_COLLAPSE));
Chris Wren377ac6d2017-09-12 14:15:23 -0400870 }
Julia Reynolds84dc96b2017-11-14 09:51:01 -0500871 if (expanded && userAction) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400872 r.recordExpanded();
873 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400874 EventLogTags.writeNotificationExpansion(key,
875 userAction ? 1 : 0, expanded ? 1 : 0,
876 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Chris Wren78403d72014-07-28 10:23:24 +0100877 }
878 }
879 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400880
881 @Override
882 public void onNotificationDirectReplied(String key) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800883 exitIdle();
Julia Reynolds503ed942017-10-04 16:04:56 -0400884 synchronized (mNotificationLock) {
885 NotificationRecord r = mNotificationsByKey.get(key);
886 if (r != null) {
887 r.recordDirectReplied();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800888 reportUserInteraction(r);
Julia Reynolds503ed942017-10-04 16:04:56 -0400889 }
890 }
891 }
892
893 @Override
Kenny Guy23991102018-04-05 21:18:38 +0100894 public void onNotificationSmartRepliesAdded(String key, int replyCount) {
895 synchronized (mNotificationLock) {
896 NotificationRecord r = mNotificationsByKey.get(key);
897 if (r != null) {
898 r.setNumSmartRepliesAdded(replyCount);
899 }
900 }
901 }
902
903 @Override
904 public void onNotificationSmartReplySent(String key, int replyIndex) {
905 synchronized (mNotificationLock) {
906 NotificationRecord r = mNotificationsByKey.get(key);
907 if (r != null) {
908 LogMaker logMaker = r.getLogMaker()
909 .setCategory(MetricsEvent.SMART_REPLY_ACTION)
910 .setSubtype(replyIndex);
911 mMetricsLogger.write(logMaker);
912 // Treat clicking on a smart reply as a user interaction.
913 reportUserInteraction(r);
914 }
915 }
916 }
917
918 @Override
Julia Reynolds503ed942017-10-04 16:04:56 -0400919 public void onNotificationSettingsViewed(String key) {
920 synchronized (mNotificationLock) {
921 NotificationRecord r = mNotificationsByKey.get(key);
922 if (r != null) {
923 r.recordViewedSettings();
924 }
925 }
926 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 };
928
Julia Reynolds88860ce2017-06-01 16:55:49 -0400929 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400930 private void clearSoundLocked() {
931 mSoundNotificationKey = null;
932 long identity = Binder.clearCallingIdentity();
933 try {
934 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
935 if (player != null) {
936 player.stopAsync();
937 }
938 } catch (RemoteException e) {
939 } finally {
940 Binder.restoreCallingIdentity(identity);
941 }
942 }
943
Julia Reynolds88860ce2017-06-01 16:55:49 -0400944 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400945 private void clearVibrateLocked() {
946 mVibrateNotificationKey = null;
947 long identity = Binder.clearCallingIdentity();
948 try {
949 mVibrator.cancel();
950 } finally {
951 Binder.restoreCallingIdentity(identity);
952 }
953 }
954
Julia Reynolds88860ce2017-06-01 16:55:49 -0400955 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400956 private void clearLightsLocked() {
957 // light
958 mLights.clear();
959 updateLightsLocked();
960 }
961
Beverlyd4f96492017-08-02 13:36:11 -0400962 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
963 @Override
964 public void onReceive(Context context, Intent intent) {
965 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
Beverly70dcd002018-03-29 17:09:16 -0400966 // update system notification channels
967 SystemNotificationChannels.createAll(context);
Beverlyd4f96492017-08-02 13:36:11 -0400968 mZenModeHelper.updateDefaultZenRules();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -0400969 mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
Beverlyd4f96492017-08-02 13:36:11 -0400970 }
971 }
972 };
973
Julia Reynoldsb852e562017-06-06 16:14:18 -0400974 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
975 @Override
976 public void onReceive(Context context, Intent intent) {
977 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
978 try {
979 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
980 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
Michal Karpinski6135a262017-08-11 10:45:58 +0100981 int restoredFromSdkInt = intent.getIntExtra(
982 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400983 mListeners.onSettingRestored(
984 element, newValue, restoredFromSdkInt, getSendingUserId());
985 mConditionProviders.onSettingRestored(
986 element, newValue, restoredFromSdkInt, getSendingUserId());
Julia Reynoldsb852e562017-06-06 16:14:18 -0400987 } catch (Exception e) {
988 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
989 }
990 }
991 }
992 };
993
Julia Reynolds2a128742016-11-28 14:29:25 -0500994 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
995 @Override
996 public void onReceive(Context context, Intent intent) {
997 String action = intent.getAction();
998 if (action == null) {
999 return;
1000 }
1001 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
1002 final NotificationRecord record;
1003 synchronized (mNotificationLock) {
1004 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
1005 }
1006 if (record != null) {
1007 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
1008 record.sbn.getPackageName(), record.sbn.getTag(),
1009 record.sbn.getId(), 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -04001010 FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
Julia Reynolds2a128742016-11-28 14:29:25 -05001011 REASON_TIMEOUT, null);
1012 }
1013 }
1014 }
1015 };
1016
Kenny Guy70058402014-10-28 20:45:06 +00001017 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 @Override
1019 public void onReceive(Context context, Intent intent) {
1020 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -08001021 if (action == null) {
1022 return;
1023 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001025 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -04001026 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -04001027 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -04001028 boolean cancelNotifications = true;
Beverly5a20a5e2018-03-06 15:02:44 -05001029 boolean hideNotifications = false;
1030 boolean unhideNotifications = false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001031 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -04001032
Chris Wren3da73022013-05-10 14:41:21 -04001033 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -04001034 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001035 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -04001036 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001037 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001038 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
Beverly5a20a5e2018-03-06 15:02:44 -05001039 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
1040 || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
Kenny Guy70058402014-10-28 20:45:06 +00001041 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1042 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001043 String pkgList[] = null;
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001044 int uidList[] = null;
Julia Reynolds6434eb22016-08-08 17:19:26 -04001045 boolean removingPackage = queryRemove &&
1046 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
1047 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001048 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001049 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001050 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001051 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
1052 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4bc42b92018-08-14 11:27:35 -04001053 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Beverly5a20a5e2018-03-06 15:02:44 -05001054 cancelNotifications = false;
1055 hideNotifications = true;
1056 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
1057 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4bc42b92018-08-14 11:27:35 -04001058 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Beverly5a20a5e2018-03-06 15:02:44 -05001059 cancelNotifications = false;
1060 unhideNotifications = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001061 } else if (queryRestart) {
1062 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001063 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001064 } else {
1065 Uri uri = intent.getData();
1066 if (uri == null) {
1067 return;
1068 }
1069 String pkgName = uri.getSchemeSpecificPart();
1070 if (pkgName == null) {
1071 return;
1072 }
Daniel Sandler26ece572012-06-01 15:38:46 -04001073 if (packageChanged) {
1074 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -07001075 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001076 final int enabled = mPackageManager.getApplicationEnabledSetting(
1077 pkgName,
Kenny Guy70058402014-10-28 20:45:06 +00001078 changeUserId != UserHandle.USER_ALL ? changeUserId :
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001079 USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -07001080 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1081 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
1082 cancelNotifications = false;
1083 }
1084 } catch (IllegalArgumentException e) {
1085 // Package doesn't exist; probably racing with uninstall.
1086 // cancelNotifications is already true, so nothing to do here.
1087 if (DBG) {
1088 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
1089 }
Kenny Guy70058402014-10-28 20:45:06 +00001090 } catch (RemoteException e) {
1091 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -04001092 }
1093 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001094 pkgList = new String[]{pkgName};
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001095 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001097 if (pkgList != null && (pkgList.length > 0)) {
1098 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -04001099 if (cancelNotifications) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001100 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
1101 !queryRestart, changeUserId, reason, null);
Beverly5a20a5e2018-03-06 15:02:44 -05001102 } else if (hideNotifications) {
1103 hideNotificationsForPackages(pkgList);
1104 } else if (unhideNotifications) {
1105 unhideNotificationsForPackages(pkgList);
John Spurlock79f78922013-05-16 09:10:05 -04001106 }
Beverly5a20a5e2018-03-06 15:02:44 -05001107
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001108 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 }
Beverly5a20a5e2018-03-06 15:02:44 -05001110
Julia Reynoldsb852e562017-06-06 16:14:18 -04001111 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001112 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsb852e562017-06-06 16:14:18 -04001113 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001114 mPreferencesHelper.onPackagesChanged(
1115 removingPackage, changeUserId, pkgList, uidList);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001116 savePolicyFile();
Kenny Guy70058402014-10-28 20:45:06 +00001117 }
1118 }
1119 };
1120
1121 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1122 @Override
1123 public void onReceive(Context context, Intent intent) {
1124 String action = intent.getAction();
1125
1126 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001127 // Keep track of screen on/off state, but do not turn off the notification light
1128 // until user passes through the lock screen or views the notification.
1129 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +01001130 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001131 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1132 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +01001133 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001134 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -05001135 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
1136 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001137 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001138 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
1139 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1140 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001141 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001142 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001143 }
Rubin Xue95057a2016-04-01 16:49:25 +01001144 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001145 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +01001146 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001147 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001148 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001149 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001150 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1151 // turn off LED when user passes through lock screen
1152 mNotificationLight.turnOff();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001153 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Julia Reynolds4ff97492018-09-24 14:53:54 -04001154 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
John Spurlockb408e8e2014-04-23 21:12:45 -04001155 mUserProfiles.updateCache(context);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001156 if (!mUserProfiles.isManagedProfile(userId)) {
1157 // reload per-user settings
1158 mSettingsObserver.update(null);
1159 // Refresh managed services
1160 mConditionProviders.onUserSwitched(userId);
1161 mListeners.onUserSwitched(userId);
1162 mZenModeHelper.onUserSwitched(userId);
1163 }
1164 // assistant is the only thing that cares about managed profiles specifically
1165 mAssistants.onUserSwitched(userId);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001166 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001167 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1168 if (userId != USER_NULL) {
1169 mUserProfiles.updateCache(context);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001170 if (!mUserProfiles.isManagedProfile(userId)) {
1171 readDefaultApprovedServices(userId);
1172 }
Julia Reynolds88a879f2017-07-26 17:06:46 -04001173 }
John Spurlock21258a32015-05-27 18:22:55 -04001174 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
Julia Reynolds4ff97492018-09-24 14:53:54 -04001175 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001176 mUserProfiles.updateCache(context);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001177 mZenModeHelper.onUserRemoved(userId);
1178 mPreferencesHelper.onUserRemoved(userId);
1179 mListeners.onUserRemoved(userId);
1180 mConditionProviders.onUserRemoved(userId);
1181 mAssistants.onUserRemoved(userId);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -04001182 savePolicyFile();
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001183 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
Julia Reynolds4ff97492018-09-24 14:53:54 -04001184 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1185 mUserProfiles.updateCache(context);
1186 mAssistants.onUserUnlocked(userId);
1187 if (!mUserProfiles.isManagedProfile(userId)) {
1188 mConditionProviders.onUserUnlocked(userId);
1189 mListeners.onUserUnlocked(userId);
1190 mZenModeHelper.onUserUnlocked(userId);
1191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 }
1193 }
1194 };
1195
John Spurlock7c74f782015-06-04 13:01:42 -04001196 private final class SettingsObserver extends ContentObserver {
Chris Wren89aa2262017-05-05 18:05:56 -04001197 private final Uri NOTIFICATION_BADGING_URI
1198 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001199 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1200 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wren763a9bb2016-05-31 17:14:12 -04001201 private final Uri NOTIFICATION_RATE_LIMIT_URI
1202 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001203
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001204 SettingsObserver(Handler handler) {
1205 super(handler);
1206 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001207
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001208 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001209 ContentResolver resolver = getContext().getContentResolver();
Chris Wren89aa2262017-05-05 18:05:56 -04001210 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1211 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001212 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -07001213 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -04001214 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1215 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001216 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001217 }
1218
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001219 @Override public void onChange(boolean selfChange, Uri uri) {
1220 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001221 }
1222
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001223 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001224 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001225 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
zhoulei7e376972017-05-17 18:41:25 +08001226 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
Julia Reynolds28149f62018-07-03 10:43:35 -04001227 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT)
1228 != 0;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001229 if (mNotificationPulseEnabled != pulseEnabled) {
1230 mNotificationPulseEnabled = pulseEnabled;
1231 updateNotificationPulse();
1232 }
1233 }
Chris Wren763a9bb2016-05-31 17:14:12 -04001234 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1235 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1236 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1237 }
Chris Wren89aa2262017-05-05 18:05:56 -04001238 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001239 mPreferencesHelper.updateBadgingEnabled();
Chris Wren89aa2262017-05-05 18:05:56 -04001240 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001241 }
1242 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001243
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001244 private SettingsObserver mSettingsObserver;
Beverlyd4f96492017-08-02 13:36:11 -04001245 protected ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001246
Daniel Sandleredbb3802012-11-13 20:49:47 -08001247 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1248 int[] ar = r.getIntArray(resid);
1249 if (ar == null) {
1250 return def;
1251 }
1252 final int len = ar.length > maxlen ? maxlen : ar.length;
1253 long[] out = new long[len];
1254 for (int i=0; i<len; i++) {
1255 out[i] = ar[i];
1256 }
1257 return out;
1258 }
1259
Jeff Brownb880d882014-02-10 19:47:07 -08001260 public NotificationManagerService(Context context) {
1261 super(context);
Dianne Hackborn98305522017-05-05 17:53:53 -07001262 Notification.processWhitelistToken = WHITELIST_TOKEN;
Jeff Brownb880d882014-02-10 19:47:07 -08001263 }
1264
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001265 // TODO - replace these methods with a single VisibleForTesting constructor
Chris Wren93bb8b82016-03-29 14:35:05 -04001266 @VisibleForTesting
1267 void setAudioManager(AudioManager audioMananger) {
1268 mAudioManager = audioMananger;
1269 }
1270
1271 @VisibleForTesting
1272 void setVibrator(Vibrator vibrator) {
1273 mVibrator = vibrator;
1274 }
1275
1276 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001277 void setLights(Light light) {
1278 mNotificationLight = light;
1279 mAttentionLight = light;
Julia Reynolds033a4122017-01-31 16:50:38 -05001280 mNotificationPulseEnabled = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001281 }
1282
1283 @VisibleForTesting
1284 void setScreenOn(boolean on) {
1285 mScreenOn = on;
1286 }
1287
1288 @VisibleForTesting
Julia Reynolds080361e2017-07-13 11:23:12 -04001289 int getNotificationRecordCount() {
1290 synchronized (mNotificationLock) {
1291 int count = mNotificationList.size() + mNotificationsByKey.size()
1292 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1293 // subtract duplicates
1294 for (NotificationRecord posted : mNotificationList) {
1295 if (mNotificationsByKey.containsKey(posted.getKey())) {
1296 count--;
1297 }
1298 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001299 count--;
Julia Reynolds080361e2017-07-13 11:23:12 -04001300 }
1301 }
1302
1303 return count;
1304 }
1305 }
1306
Julia Reynolds7380d872018-01-12 10:28:26 -05001307 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001308 void clearNotifications() {
1309 mEnqueuedNotifications.clear();
1310 mNotificationList.clear();
1311 mNotificationsByKey.clear();
1312 mSummaryByGroupKey.clear();
1313 }
1314
Julia Reynolds080361e2017-07-13 11:23:12 -04001315 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001316 void addNotification(NotificationRecord r) {
1317 mNotificationList.add(r);
1318 mNotificationsByKey.put(r.sbn.getKey(), r);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001319 if (r.sbn.isGroup()) {
1320 mSummaryByGroupKey.put(r.getGroupKey(), r);
1321 }
1322 }
1323
1324 @VisibleForTesting
1325 void addEnqueuedNotification(NotificationRecord r) {
1326 mEnqueuedNotifications.add(r);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001327 }
1328
1329 @VisibleForTesting
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001330 NotificationRecord getNotificationRecord(String key) {
1331 return mNotificationsByKey.get(key);
1332 }
1333
1334
1335 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001336 void setSystemReady(boolean systemReady) {
1337 mSystemReady = systemReady;
1338 }
1339
1340 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001341 void setHandler(WorkerHandler handler) {
Chris Wren93bb8b82016-03-29 14:35:05 -04001342 mHandler = handler;
1343 }
1344
Chris Wrend4054312016-06-24 17:07:40 -04001345 @VisibleForTesting
Julia Reynolds0c299d42016-11-15 14:37:04 -05001346 void setFallbackVibrationPattern(long[] vibrationPattern) {
1347 mFallbackVibrationPattern = vibrationPattern;
Chris Wrend4054312016-06-24 17:07:40 -04001348 }
1349
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001350 @VisibleForTesting
1351 void setPackageManager(IPackageManager packageManager) {
1352 mPackageManager = packageManager;
1353 }
1354
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001355 @VisibleForTesting
1356 void setRankingHelper(RankingHelper rankingHelper) {
1357 mRankingHelper = rankingHelper;
1358 }
1359
1360 @VisibleForTesting
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001361 void setPreferencesHelper(PreferencesHelper prefHelper) { mPreferencesHelper = prefHelper; }
1362
1363 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001364 void setRankingHandler(RankingHandler rankingHandler) {
1365 mRankingHandler = rankingHandler;
1366 }
1367
1368 @VisibleForTesting
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001369 void setIsTelevision(boolean isTelevision) {
1370 mIsTelevision = isTelevision;
1371 }
1372
Julia Reynolds76c096d2017-06-19 08:16:04 -04001373 @VisibleForTesting
1374 void setUsageStats(NotificationUsageStats us) {
1375 mUsageStats = us;
1376 }
1377
Julia Reynolds94187562017-10-10 13:58:49 -04001378 @VisibleForTesting
1379 void setAccessibilityManager(AccessibilityManager am) {
1380 mAccessibilityManager = am;
1381 }
1382
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001383 // TODO: All tests should use this init instead of the one-off setters above.
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001384 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001385 void init(Looper looper, IPackageManager packageManager,
1386 PackageManager packageManagerClient,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001387 LightsManager lightsManager, NotificationListeners notificationListeners,
Julia Reynoldsb852e562017-06-06 16:14:18 -04001388 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001389 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
Julia Reynolds68263d12017-06-21 14:21:19 -04001390 NotificationUsageStats usageStats, AtomicFile policyFile,
Julia Reynolds7217dc92018-03-07 12:12:09 -05001391 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001392 UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04001393 IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps) {
Chris Wren54bbef42014-07-09 18:37:56 -04001394 Resources resources = getContext().getResources();
Chris Wren763a9bb2016-05-31 17:14:12 -04001395 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1396 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1397 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1398
Julia Reynolds94187562017-10-10 13:58:49 -04001399 mAccessibilityManager =
1400 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001401 mAm = am;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001402 mUgm = ugm;
1403 mUgmInternal = ugmInternal;
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001404 mPackageManager = packageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001405 mPackageManagerClient = packageManagerClient;
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04001406 mAppOps = appOps;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001407 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Julia Reynolds7217dc92018-03-07 12:12:09 -05001408 mAppUsageStats = appUsageStats;
Julia Reynolds2a128742016-11-28 14:29:25 -05001409 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001410 mCompanionManager = companionManager;
Julia Reynolds68263d12017-06-21 14:21:19 -04001411 mActivityManager = activityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -08001412 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1413 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
Jason Parks50322ff2018-03-27 10:23:33 -05001414 mDpm = dpm;
1415
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001416 mHandler = new WorkerHandler(looper);
Chris Wrenf9536642014-04-17 10:01:54 -04001417 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -04001418 String[] extractorNames;
1419 try {
1420 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1421 } catch (Resources.NotFoundException e) {
1422 extractorNames = new String[0];
1423 }
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001424 mUsageStats = usageStats;
Kenny Guy23991102018-04-05 21:18:38 +01001425 mMetricsLogger = new MetricsLogger();
Chris Wren51017d02015-12-15 15:34:46 -05001426 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Julia Reynoldsb852e562017-06-06 16:14:18 -04001427 mConditionProviders = conditionProviders;
John Spurlockb2278d62015-04-07 12:47:12 -04001428 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -04001429 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -04001430 @Override
1431 public void onConfigChanged() {
1432 savePolicyFile();
1433 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001434
1435 @Override
1436 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001437 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -05001438 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -05001439 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1440 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -05001441 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001442 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02001443 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001444 }
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001445 mRankingHandler.requestSort();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001446 }
John Spurlock1fc476d2015-04-14 16:05:20 -04001447
1448 @Override
1449 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001450 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001451 mRankingHandler.requestSort();
John Spurlock80774932015-05-07 17:38:50 -04001452 }
John Spurlock056c5192014-04-20 21:52:01 -04001453 });
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001454 mPreferencesHelper = new PreferencesHelper(getContext(),
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001455 mPackageManagerClient,
1456 mRankingHandler,
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001457 mZenModeHelper);
1458 mRankingHelper = new RankingHelper(getContext(),
1459 mRankingHandler,
1460 mPreferencesHelper,
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001461 mZenModeHelper,
1462 mUsageStats,
1463 extractorNames);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001464 mSnoozeHelper = snoozeHelper;
Julia Reynolds8aebf352017-06-26 11:35:33 -04001465 mGroupHelper = groupHelper;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04001466
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001467 // This is a ManagedServices object that keeps track of the listeners.
1468 mListeners = notificationListeners;
Chris Wren0efdb882016-03-01 17:17:47 -05001469
Julia Reynolds77b2cc92016-11-08 14:41:09 -05001470 // This is a MangedServices object that keeps track of the assistant.
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001471 mAssistants = notificationAssistants;
Julia Reynoldsb852e562017-06-06 16:14:18 -04001472
Kristian Monsen30f59b22018-04-09 10:27:16 +02001473 // Needs to be set before loadPolicyFile
1474 mAllowedManagedServicePackages = this::canUseManagedServices;
1475
Julia Reynoldsb852e562017-06-06 16:14:18 -04001476 mPolicyFile = policyFile;
1477 loadPolicyFile();
Chris Wren0efdb882016-03-01 17:17:47 -05001478
Adam Lesinski182f73f2013-12-05 16:48:06 -08001479 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -08001480 if (mStatusBar != null) {
1481 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1482 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001484 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1485 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001486
Daniel Sandleredbb3802012-11-13 20:49:47 -08001487 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001488 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001489 VIBRATE_PATTERN_MAXLEN,
1490 DEFAULT_VIBRATE_PATTERN);
Beverly5d463b62017-07-26 14:13:40 -04001491 mInCallNotificationUri = Uri.parse("file://" +
1492 resources.getString(R.string.config_inCallNotificationSound));
1493 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1494 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1495 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
Beverly5d463b62017-07-26 14:13:40 -04001496 .build();
1497 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1498
Chris Wren5116a822014-06-04 15:59:50 -04001499 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
Julia Reynolds28149f62018-07-03 10:43:35 -04001500 mHasLight =
1501 resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
Chris Wren5116a822014-06-04 15:59:50 -04001502
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001503 // Don't start allowing notifications until the setup wizard has run once.
1504 // After that, including subsequent boots, init with notifications turned on.
1505 // This works on the first boot because the setup wizard will toggle this
1506 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001507 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001508 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001509 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001510 }
John Spurlockb2278d62015-04-07 12:47:12 -04001511 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001512 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001513
John Spurlockb408e8e2014-04-23 21:12:45 -04001514 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001515 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001516
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001517 mSettingsObserver = new SettingsObserver(mHandler);
1518
1519 mArchive = new Archive(resources.getInteger(
1520 R.integer.config_notificationServiceArchiveSize));
1521
1522 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1523 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1524 }
1525
1526 @Override
1527 public void onStart() {
1528 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1529 @Override
1530 public void repost(int userId, NotificationRecord r) {
1531 try {
1532 if (DBG) {
1533 Slog.d(TAG, "Reposting " + r.getKey());
1534 }
1535 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1536 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1537 r.sbn.getNotification(), userId);
1538 } catch (Exception e) {
1539 Slog.e(TAG, "Cannot un-snooze notification", e);
1540 }
1541 }
1542 }, mUserProfiles);
1543
1544 final File systemDir = new File(Environment.getDataDirectory(), "system");
1545
1546 init(Looper.myLooper(),
1547 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1548 getLocalService(LightsManager.class),
1549 new NotificationListeners(AppGlobals.getPackageManager()),
Julia Reynolds7380d872018-01-12 10:28:26 -05001550 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
1551 AppGlobals.getPackageManager()),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001552 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1553 null, snoozeHelper, new NotificationUsageStats(getContext()),
Dianne Hackborne17b4452018-01-10 13:15:40 -08001554 new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001555 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
Julia Reynolds7217dc92018-03-07 12:12:09 -05001556 getGroupHelper(), ActivityManager.getService(),
Jason Parks50322ff2018-03-27 10:23:33 -05001557 LocalServices.getService(UsageStatsManagerInternal.class),
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001558 LocalServices.getService(DevicePolicyManagerInternal.class),
1559 UriGrantsManager.getService(),
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04001560 LocalServices.getService(UriGrantsManagerInternal.class),
1561 (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE));
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001562
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001563 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001565 filter.addAction(Intent.ACTION_SCREEN_ON);
1566 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001567 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001568 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001569 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001570 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001571 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001572 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001573 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001574 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001575 getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
Kenny Guy70058402014-10-28 20:45:06 +00001576
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001577 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001578 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001579 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001580 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001581 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1582 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1583 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001584 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1585 null);
1586
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001587 IntentFilter suspendedPkgFilter = new IntentFilter();
1588 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
Beverly5a20a5e2018-03-06 15:02:44 -05001589 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001590 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1591 suspendedPkgFilter, null, null);
1592
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001593 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001594 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1595 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001596
Julia Reynolds2a128742016-11-28 14:29:25 -05001597 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1598 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1599 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1600
Julia Reynoldsb852e562017-06-06 16:14:18 -04001601 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1602 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1603
Beverlyd4f96492017-08-02 13:36:11 -04001604 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1605 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1606
Vishnu Naire3e4d252018-03-01 11:26:57 -08001607 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
1608 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001609 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001610 }
1611
Julia Reynolds8aebf352017-06-26 11:35:33 -04001612 private GroupHelper getGroupHelper() {
Adora Zhang48dd614a82018-06-25 19:18:41 -07001613 mAutoGroupAtCount =
1614 getContext().getResources().getInteger(R.integer.config_autoGroupAtCount);
1615 return new GroupHelper(mAutoGroupAtCount, new GroupHelper.Callback() {
Julia Reynolds8aebf352017-06-26 11:35:33 -04001616 @Override
1617 public void addAutoGroup(String key) {
1618 synchronized (mNotificationLock) {
1619 addAutogroupKeyLocked(key);
1620 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001621 }
1622
1623 @Override
1624 public void removeAutoGroup(String key) {
1625 synchronized (mNotificationLock) {
1626 removeAutogroupKeyLocked(key);
1627 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001628 }
1629
1630 @Override
1631 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1632 createAutoGroupSummary(userId, pkg, triggeringKey);
1633 }
1634
1635 @Override
1636 public void removeAutoGroupSummary(int userId, String pkg) {
1637 synchronized (mNotificationLock) {
1638 clearAutogroupSummaryLocked(userId, pkg);
1639 }
1640 }
1641 });
1642 }
1643
John Spurlocke7a835b2015-05-13 10:47:05 -04001644 private void sendRegisteredOnlyBroadcast(String action) {
1645 getContext().sendBroadcastAsUser(new Intent(action)
1646 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1647 }
1648
Adam Lesinski182f73f2013-12-05 16:48:06 -08001649 @Override
1650 public void onBootPhase(int phase) {
1651 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1652 // no beeping until we're basically done booting
1653 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001654
Adam Lesinski182f73f2013-12-05 16:48:06 -08001655 // Grab our optional AudioService
1656 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001657 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001658 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001659 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001660 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1661 // This observer will force an update when observe is called, causing us to
1662 // bind to listener services.
1663 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001664 mListeners.onBootPhaseAppsCanStart();
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001665 mAssistants.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001666 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 }
1668 }
1669
Julia Reynolds88860ce2017-06-01 16:55:49 -04001670 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04001671 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001672 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001673 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001674 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001675 mListenerHints = hints;
1676 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001677 }
1678
Julia Reynolds88860ce2017-06-01 16:55:49 -04001679 @GuardedBy("mNotificationLock")
John Spurlockb4782522014-08-22 14:54:46 -04001680 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001681 final long updatedSuppressedEffects = calculateSuppressedEffects();
1682 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1683 final List<ComponentName> suppressors = getSuppressors();
1684 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1685 mEffectsSuppressors = suppressors;
1686 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001687 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001688 }
1689
Amith Yamasani396a10c2018-01-19 10:58:07 -08001690 private void exitIdle() {
1691 try {
1692 if (mDeviceIdleController != null) {
1693 mDeviceIdleController.exitIdle("notification interaction");
1694 }
1695 } catch (RemoteException e) {
1696 }
1697 }
1698
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001699 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1700 boolean fromListener) {
Julia Reynolds924eed12017-01-19 09:52:07 -05001701 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1702 // cancel
1703 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001704 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
Julia Reynolds924eed12017-01-19 09:52:07 -05001705 null);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001706 if (isUidSystemOrPhone(uid)) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001707 IntArray profileIds = mUserProfiles.getCurrentProfileIds();
1708 int N = profileIds.size();
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001709 for (int i = 0; i < N; i++) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001710 int profileId = profileIds.get(i);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001711 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1712 profileId, REASON_CHANNEL_BANNED,
1713 null);
1714 }
1715 }
Julia Reynolds924eed12017-01-19 09:52:07 -05001716 }
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001717 final NotificationChannel preUpdate =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001718 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001719
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001720 mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001721 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
Julia Reynolds924eed12017-01-19 09:52:07 -05001722
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001723 if (!fromListener) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001724 final NotificationChannel modifiedChannel =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001725 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001726 mListeners.notifyNotificationChannelChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001727 pkg, UserHandle.getUserHandleForUid(uid),
1728 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001729 }
1730
Julia Reynolds924eed12017-01-19 09:52:07 -05001731 savePolicyFile();
1732 }
1733
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001734 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1735 NotificationChannel update) {
1736 try {
1737 if ((preUpdate.getImportance() == IMPORTANCE_NONE
1738 && update.getImportance() != IMPORTANCE_NONE)
1739 || (preUpdate.getImportance() != IMPORTANCE_NONE
1740 && update.getImportance() == IMPORTANCE_NONE)) {
1741 getContext().sendBroadcastAsUser(
1742 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001743 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001744 update.getId())
1745 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1746 update.getImportance() == IMPORTANCE_NONE)
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 channel change", e);
1753 }
1754 }
1755
Julia Reynolds005c8b92017-08-24 10:35:53 -04001756 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
1757 boolean fromApp, boolean fromListener) {
1758 Preconditions.checkNotNull(group);
1759 Preconditions.checkNotNull(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001760
1761 final NotificationChannelGroup preUpdate =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001762 mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
1763 mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group,
Julia Reynolds005c8b92017-08-24 10:35:53 -04001764 fromApp);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001765 if (!fromApp) {
1766 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
1767 }
Julia Reynolds005c8b92017-08-24 10:35:53 -04001768 if (!fromListener) {
1769 mListeners.notifyNotificationChannelGroupChanged(pkg,
1770 UserHandle.of(UserHandle.getCallingUserId()), group,
1771 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1772 }
1773 }
1774
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001775 private void maybeNotifyChannelGroupOwner(String pkg, int uid,
1776 NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
1777 try {
1778 if (preUpdate.isBlocked() != update.isBlocked()) {
1779 getContext().sendBroadcastAsUser(
1780 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001781 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001782 update.getId())
1783 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1784 update.isBlocked())
1785 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1786 .setPackage(pkg),
1787 UserHandle.of(UserHandle.getUserId(uid)), null);
1788 }
1789 } catch (SecurityException e) {
1790 Slog.w(TAG, "Can't notify app about group change", e);
1791 }
1792 }
1793
Bryce Lee7219ada2016-04-08 10:54:23 -07001794 private ArrayList<ComponentName> getSuppressors() {
1795 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1796 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04001797 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07001798
Julia Reynolds4703bac2018-09-12 10:39:30 -04001799 for (ComponentName info : serviceInfoList) {
1800 names.add(info);
Bryce Lee7219ada2016-04-08 10:54:23 -07001801 }
1802 }
1803
1804 return names;
1805 }
1806
1807 private boolean removeDisabledHints(ManagedServiceInfo info) {
1808 return removeDisabledHints(info, 0);
1809 }
1810
1811 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1812 boolean removed = false;
1813
1814 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1815 final int hint = mListenersDisablingEffects.keyAt(i);
Julia Reynolds4703bac2018-09-12 10:39:30 -04001816 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07001817
1818 if (hints == 0 || (hint & hints) == hint) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04001819 removed |= listeners.remove(info.component);
Bryce Lee7219ada2016-04-08 10:54:23 -07001820 }
1821 }
1822
1823 return removed;
1824 }
1825
1826 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1827 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1828 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1829 }
1830
1831 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1832 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1833 }
1834
1835 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1836 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1837 }
1838 }
1839
1840 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1841 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04001842 mListenersDisablingEffects.put(hint, new ArraySet<>());
Bryce Lee7219ada2016-04-08 10:54:23 -07001843 }
1844
Julia Reynolds4703bac2018-09-12 10:39:30 -04001845 ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint);
1846 hintListeners.add(info.component);
Bryce Lee7219ada2016-04-08 10:54:23 -07001847 }
1848
1849 private int calculateHints() {
1850 int hints = 0;
1851 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1852 int hint = mListenersDisablingEffects.keyAt(i);
Julia Reynolds4703bac2018-09-12 10:39:30 -04001853 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07001854
1855 if (!serviceInfoList.isEmpty()) {
1856 hints |= hint;
1857 }
1858 }
1859
1860 return hints;
1861 }
1862
1863 private long calculateSuppressedEffects() {
1864 int hints = calculateHints();
1865 long suppressedEffects = 0;
1866
1867 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1868 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1869 }
1870
1871 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1872 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1873 }
1874
1875 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1876 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1877 }
1878
1879 return suppressedEffects;
1880 }
1881
Julia Reynolds88860ce2017-06-01 16:55:49 -04001882 @GuardedBy("mNotificationLock")
Christoph Studer85a384b2014-08-27 20:16:15 +02001883 private void updateInterruptionFilterLocked() {
1884 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1885 if (interruptionFilter == mInterruptionFilter) return;
1886 mInterruptionFilter = interruptionFilter;
1887 scheduleInterruptionFilterChanged(interruptionFilter);
1888 }
1889
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001890 @VisibleForTesting
1891 INotificationManager getBinderService() {
1892 return INotificationManager.Stub.asInterface(mService);
1893 }
1894
Amith Yamasani7ec89412018-02-07 08:48:49 -08001895 /**
1896 * Report to usage stats that the notification was seen.
1897 * @param r notification record
1898 */
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001899 @GuardedBy("mNotificationLock")
Amith Yamasani803eab692017-11-09 17:47:04 -08001900 protected void reportSeen(NotificationRecord r) {
Amith Yamasani803eab692017-11-09 17:47:04 -08001901 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001902 getRealUserId(r.sbn.getUserId()),
Amith Yamasani803eab692017-11-09 17:47:04 -08001903 UsageEvents.Event.NOTIFICATION_SEEN);
1904 }
1905
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001906 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
1907 int targetSdkVersion) {
1908 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
1909 return incomingPolicy.suppressedVisualEffects;
1910 }
1911 final int[] effectsIntroducedInP = {
1912 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
1913 SUPPRESSED_EFFECT_LIGHTS,
1914 SUPPRESSED_EFFECT_PEEK,
1915 SUPPRESSED_EFFECT_STATUS_BAR,
1916 SUPPRESSED_EFFECT_BADGE,
1917 SUPPRESSED_EFFECT_AMBIENT,
1918 SUPPRESSED_EFFECT_NOTIFICATION_LIST
1919 };
1920
1921 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06001922 if (targetSdkVersion < Build.VERSION_CODES.P) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001923 // unset higher order bits introduced in P, maintain the user's higher order bits
1924 for (int i = 0; i < effectsIntroducedInP.length ; i++) {
1925 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
1926 newSuppressedVisualEffects |=
1927 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
1928 }
1929 // set higher order bits according to lower order bits
1930 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1931 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1932 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001933 }
1934 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1935 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1936 }
1937 } else {
1938 boolean hasNewEffects = (newSuppressedVisualEffects
1939 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
1940 // if any of the new effects introduced in P are set
1941 if (hasNewEffects) {
1942 // clear out the deprecated effects
1943 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
1944 | SUPPRESSED_EFFECT_SCREEN_OFF);
1945
1946 // set the deprecated effects according to the new more specific effects
1947 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
1948 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
1949 }
1950 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
1951 && (newSuppressedVisualEffects
1952 & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
1953 && (newSuppressedVisualEffects
1954 & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
1955 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
1956 }
1957 } else {
1958 // set higher order bits according to lower order bits
1959 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1960 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1961 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
1962 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
1963 }
1964 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1965 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1966 }
1967 }
1968 }
1969
1970 return newSuppressedVisualEffects;
1971 }
1972
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001973 @GuardedBy("mNotificationLock")
1974 protected void maybeRecordInterruptionLocked(NotificationRecord r) {
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04001975 if (r.isInterruptive() && !r.hasRecordedInterruption()) {
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001976 mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
1977 r.getChannel().getId(),
1978 getRealUserId(r.sbn.getUserId()));
Julia Reynoldsad7d7132018-03-21 16:05:00 -04001979 logRecentLocked(r);
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04001980 r.setRecordedInterruption(true);
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001981 }
1982 }
1983
Amith Yamasani7ec89412018-02-07 08:48:49 -08001984 /**
1985 * Report to usage stats that the notification was clicked.
1986 * @param r notification record
1987 */
1988 protected void reportUserInteraction(NotificationRecord r) {
Amith Yamasani7ec89412018-02-07 08:48:49 -08001989 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001990 getRealUserId(r.sbn.getUserId()),
Amith Yamasani7ec89412018-02-07 08:48:49 -08001991 UsageEvents.Event.USER_INTERACTION);
1992 }
1993
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001994 private int getRealUserId(int userId) {
1995 return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
1996 }
1997
Geoffrey Pitsch415e4542017-04-10 13:12:58 -04001998 @VisibleForTesting
1999 NotificationManagerInternal getInternalService() {
2000 return mInternalService;
2001 }
2002
Beverly58b24532018-10-02 09:08:23 -04002003 @VisibleForTesting
2004 final IBinder mService = new INotificationManager.Stub() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002005 // Toasts
2006 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002008 @Override
Jeff Chang48ecef42018-08-09 16:31:59 +08002009 public void enqueueToast(String pkg, ITransientNotification callback, int duration,
2010 int displayId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002011 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002012 if (DBG) {
2013 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
Jeff Chang48ecef42018-08-09 16:31:59 +08002014 + " duration=" + duration + " displayId=" + displayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002015 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002016
2017 if (pkg == null || callback == null) {
Beverly58b24532018-10-02 09:08:23 -04002018 Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " callback=" + callback);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002019 return ;
2020 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002021
Beverly58b24532018-10-02 09:08:23 -04002022 final int callingUid = Binder.getCallingUid();
2023 final boolean isSystemToast = isCallerSystemOrPhone()
2024 || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg);
2025 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
2026 final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg,
2027 callingUid);
2028
2029 long callingIdentity = Binder.clearCallingIdentity();
2030 try {
2031 final boolean appIsForeground = mActivityManager.getUidImportance(callingUid)
2032 == IMPORTANCE_FOREGROUND;
2033 if (ENABLE_BLOCKED_TOASTS && !isSystemToast && ((notificationsDisabledForPackage
2034 && !appIsForeground) || isPackageSuspended)) {
2035 Slog.e(TAG, "Suppressing toast from package " + pkg
2036 + (isPackageSuspended ? " due to package suspended."
2037 : " by user request."));
2038 return;
2039 }
2040 } finally {
2041 Binder.restoreCallingIdentity(callingIdentity);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002042 }
2043
2044 synchronized (mToastQueue) {
2045 int callingPid = Binder.getCallingPid();
2046 long callingId = Binder.clearCallingIdentity();
2047 try {
2048 ToastRecord record;
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002049 int index = indexOfToastLocked(pkg, callback);
2050 // If it's already in the queue, we update it in place, we don't
2051 // move it to the end of the queue.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002052 if (index >= 0) {
2053 record = mToastQueue.get(index);
2054 record.update(duration);
2055 } else {
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002056 // Limit the number of toasts that any given package except the android
2057 // package can enqueue. Prevents DOS attacks and deals with leaks.
2058 if (!isSystemToast) {
2059 int count = 0;
2060 final int N = mToastQueue.size();
2061 for (int i=0; i<N; i++) {
2062 final ToastRecord r = mToastQueue.get(i);
2063 if (r.pkg.equals(pkg)) {
2064 count++;
2065 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2066 Slog.e(TAG, "Package has already posted " + count
2067 + " toasts. Not showing more. Package=" + pkg);
2068 return;
2069 }
2070 }
2071 }
2072 }
2073
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002074 Binder token = new Binder();
Jeff Chang48ecef42018-08-09 16:31:59 +08002075 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, displayId);
2076 record = new ToastRecord(callingPid, pkg, callback, duration, token,
2077 displayId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002078 mToastQueue.add(record);
2079 index = mToastQueue.size() - 1;
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002080 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002081 }
2082 // If it's at index 0, it's the current toast. It doesn't matter if it's
2083 // new or just been updated. Call back and tell it to show itself.
2084 // If the callback fails, this will remove it from the list, so don't
2085 // assume that it's valid after this.
2086 if (index == 0) {
2087 showNextToastLocked();
2088 }
2089 } finally {
2090 Binder.restoreCallingIdentity(callingId);
2091 }
2092 }
2093 }
2094
2095 @Override
2096 public void cancelToast(String pkg, ITransientNotification callback) {
2097 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
2098
2099 if (pkg == null || callback == null) {
2100 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
2101 return ;
2102 }
2103
2104 synchronized (mToastQueue) {
2105 long callingId = Binder.clearCallingIdentity();
2106 try {
2107 int index = indexOfToastLocked(pkg, callback);
2108 if (index >= 0) {
2109 cancelToastLocked(index);
2110 } else {
2111 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
2112 + " callback=" + callback);
2113 }
2114 } finally {
2115 Binder.restoreCallingIdentity(callingId);
2116 }
2117 }
2118 }
2119
2120 @Override
Robert Carr997427342018-02-28 18:06:10 -08002121 public void finishToken(String pkg, ITransientNotification callback) {
2122 synchronized (mToastQueue) {
2123 long callingId = Binder.clearCallingIdentity();
2124 try {
2125 int index = indexOfToastLocked(pkg, callback);
2126 if (index >= 0) {
2127 ToastRecord record = mToastQueue.get(index);
Jeff Chang48ecef42018-08-09 16:31:59 +08002128 finishTokenLocked(record.token, record.displayId);
Robert Carr997427342018-02-28 18:06:10 -08002129 } else {
2130 Slog.w(TAG, "Toast already killed. pkg=" + pkg
2131 + " callback=" + callback);
2132 }
2133 } finally {
2134 Binder.restoreCallingIdentity(callingId);
2135 }
2136 }
2137 }
2138
2139 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002140 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002141 Notification notification, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002142 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002143 Binder.getCallingPid(), tag, id, notification, userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002144 }
2145
2146 @Override
2147 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002148 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002149 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2150 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002151 // Don't allow client applications to cancel foreground service notis or autobundled
2152 // summaries.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002153 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
Julia Reynoldse5c60452018-04-30 14:41:36 -04002154 (FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
John Spurlocke6a7d932014-03-13 12:29:00 -04002155 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002156 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002157 }
2158
2159 @Override
2160 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002161 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002162
2163 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2164 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
2165
2166 // Calling from user space, don't allow the canceling of actively
2167 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04002168 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
Julia Reynoldse5c60452018-04-30 14:41:36 -04002169 pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05002170 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002171 }
2172
2173 @Override
2174 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
Rohan Shahca0447e2018-03-30 15:18:27 -07002175 enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002176
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002177 mPreferencesHelper.setEnabled(pkg, uid, enabled);
Howard Ro8b56f752018-08-07 15:44:25 -07002178 mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
2179 .setType(MetricsEvent.TYPE_ACTION)
2180 .setPackageName(pkg)
2181 .setSubtype(enabled ? 1 : 0));
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002182 // Now, cancel any outstanding notifications that are part of a just-disabled app
Julia Reynolds4da79702017-06-01 11:06:10 -04002183 if (!enabled) {
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002184 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
2185 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
2186 }
Julia Reynoldsfc9767b2018-01-22 17:45:16 -05002187
2188 try {
2189 getContext().sendBroadcastAsUser(
2190 new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
2191 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
2192 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2193 .setPackage(pkg),
2194 UserHandle.of(UserHandle.getUserId(uid)), null);
2195 } catch (SecurityException e) {
2196 Slog.w(TAG, "Can't notify app about app block change", e);
2197 }
2198
Chris Wrenacf424a2016-03-15 12:48:55 -04002199 savePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002200 }
2201
2202 /**
Rohan Shah590e1b22018-04-10 23:48:47 -04002203 * Updates the enabled state for notifications for the given package (and uid).
2204 * Additionally, this method marks the app importance as locked by the user, which means
2205 * that notifications from the app will <b>not</b> be considered for showing a
2206 * blocking helper.
2207 *
2208 * @param pkg package that owns the notifications to update
2209 * @param uid uid of the app providing notifications
2210 * @param enabled whether notifications should be enabled for the app
2211 *
2212 * @see #setNotificationsEnabledForPackage(String, int, boolean)
2213 */
2214 @Override
2215 public void setNotificationsEnabledWithImportanceLockForPackage(
2216 String pkg, int uid, boolean enabled) {
2217 setNotificationsEnabledForPackage(pkg, uid, enabled);
2218
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002219 mPreferencesHelper.setAppImportanceLocked(pkg, uid);
Rohan Shah590e1b22018-04-10 23:48:47 -04002220 }
2221
2222 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002223 * Use this when you just want to know if notifications are OK for this package.
2224 */
2225 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002226 public boolean areNotificationsEnabled(String pkg) {
2227 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
2228 }
2229
2230 /**
2231 * Use this when you just want to know if notifications are OK for this package.
2232 */
2233 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002234 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002235 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002236
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002237 return mPreferencesHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002238 }
2239
Chris Wren54bbef42014-07-09 18:37:56 -04002240 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05002241 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002242 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002243 return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002244 }
2245
2246 @Override
Julia Reynolds924eed12017-01-19 09:52:07 -05002247 public boolean canShowBadge(String pkg, int uid) {
2248 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002249 return mPreferencesHelper.canShowBadge(pkg, uid);
Julia Reynolds924eed12017-01-19 09:52:07 -05002250 }
2251
2252 @Override
2253 public void setShowBadge(String pkg, int uid, boolean showBadge) {
2254 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002255 mPreferencesHelper.setShowBadge(pkg, uid, showBadge);
Julia Reynolds924eed12017-01-19 09:52:07 -05002256 savePolicyFile();
2257 }
2258
2259 @Override
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002260 public void setNotificationDelegate(String callingPkg, String delegate) {
2261 checkCallerIsSameApp(callingPkg);
2262 final int callingUid = Binder.getCallingUid();
2263 UserHandle user = UserHandle.getUserHandleForUid(callingUid);
2264 try {
2265 ApplicationInfo info =
2266 mPackageManager.getApplicationInfo(delegate,
2267 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
2268 user.getIdentifier());
2269 if (info != null) {
2270 mPreferencesHelper.setNotificationDelegate(
2271 callingPkg, callingUid, delegate, info.uid);
2272 savePolicyFile();
2273 }
2274 } catch (RemoteException e) {
2275 // :(
2276 }
2277 }
2278
2279 @Override
2280 public void revokeNotificationDelegate(String callingPkg) {
2281 checkCallerIsSameApp(callingPkg);
2282 mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid());
2283 savePolicyFile();
2284 }
2285
2286 @Override
2287 public String getNotificationDelegate(String callingPkg) {
2288 // callable by Settings also
2289 checkCallerIsSystemOrSameApp(callingPkg);
2290 return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid());
2291 }
2292
2293 @Override
2294 public boolean canNotifyAsPackage(String callingPkg, String targetPkg) {
2295 checkCallerIsSameApp(callingPkg);
2296 final int callingUid = Binder.getCallingUid();
2297 UserHandle user = UserHandle.getUserHandleForUid(callingUid);
2298 try {
2299 ApplicationInfo info =
2300 mPackageManager.getApplicationInfo(targetPkg,
2301 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
2302 user.getIdentifier());
2303 if (info != null) {
2304 return mPreferencesHelper.isDelegateAllowed(
2305 targetPkg, info.uid, callingPkg, callingUid);
2306 }
2307 } catch (RemoteException e) {
2308 // :(
2309 }
2310 return false;
2311 }
2312
2313 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002314 public void updateNotificationChannelGroupForPackage(String pkg, int uid,
2315 NotificationChannelGroup group) throws RemoteException {
2316 enforceSystemOrSystemUI("Caller not system or systemui");
2317 createNotificationChannelGroup(pkg, uid, group, false, false);
2318 savePolicyFile();
2319 }
2320
2321 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002322 public void createNotificationChannelGroups(String pkg,
2323 ParceledListSlice channelGroupList) throws RemoteException {
2324 checkCallerIsSystemOrSameApp(pkg);
2325 List<NotificationChannelGroup> groups = channelGroupList.getList();
2326 final int groupSize = groups.size();
2327 for (int i = 0; i < groupSize; i++) {
2328 final NotificationChannelGroup group = groups.get(i);
Julia Reynolds005c8b92017-08-24 10:35:53 -04002329 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002330 }
2331 savePolicyFile();
2332 }
2333
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002334 private void createNotificationChannelsImpl(String pkg, int uid,
2335 ParceledListSlice channelsList) {
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002336 List<NotificationChannel> channels = channelsList.getList();
2337 final int channelsSize = channels.size();
2338 for (int i = 0; i < channelsSize; i++) {
2339 final NotificationChannel channel = channels.get(i);
2340 Preconditions.checkNotNull(channel, "channel in list is null");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002341 mPreferencesHelper.createNotificationChannel(pkg, uid, channel,
Julia Reynolds1fe10942018-03-28 12:46:51 -04002342 true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed(
2343 pkg, UserHandle.getUserId(uid)));
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002344 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002345 UserHandle.getUserHandleForUid(uid),
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002346 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002347 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002348 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002349 savePolicyFile();
2350 }
2351
2352 @Override
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002353 public void createNotificationChannels(String pkg,
2354 ParceledListSlice channelsList) throws RemoteException {
2355 checkCallerIsSystemOrSameApp(pkg);
2356 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
2357 }
2358
2359 @Override
2360 public void createNotificationChannelsForPackage(String pkg, int uid,
2361 ParceledListSlice channelsList) throws RemoteException {
2362 checkCallerIsSystem();
2363 createNotificationChannelsImpl(pkg, uid, channelsList);
2364 }
2365
2366 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002367 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002368 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002369 return mPreferencesHelper.getNotificationChannel(
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002370 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002371 }
2372
2373 @Override
2374 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002375 String channelId, boolean includeDeleted) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002376 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002377 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002378 }
2379
2380 @Override
2381 public void deleteNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002382 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002383 final int callingUid = Binder.getCallingUid();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002384 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
2385 throw new IllegalArgumentException("Cannot delete default channel");
2386 }
2387 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002388 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002389 mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002390 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002391 UserHandle.getUserHandleForUid(callingUid),
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002392 mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002393 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002394 savePolicyFile();
2395 }
2396
2397 @Override
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002398 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
2399 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002400 return mPreferencesHelper.getNotificationChannelGroupWithChannels(
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002401 pkg, Binder.getCallingUid(), groupId, false);
2402 }
2403
2404 @Override
Julia Reynolds9bfba592017-03-15 14:03:55 -04002405 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
2406 String pkg) {
2407 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002408 return mPreferencesHelper.getNotificationChannelGroups(
Julia Reynolds13ed28b2018-09-21 15:20:13 -04002409 pkg, Binder.getCallingUid(), false, false, true);
Julia Reynolds9bfba592017-03-15 14:03:55 -04002410 }
2411
2412 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002413 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04002414 checkCallerIsSystemOrSameApp(pkg);
2415
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002416 final int callingUid = Binder.getCallingUid();
2417 NotificationChannelGroup groupToDelete =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002418 mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002419 if (groupToDelete != null) {
2420 List<NotificationChannel> deletedChannels =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002421 mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002422 for (int i = 0; i < deletedChannels.size(); i++) {
2423 final NotificationChannel deletedChannel = deletedChannels.get(i);
2424 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2425 true,
2426 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2427 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002428 mListeners.notifyNotificationChannelChanged(pkg,
2429 UserHandle.getUserHandleForUid(callingUid),
2430 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002431 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2432 }
2433 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002434 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2435 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002436 savePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002437 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04002438 }
2439
2440 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002441 public void updateNotificationChannelForPackage(String pkg, int uid,
2442 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002443 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05002444 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002445 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002446 }
2447
2448 @Override
2449 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002450 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002451 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002452 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002453 }
2454
2455 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002456 public int getNumNotificationChannelsForPackage(String pkg, int uid,
2457 boolean includeDeleted) {
2458 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002459 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted)
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002460 .getList().size();
2461 }
2462
2463 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04002464 public boolean onlyHasDefaultChannel(String pkg, int uid) {
2465 enforceSystemOrSystemUI("onlyHasDefaultChannel");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002466 return mPreferencesHelper.onlyHasDefaultChannel(pkg, uid);
Julia Reynolds17717f52017-05-09 11:46:06 -04002467 }
2468
2469 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04002470 public int getDeletedChannelCount(String pkg, int uid) {
2471 enforceSystemOrSystemUI("getDeletedChannelCount");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002472 return mPreferencesHelper.getDeletedChannelCount(pkg, uid);
Julia Reynolds41103f42017-03-15 11:36:35 -04002473 }
2474
2475 @Override
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002476 public int getBlockedChannelCount(String pkg, int uid) {
2477 enforceSystemOrSystemUI("getBlockedChannelCount");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002478 return mPreferencesHelper.getBlockedChannelCount(pkg, uid);
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002479 }
2480
2481 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002482 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2483 String pkg, int uid, boolean includeDeleted) {
2484 checkCallerIsSystem();
Julia Reynolds13ed28b2018-09-21 15:20:13 -04002485 return mPreferencesHelper.getNotificationChannelGroups(
2486 pkg, uid, includeDeleted, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002487 }
2488
2489 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002490 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2491 String pkg, int uid, String groupId, boolean includeDeleted) {
2492 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002493 return mPreferencesHelper.getNotificationChannelGroupWithChannels(
Julia Reynolds005c8b92017-08-24 10:35:53 -04002494 pkg, uid, groupId, includeDeleted);
2495 }
2496
2497 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002498 public NotificationChannelGroup getNotificationChannelGroupForPackage(
2499 String groupId, String pkg, int uid) {
2500 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002501 return mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, uid);
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002502 }
2503
2504 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002505 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
2506 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002507 return mPreferencesHelper.getNotificationChannels(
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002508 pkg, Binder.getCallingUid(), false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002509 }
2510
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002511 @Override
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05002512 public ParceledListSlice<NotifyingApp> getRecentNotifyingAppsForUser(int userId) {
2513 checkCallerIsSystem();
2514 synchronized (mNotificationLock) {
2515 List<NotifyingApp> apps = new ArrayList<>(
2516 mRecentApps.getOrDefault(userId, new ArrayList<>()));
2517 return new ParceledListSlice<>(apps);
2518 }
2519 }
2520
2521 @Override
Julia Reynoldse273f082018-04-12 13:48:49 -04002522 public int getBlockedAppCount(int userId) {
2523 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002524 return mPreferencesHelper.getBlockedAppCount(userId);
Julia Reynoldse273f082018-04-12 13:48:49 -04002525 }
2526
2527 @Override
Beverly86d076f2018-04-17 14:44:52 -04002528 public boolean areChannelsBypassingDnd() {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002529 return mPreferencesHelper.areChannelsBypassingDnd();
Beverly86d076f2018-04-17 14:44:52 -04002530 }
2531
2532 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05002533 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002534 checkCallerIsSystem();
2535
2536 // Cancel posted notifications
2537 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2538 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2539
Julia Reynoldsb852e562017-06-06 16:14:18 -04002540 final String[] packages = new String[] {packageName};
2541 final int[] uids = new int[] {uid};
2542
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002543 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04002544 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002545 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002546
2547 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04002548 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002549
2550 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05002551 if (!fromApp) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002552 mPreferencesHelper.onPackagesChanged(
Julia Reynoldsb852e562017-06-06 16:14:18 -04002553 true, UserHandle.getCallingUserId(), packages, uids);
Julia Reynolds5355e852017-02-07 14:54:13 -05002554 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002555
2556 savePolicyFile();
2557 }
2558
2559
Adam Lesinski182f73f2013-12-05 16:48:06 -08002560 /**
2561 * System-only API for getting a list of current (i.e. not cleared) notifications.
2562 *
2563 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04002564 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002565 */
2566 @Override
2567 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2568 // enforce() will ensure the calling uid has the correct permission
2569 getContext().enforceCallingOrSelfPermission(
2570 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2571 "NotificationManagerService.getActiveNotifications");
2572
2573 StatusBarNotification[] tmp = null;
2574 int uid = Binder.getCallingUid();
2575
2576 // noteOp will check to make sure the callingPkg matches the uid
2577 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2578 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002579 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002580 tmp = new StatusBarNotification[mNotificationList.size()];
2581 final int N = mNotificationList.size();
2582 for (int i=0; i<N; i++) {
2583 tmp[i] = mNotificationList.get(i).sbn;
2584 }
2585 }
2586 }
2587 return tmp;
2588 }
2589
2590 /**
Dan Sandler994349c2015-04-15 11:02:54 -04002591 * Public API for getting a list of current notifications for the calling package/uid.
2592 *
Julia Reynolds573c6532017-01-24 17:44:38 -05002593 * Note that since notification posting is done asynchronously, this will not return
2594 * notifications that are in the process of being posted.
2595 *
Dan Sandler994349c2015-04-15 11:02:54 -04002596 * @returns A list of all the package's notifications, in natural order.
2597 */
2598 @Override
2599 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2600 int incomingUserId) {
2601 checkCallerIsSystemOrSameApp(pkg);
2602 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2603 Binder.getCallingUid(), incomingUserId, true, false,
2604 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002605 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002606 final ArrayMap<String, StatusBarNotification> map
2607 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002608 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002609 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002610 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2611 mNotificationList.get(i).sbn);
2612 if (sbn != null) {
2613 map.put(sbn.getKey(), sbn);
2614 }
2615 }
2616 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2617 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2618 if (sbn != null) {
2619 map.put(sbn.getKey(), sbn);
2620 }
2621 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002622 final int M = mEnqueuedNotifications.size();
2623 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002624 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2625 mEnqueuedNotifications.get(i).sbn);
2626 if (sbn != null) {
2627 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04002628 }
2629 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002630 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2631 list.addAll(map.values());
2632 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04002633 }
Dan Sandler994349c2015-04-15 11:02:54 -04002634 }
2635
Chris Wren6676dab2016-12-21 18:26:27 -05002636 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2637 StatusBarNotification sbn) {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04002638 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
Chris Wren6676dab2016-12-21 18:26:27 -05002639 // We could pass back a cloneLight() but clients might get confused and
2640 // try to send this thing back to notify() again, which would not work
2641 // very well.
2642 return new StatusBarNotification(
2643 sbn.getPackageName(),
2644 sbn.getOpPkg(),
Chris Wren6676dab2016-12-21 18:26:27 -05002645 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2646 sbn.getNotification().clone(),
2647 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2648 }
2649 return null;
2650 }
2651
Dan Sandler994349c2015-04-15 11:02:54 -04002652 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002653 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2654 *
2655 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2656 */
2657 @Override
2658 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2659 // enforce() will ensure the calling uid has the correct permission
2660 getContext().enforceCallingOrSelfPermission(
2661 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2662 "NotificationManagerService.getHistoricalNotifications");
2663
2664 StatusBarNotification[] tmp = null;
2665 int uid = Binder.getCallingUid();
2666
2667 // noteOp will check to make sure the callingPkg matches the uid
2668 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2669 == AppOpsManager.MODE_ALLOWED) {
2670 synchronized (mArchive) {
2671 tmp = mArchive.getArray(count);
2672 }
2673 }
2674 return tmp;
2675 }
2676
2677 /**
2678 * Register a listener binder directly with the notification manager.
2679 *
2680 * Only works with system callers. Apps should extend
2681 * {@link android.service.notification.NotificationListenerService}.
2682 */
2683 @Override
2684 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05002685 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02002686 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05002687 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002688 }
2689
2690 /**
2691 * Remove a listener binder directly
2692 */
2693 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002694 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05002695 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002696 }
2697
2698 /**
2699 * Allow an INotificationListener to simulate a "clear all" operation.
2700 *
2701 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2702 *
2703 * @param token The binder for the listener, to check that the caller is allowed
2704 */
2705 @Override
John Spurlocka4294292014-03-24 18:02:32 -04002706 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002707 final int callingUid = Binder.getCallingUid();
2708 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002709 long identity = Binder.clearCallingIdentity();
2710 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002711 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002712 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Beverly5a20a5e2018-03-06 15:02:44 -05002713
John Spurlocka4294292014-03-24 18:02:32 -04002714 if (keys != null) {
2715 final int N = keys.length;
2716 for (int i = 0; i < N; i++) {
2717 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07002718 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00002719 final int userId = r.sbn.getUserId();
2720 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04002721 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00002722 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04002723 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00002724 }
Griff Hazen335e1f02014-09-11 14:49:31 -07002725 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2726 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2727 userId);
John Spurlocka4294292014-03-24 18:02:32 -04002728 }
2729 } else {
2730 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00002731 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04002732 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002733 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002734 } finally {
2735 Binder.restoreCallingIdentity(identity);
2736 }
2737 }
2738
Chris Wrenab41eec2016-01-04 18:01:27 -05002739 /**
2740 * Handle request from an approved listener to re-enable itself.
2741 *
2742 * @param component The componenet to be re-enabled, caller must match package.
2743 */
2744 @Override
2745 public void requestBindListener(ComponentName component) {
2746 checkCallerIsSystemOrSameApp(component.getPackageName());
2747 long identity = Binder.clearCallingIdentity();
2748 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002749 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002750 mAssistants.isComponentEnabledForCurrentProfiles(component)
2751 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05002752 : mListeners;
2753 manager.setComponentState(component, true);
2754 } finally {
2755 Binder.restoreCallingIdentity(identity);
2756 }
2757 }
2758
2759 @Override
2760 public void requestUnbindListener(INotificationListener token) {
2761 long identity = Binder.clearCallingIdentity();
2762 try {
2763 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002764 synchronized (mNotificationLock) {
2765 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2766 info.getOwner().setComponentState(info.component, false);
2767 }
Chris Wrenab41eec2016-01-04 18:01:27 -05002768 } finally {
2769 Binder.restoreCallingIdentity(identity);
2770 }
2771 }
2772
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002773 @Override
2774 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002775 long identity = Binder.clearCallingIdentity();
2776 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002777 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002778 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04002779 if (keys == null) {
2780 return;
2781 }
2782 ArrayList<NotificationRecord> seen = new ArrayList<>();
2783 final int n = keys.length;
2784 for (int i = 0; i < n; i++) {
2785 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2786 if (r == null) continue;
2787 final int userId = r.sbn.getUserId();
2788 if (userId != info.userid && userId != UserHandle.USER_ALL
2789 && !mUserProfiles.isCurrentProfile(userId)) {
2790 throw new SecurityException("Disallowed call from listener: "
2791 + info.service);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002792 }
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04002793 seen.add(r);
2794 if (!r.isSeen()) {
2795 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2796 reportSeen(r);
2797 r.setSeen();
2798 maybeRecordInterruptionLocked(r);
2799 }
2800 }
2801 if (!seen.isEmpty()) {
2802 mAssistants.onNotificationsSeenLocked(seen);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002803 }
2804 }
2805 } finally {
2806 Binder.restoreCallingIdentity(identity);
2807 }
2808 }
2809
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002810 /**
2811 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2812 *
2813 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2814 *
Julia Reynolds79672302017-01-12 08:30:16 -05002815 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002816 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04002817 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04002818 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00002819 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04002820 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -04002821 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
John Spurlocka4294292014-03-24 18:02:32 -04002822 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00002823 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04002824 }
2825
Adam Lesinski182f73f2013-12-05 16:48:06 -08002826 /**
Julia Reynolds79672302017-01-12 08:30:16 -05002827 * Allow an INotificationListener to snooze a single notification until a context.
2828 *
2829 * @param token The binder for the listener, to check that the caller is allowed
2830 */
2831 @Override
2832 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2833 String key, String snoozeCriterionId) {
2834 long identity = Binder.clearCallingIdentity();
2835 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002836 synchronized (mNotificationLock) {
2837 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2838 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2839 }
Julia Reynolds79672302017-01-12 08:30:16 -05002840 } finally {
2841 Binder.restoreCallingIdentity(identity);
2842 }
2843 }
2844
2845 /**
2846 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002847 *
2848 * @param token The binder for the listener, to check that the caller is allowed
2849 */
2850 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002851 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05002852 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002853 long identity = Binder.clearCallingIdentity();
2854 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002855 synchronized (mNotificationLock) {
2856 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2857 snoozeNotificationInt(key, duration, null, info);
2858 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002859 } finally {
2860 Binder.restoreCallingIdentity(identity);
2861 }
2862 }
2863
2864 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002865 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002866 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002867 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002868 */
2869 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002870 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002871 long identity = Binder.clearCallingIdentity();
2872 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002873 synchronized (mNotificationLock) {
2874 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002875 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002876 unsnoozeNotificationInt(key, info);
2877 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002878 } finally {
2879 Binder.restoreCallingIdentity(identity);
2880 }
2881 }
2882
2883 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002884 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2885 *
2886 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2887 *
2888 * @param token The binder for the listener, to check that the caller is allowed
2889 */
2890 @Override
2891 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2892 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002893 final int callingUid = Binder.getCallingUid();
2894 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002895 long identity = Binder.clearCallingIdentity();
2896 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002897 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002898 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00002899 if (info.supportsProfiles()) {
2900 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2901 + "from " + info.component
2902 + " use cancelNotification(key) instead.");
2903 } else {
2904 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2905 pkg, tag, id, info.userid);
2906 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002907 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002908 } finally {
2909 Binder.restoreCallingIdentity(identity);
2910 }
2911 }
2912
2913 /**
2914 * Allow an INotificationListener to request the list of outstanding notifications seen by
2915 * the current user. Useful when starting up, after which point the listener callbacks
2916 * should be used.
2917 *
2918 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002919 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04002920 * @returns The return value will contain the notifications specified in keys, in that
2921 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002922 */
2923 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02002924 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02002925 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002926 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002927 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002928 final boolean getKeys = keys != null;
2929 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02002930 final ArrayList<StatusBarNotification> list
2931 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02002932 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002933 final NotificationRecord r = getKeys
2934 ? mNotificationsByKey.get(keys[i])
2935 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02002936 if (r == null) continue;
2937 StatusBarNotification sbn = r.sbn;
2938 if (!isVisibleToListener(sbn, info)) continue;
2939 StatusBarNotification sbnToSend =
2940 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2941 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002942 }
Christoph Studercee44ba2014-05-20 18:36:43 +02002943 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002944 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002945 }
2946
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002947 /**
2948 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2949 * seen by the current user. Useful when starting up, after which point the listener
2950 * callbacks should be used.
2951 *
2952 * @param token The binder for the listener, to check that the caller is allowed
2953 * @returns The return value will contain the notifications specified in keys, in that
2954 * order, or if keys is null, all the notifications, in natural order.
2955 */
2956 @Override
2957 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2958 INotificationListener token, int trim) {
2959 synchronized (mNotificationLock) {
2960 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2961 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2962 final int N = snoozedRecords.size();
2963 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2964 for (int i=0; i < N; i++) {
2965 final NotificationRecord r = snoozedRecords.get(i);
2966 if (r == null) continue;
2967 StatusBarNotification sbn = r.sbn;
2968 if (!isVisibleToListener(sbn, info)) continue;
2969 StatusBarNotification sbnToSend =
2970 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2971 list.add(sbnToSend);
2972 }
2973 return new ParceledListSlice<>(list);
2974 }
2975 }
2976
Adam Lesinski182f73f2013-12-05 16:48:06 -08002977 @Override
Julia Reynolds4703bac2018-09-12 10:39:30 -04002978 public void clearRequestedListenerHints(INotificationListener token) {
2979 final long identity = Binder.clearCallingIdentity();
2980 try {
2981 synchronized (mNotificationLock) {
2982 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2983 removeDisabledHints(info);
2984 updateListenerHintsLocked();
2985 updateEffectsSuppressorLocked();
2986 }
2987 } finally {
2988 Binder.restoreCallingIdentity(identity);
2989 }
2990 }
2991
2992 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002993 public void requestHintsFromListener(INotificationListener token, int hints) {
2994 final long identity = Binder.clearCallingIdentity();
2995 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002996 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002997 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07002998 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2999 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
3000 | HINT_HOST_DISABLE_CALL_EFFECTS;
3001 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04003002 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003003 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003004 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07003005 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003006 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04003007 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04003008 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04003009 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04003010 } finally {
3011 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04003012 }
3013 }
3014
3015 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04003016 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003017 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003018 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04003019 }
3020 }
3021
3022 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02003023 public void requestInterruptionFilterFromListener(INotificationListener token,
3024 int interruptionFilter) throws RemoteException {
3025 final long identity = Binder.clearCallingIdentity();
3026 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003027 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05003028 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3029 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02003030 updateInterruptionFilterLocked();
3031 }
3032 } finally {
3033 Binder.restoreCallingIdentity(identity);
3034 }
3035 }
3036
3037 @Override
3038 public int getInterruptionFilterFromListener(INotificationListener token)
3039 throws RemoteException {
3040 synchronized (mNotificationLight) {
3041 return mInterruptionFilter;
3042 }
3043 }
3044
3045 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02003046 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
3047 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003048 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02003049 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3050 if (info == null) return;
3051 mListeners.setOnNotificationPostedTrimLocked(info, trim);
3052 }
3053 }
3054
3055 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04003056 public int getZenMode() {
3057 return mZenModeHelper.getZenMode();
3058 }
3059
3060 @Override
John Spurlock056c5192014-04-20 21:52:01 -04003061 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003062 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04003063 return mZenModeHelper.getConfig();
3064 }
3065
3066 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04003067 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003068 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05003069 final long identity = Binder.clearCallingIdentity();
3070 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04003071 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05003072 } finally {
3073 Binder.restoreCallingIdentity(identity);
3074 }
3075 }
3076
3077 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05003078 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003079 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05003080 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003081 }
3082
3083 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003084 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
3085 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003086 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003087 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003088 }
3089
3090 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05003091 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003092 throws RemoteException {
3093 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
3094 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
3095 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
3096 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003097 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003098
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003099 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
3100 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003101 }
3102
3103 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05003104 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003105 throws RemoteException {
3106 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
3107 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
3108 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
3109 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
3110 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003111
Julia Reynolds361e82d32016-02-26 18:19:49 -05003112 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003113 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003114 }
3115
3116 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003117 public boolean removeAutomaticZenRule(String id) throws RemoteException {
3118 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003119 // Verify that they can modify zen rules.
3120 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
3121
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003122 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003123 }
3124
3125 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05003126 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
3127 Preconditions.checkNotNull(packageName, "Package name is null");
3128 enforceSystemOrSystemUI("removeAutomaticZenRules");
3129
3130 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
3131 }
3132
3133 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05003134 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
3135 Preconditions.checkNotNull(owner, "Owner is null");
3136 enforceSystemOrSystemUI("getRuleInstanceCount");
3137
3138 return mZenModeHelper.getCurrentInstanceCount(owner);
3139 }
3140
3141 @Override
John Spurlock80774932015-05-07 17:38:50 -04003142 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
3143 enforcePolicyAccess(pkg, "setInterruptionFilter");
3144 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
3145 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
3146 final long identity = Binder.clearCallingIdentity();
3147 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04003148 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04003149 } finally {
3150 Binder.restoreCallingIdentity(identity);
3151 }
3152 }
3153
3154 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04003155 public void notifyConditions(final String pkg, IConditionProvider provider,
3156 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04003157 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3158 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04003159 mHandler.post(new Runnable() {
3160 @Override
3161 public void run() {
3162 mConditionProviders.notifyConditions(pkg, info, conditions);
3163 }
3164 });
John Spurlocke77bb362014-04-26 10:24:59 -04003165 }
3166
Julia Reynolds38e6ca42016-08-08 08:38:09 -04003167 @Override
3168 public void requestUnbindProvider(IConditionProvider provider) {
3169 long identity = Binder.clearCallingIdentity();
3170 try {
3171 // allow bound services to disable themselves
3172 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3173 info.getOwner().setComponentState(info.component, false);
3174 } finally {
3175 Binder.restoreCallingIdentity(identity);
3176 }
3177 }
3178
3179 @Override
3180 public void requestBindProvider(ComponentName component) {
3181 checkCallerIsSystemOrSameApp(component.getPackageName());
3182 long identity = Binder.clearCallingIdentity();
3183 try {
3184 mConditionProviders.setComponentState(component, true);
3185 } finally {
3186 Binder.restoreCallingIdentity(identity);
3187 }
3188 }
3189
John Spurlocke77bb362014-04-26 10:24:59 -04003190 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003191 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04003192 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
3193 message);
John Spurlock7340fc82014-04-24 18:50:12 -04003194 }
3195
Julia Reynolds48034f82016-03-09 10:15:16 -05003196 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
3197 try {
3198 checkCallerIsSystemOrSameApp(pkg);
3199 } catch (SecurityException e) {
3200 getContext().enforceCallingPermission(
3201 android.Manifest.permission.STATUS_BAR_SERVICE,
3202 message);
3203 }
3204 }
3205
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003206 private void enforcePolicyAccess(int uid, String method) {
3207 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3208 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3209 return;
3210 }
3211 boolean accessAllowed = false;
3212 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
3213 final int packageCount = packages.length;
3214 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003215 if (mConditionProviders.isPackageOrComponentAllowed(
3216 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003217 accessAllowed = true;
3218 }
3219 }
3220 if (!accessAllowed) {
3221 Slog.w(TAG, "Notification policy access denied calling " + method);
3222 throw new SecurityException("Notification policy access denied");
3223 }
3224 }
3225
John Spurlock80774932015-05-07 17:38:50 -04003226 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04003227 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3228 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3229 return;
3230 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04003231 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003232 if (!checkPolicyAccess(pkg)) {
3233 Slog.w(TAG, "Notification policy access denied calling " + method);
3234 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04003235 }
3236 }
3237
John Spurlock80774932015-05-07 17:38:50 -04003238 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003239 return mConditionProviders.isPackageOrComponentAllowed(
3240 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04003241 }
3242
3243 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003244 try {
Jason Parks50322ff2018-03-27 10:23:33 -05003245 int uid = getContext().getPackageManager().getPackageUidAsUser(pkg,
3246 UserHandle.getCallingUserId());
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003247 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
3248 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
3249 -1, true)) {
3250 return true;
3251 }
3252 } catch (NameNotFoundException e) {
3253 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003254 }
Jason Parks50322ff2018-03-27 10:23:33 -05003255 return checkPackagePolicyAccess(pkg)
3256 || mListeners.isComponentEnabledForPackage(pkg)
3257 || (mDpm != null &&
3258 mDpm.isActiveAdminWithPolicy(Binder.getCallingUid(),
3259 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER));
John Spurlock1fc476d2015-04-14 16:05:20 -04003260 }
3261
John Spurlock7340fc82014-04-24 18:50:12 -04003262 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08003263 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003264 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04003265 final DumpFilter filter = DumpFilter.parseFromArguments(args);
Makoto Onukibbb4b222018-06-25 16:01:02 -07003266 final long token = Binder.clearCallingIdentity();
3267 try {
3268 if (filter.stats) {
3269 dumpJson(pw, filter);
3270 } else if (filter.proto) {
3271 dumpProto(fd, filter);
3272 } else if (filter.criticalPriority) {
3273 dumpNotificationRecords(pw, filter);
3274 } else {
3275 dumpImpl(pw, filter);
3276 }
3277 } finally {
3278 Binder.restoreCallingIdentity(token);
Chris Wrene4b38802015-07-07 15:54:19 -04003279 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003280 }
John Spurlockb4782522014-08-22 14:54:46 -04003281
3282 @Override
3283 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07003284 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04003285 }
John Spurlock2b122f42014-08-27 16:29:47 -04003286
3287 @Override
3288 public boolean matchesCallFilter(Bundle extras) {
3289 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02003290 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003291 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02003292 extras,
3293 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
3294 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
3295 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04003296 }
John Spurlock530052a2014-11-30 16:26:19 -05003297
3298 @Override
3299 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003300 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04003301 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05003302 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003303
Christopher Tatef9767d62015-04-08 14:35:43 -07003304 // Backup/restore interface
3305 @Override
3306 public byte[] getBackupPayload(int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003307 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003308 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003309 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003310 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003311 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
3312 return null;
3313 }
songjinshi9bf22712017-02-04 10:47:45 +08003314 synchronized(mPolicyFile) {
3315 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
3316 try {
3317 writePolicyXml(baos, true /*forBackup*/);
3318 return baos.toByteArray();
3319 } catch (IOException e) {
3320 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
3321 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003322 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003323 return null;
3324 }
3325
3326 @Override
3327 public void applyRestore(byte[] payload, int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003328 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003329 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
3330 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
3331 if (payload == null) {
3332 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
3333 return;
3334 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003335 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003336 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003337 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
3338 return;
3339 }
songjinshi9bf22712017-02-04 10:47:45 +08003340 synchronized(mPolicyFile) {
3341 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
3342 try {
3343 readPolicyXml(bais, true /*forRestore*/);
3344 savePolicyFile();
3345 } catch (NumberFormatException | XmlPullParserException | IOException e) {
3346 Slog.w(TAG, "applyRestore: error reading payload", e);
3347 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003348 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003349 }
3350
John Spurlock1fc476d2015-04-14 16:05:20 -04003351 @Override
John Spurlock80774932015-05-07 17:38:50 -04003352 public boolean isNotificationPolicyAccessGranted(String pkg) {
3353 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04003354 }
3355
3356 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05003357 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
3358 enforceSystemOrSystemUIOrSamePackage(pkg,
3359 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003360 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003361 }
3362
3363 @Override
John Spurlock80774932015-05-07 17:38:50 -04003364 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
3365 throws RemoteException {
Julia Reynolds92febc32017-10-26 11:30:31 -04003366 setNotificationPolicyAccessGrantedForUser(
3367 pkg, getCallingUserHandle().getIdentifier(), granted);
3368 }
3369
3370 @Override
3371 public void setNotificationPolicyAccessGrantedForUser(
3372 String pkg, int userId, boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003373 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003374 final long identity = Binder.clearCallingIdentity();
3375 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003376 if (mAllowedManagedServicePackages.test(pkg)) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003377 mConditionProviders.setPackageOrComponentEnabled(
Julia Reynolds92febc32017-10-26 11:30:31 -04003378 pkg, userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003379
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003380 getContext().sendBroadcastAsUser(new Intent(
3381 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3382 .setPackage(pkg)
3383 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003384 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003385 savePolicyFile();
3386 }
3387 } finally {
3388 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003389 }
John Spurlock80774932015-05-07 17:38:50 -04003390 }
3391
3392 @Override
3393 public Policy getNotificationPolicy(String pkg) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003394 final long identity = Binder.clearCallingIdentity();
3395 try {
3396 return mZenModeHelper.getNotificationPolicy();
3397 } finally {
3398 Binder.restoreCallingIdentity(identity);
3399 }
3400 }
3401
Beverly6697eff2017-12-14 15:00:27 -05003402 /**
3403 * Sets the notification policy. Apps that target API levels below
Beverly98ef61b2018-02-15 10:36:28 -05003404 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
Beverlyd6964762018-02-16 14:07:03 -05003405 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3406 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3407 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
Beverly6697eff2017-12-14 15:00:27 -05003408 */
John Spurlock1fc476d2015-04-14 16:05:20 -04003409 @Override
John Spurlock80774932015-05-07 17:38:50 -04003410 public void setNotificationPolicy(String pkg, Policy policy) {
3411 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04003412 final long identity = Binder.clearCallingIdentity();
3413 try {
Beverly6697eff2017-12-14 15:00:27 -05003414 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3415 0, UserHandle.getUserId(MY_UID));
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003416 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
Beverly6697eff2017-12-14 15:00:27 -05003417
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06003418 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
Beverly98ef61b2018-02-15 10:36:28 -05003419 int priorityCategories = policy.priorityCategories;
3420 // ignore alarm and media values from new policy
3421 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
Beverlyd6964762018-02-16 14:07:03 -05003422 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3423 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003424 // use user-designated values
Beverlyd6964762018-02-16 14:07:03 -05003425 priorityCategories |= currPolicy.priorityCategories
3426 & Policy.PRIORITY_CATEGORY_ALARMS;
3427 priorityCategories |= currPolicy.priorityCategories
3428 & Policy.PRIORITY_CATEGORY_MEDIA;
3429 priorityCategories |= currPolicy.priorityCategories
3430 & Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003431
Beverly6697eff2017-12-14 15:00:27 -05003432 policy = new Policy(priorityCategories,
3433 policy.priorityCallSenders, policy.priorityMessageSenders,
3434 policy.suppressedVisualEffects);
3435 }
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003436 int newVisualEffects = calculateSuppressedVisualEffects(
3437 policy, currPolicy, applicationInfo.targetSdkVersion);
3438 policy = new Policy(policy.priorityCategories,
3439 policy.priorityCallSenders, policy.priorityMessageSenders,
3440 newVisualEffects);
Beverly5e073222018-03-08 10:36:25 -05003441 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
John Spurlock1fc476d2015-04-14 16:05:20 -04003442 mZenModeHelper.setNotificationPolicy(policy);
Beverly6697eff2017-12-14 15:00:27 -05003443 } catch (RemoteException e) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003444 } finally {
3445 Binder.restoreCallingIdentity(identity);
3446 }
3447 }
Chris Wren51017d02015-12-15 15:34:46 -05003448
3449 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003450 public List<String> getEnabledNotificationListenerPackages() {
3451 checkCallerIsSystem();
3452 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3453 }
3454
3455 @Override
3456 public List<ComponentName> getEnabledNotificationListeners(int userId) {
3457 checkCallerIsSystem();
3458 return mListeners.getAllowedComponents(userId);
3459 }
3460
3461 @Override
3462 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3463 Preconditions.checkNotNull(listener);
3464 checkCallerIsSystemOrSameApp(listener.getPackageName());
3465 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3466 getCallingUserHandle().getIdentifier());
3467 }
3468
3469 @Override
3470 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3471 int userId) {
3472 Preconditions.checkNotNull(listener);
3473 checkCallerIsSystem();
3474 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3475 userId);
3476 }
3477
3478 @Override
3479 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3480 Preconditions.checkNotNull(assistant);
3481 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003482 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04003483 getCallingUserHandle().getIdentifier());
3484 }
3485
3486 @Override
3487 public void setNotificationListenerAccessGranted(ComponentName listener,
3488 boolean granted) throws RemoteException {
3489 setNotificationListenerAccessGrantedForUser(
3490 listener, getCallingUserHandle().getIdentifier(), granted);
3491 }
3492
3493 @Override
3494 public void setNotificationAssistantAccessGranted(ComponentName assistant,
3495 boolean granted) throws RemoteException {
3496 setNotificationAssistantAccessGrantedForUser(
3497 assistant, getCallingUserHandle().getIdentifier(), granted);
3498 }
3499
3500 @Override
3501 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3502 boolean granted) throws RemoteException {
3503 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04003504 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003505 final long identity = Binder.clearCallingIdentity();
3506 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003507 if (mAllowedManagedServicePackages.test(listener.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003508 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3509 userId, false, granted);
3510 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3511 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003512
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003513 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds92febc32017-10-26 11:30:31 -04003514 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003515 .setPackage(listener.getPackageName())
3516 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003517 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003518
3519 savePolicyFile();
3520 }
3521 } finally {
3522 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003523 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003524 }
3525
3526 @Override
3527 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3528 int userId, boolean granted) throws RemoteException {
3529 Preconditions.checkNotNull(assistant);
Julia Reynolds0d217642017-08-11 11:26:04 -04003530 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003531 final long identity = Binder.clearCallingIdentity();
3532 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003533 if (mAllowedManagedServicePackages.test(assistant.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003534 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
3535 userId, false, granted);
3536 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
3537 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003538
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003539 getContext().sendBroadcastAsUser(new Intent(
3540 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3541 .setPackage(assistant.getPackageName())
3542 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003543 UserHandle.of(userId), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003544
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003545 savePolicyFile();
3546 }
3547 } finally {
3548 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003549 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003550 }
3551
3552 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003553 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003554 Adjustment adjustment) {
3555 boolean foundEnqueued = false;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003556 final long identity = Binder.clearCallingIdentity();
3557 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003558 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003559 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003560 int N = mEnqueuedNotifications.size();
3561 for (int i = 0; i < N; i++) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003562 final NotificationRecord r = mEnqueuedNotifications.get(i);
3563 if (Objects.equals(adjustment.getKey(), r.getKey())
Julia Reynolds70aaea72018-07-13 13:38:34 -04003564 && Objects.equals(adjustment.getUser(), r.getUserId())
3565 && mAssistants.isSameUser(token, r.getUserId())) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003566 applyAdjustment(r, adjustment);
3567 r.applyAdjustments();
3568 foundEnqueued = true;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003569 break;
3570 }
3571 }
Julia Reynolds666ccf02018-06-18 10:19:20 -04003572 if (!foundEnqueued) {
3573 // adjustment arrived too late to apply to enqueued; apply to posted
3574 applyAdjustmentFromAssistant(token, adjustment);
3575 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003576 }
3577 } finally {
3578 Binder.restoreCallingIdentity(identity);
3579 }
3580 }
3581
3582 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003583 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003584 Adjustment adjustment) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003585 List<Adjustment> adjustments = new ArrayList<>();
3586 adjustments.add(adjustment);
3587 applyAdjustmentsFromAssistant(token, adjustments);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003588 }
3589
3590 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003591 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003592 List<Adjustment> adjustments) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003593
Julia Reynoldsefcdff42018-08-09 09:42:56 -04003594 boolean needsSort = false;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003595 final long identity = Binder.clearCallingIdentity();
3596 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003597 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003598 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003599 for (Adjustment adjustment : adjustments) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003600 NotificationRecord r = mNotificationsByKey.get(adjustment.getKey());
3601 if (r != null && mAssistants.isSameUser(token, r.getUserId())) {
3602 applyAdjustment(r, adjustment);
Julia Reynoldsefcdff42018-08-09 09:42:56 -04003603 r.applyAdjustments();
3604 if (r.getImportance() == IMPORTANCE_NONE) {
3605 cancelNotificationsFromListener(token, new String[]{r.getKey()});
3606 } else {
3607 needsSort = true;
3608 }
Julia Reynolds70aaea72018-07-13 13:38:34 -04003609 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003610 }
3611 }
Julia Reynoldsefcdff42018-08-09 09:42:56 -04003612 if (needsSort) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003613 mRankingHandler.requestSort();
3614 }
Chris Wren51017d02015-12-15 15:34:46 -05003615 } finally {
3616 Binder.restoreCallingIdentity(identity);
3617 }
3618 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003619
3620 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04003621 public void updateNotificationChannelGroupFromPrivilegedListener(
3622 INotificationListener token, String pkg, UserHandle user,
3623 NotificationChannelGroup group) throws RemoteException {
3624 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003625 verifyPrivilegedListener(token, user, false);
Julia Reynolds005c8b92017-08-24 10:35:53 -04003626 createNotificationChannelGroup(
3627 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
3628 savePolicyFile();
3629 }
3630
3631 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003632 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003633 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003634 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003635 Preconditions.checkNotNull(pkg);
3636 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003637
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003638 verifyPrivilegedListener(token, user, false);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003639 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003640 }
3641
3642 @Override
3643 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003644 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3645 Preconditions.checkNotNull(pkg);
3646 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003647 verifyPrivilegedListener(token, user, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003648
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003649 return mPreferencesHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003650 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003651 }
3652
3653 @Override
3654 public ParceledListSlice<NotificationChannelGroup>
3655 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003656 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3657 Preconditions.checkNotNull(pkg);
3658 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003659 verifyPrivilegedListener(token, user, true);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003660
3661 List<NotificationChannelGroup> groups = new ArrayList<>();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003662 groups.addAll(mPreferencesHelper.getNotificationChannelGroups(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003663 pkg, getUidForPackageAndUser(pkg, user)));
3664 return new ParceledListSlice<>(groups);
3665 }
3666
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003667 private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
3668 boolean assistantAllowed) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003669 ManagedServiceInfo info;
3670 synchronized (mNotificationLock) {
3671 info = mListeners.checkServiceTokenLocked(token);
3672 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003673 if (!hasCompanionDevice(info)) {
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003674 synchronized (mNotificationLock) {
3675 if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) {
3676 throw new SecurityException(info + " does not have access");
3677 }
3678 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003679 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003680 if (!info.enabledAndUserMatches(user.getIdentifier())) {
3681 throw new SecurityException(info + " does not have access");
3682 }
3683 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003684
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003685 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3686 int uid = 0;
3687 long identity = Binder.clearCallingIdentity();
3688 try {
3689 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3690 } finally {
3691 Binder.restoreCallingIdentity(identity);
3692 }
3693 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003694 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003695
3696 @Override
3697 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3698 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3699 throws RemoteException {
3700 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3701 }
John Spurlock1fc476d2015-04-14 16:05:20 -04003702 };
John Spurlocka4294292014-03-24 18:02:32 -04003703
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003704 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3705 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003706 return;
3707 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003708 if (adjustment.getSignals() != null) {
3709 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003710 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003711 }
3712 }
3713
Julia Reynolds88860ce2017-06-01 16:55:49 -04003714 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003715 void addAutogroupKeyLocked(String key) {
3716 NotificationRecord r = mNotificationsByKey.get(key);
3717 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003718 return;
3719 }
Julia Reynolds51710712017-07-19 13:48:07 -04003720 if (r.sbn.getOverrideGroupKey() == null) {
3721 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3722 EventLogTags.writeNotificationAutogrouped(key);
3723 mRankingHandler.requestSort();
3724 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003725 }
3726
Julia Reynolds88860ce2017-06-01 16:55:49 -04003727 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003728 void removeAutogroupKeyLocked(String key) {
3729 NotificationRecord r = mNotificationsByKey.get(key);
3730 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003731 return;
3732 }
Julia Reynolds51710712017-07-19 13:48:07 -04003733 if (r.sbn.getOverrideGroupKey() != null) {
3734 addAutoGroupAdjustment(r, null);
3735 EventLogTags.writeNotificationUnautogrouped(key);
3736 mRankingHandler.requestSort();
3737 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003738 }
3739
3740 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3741 Bundle signals = new Bundle();
3742 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3743 Adjustment adjustment =
3744 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3745 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003746 }
3747
3748 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04003749 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04003750 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3751 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3752 if (summaries != null && summaries.containsKey(pkg)) {
3753 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003754 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04003755 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04003756 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003757 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003758 }
3759 }
3760 }
3761
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003762 @GuardedBy("mNotificationLock")
3763 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3764 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3765 return summaries != null && summaries.containsKey(sbn.getPackageName());
3766 }
3767
Julia Reynoldse46bb372016-03-17 11:05:58 -04003768 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04003769 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3770 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003771 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003772 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3773 if (notificationRecord == null) {
3774 // The notification could have been cancelled again already. A successive
3775 // adjustment will post a summary if needed.
3776 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003777 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003778 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3779 userId = adjustedSbn.getUser().getIdentifier();
3780 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3781 if (summaries == null) {
3782 summaries = new ArrayMap<>();
3783 }
3784 mAutobundledSummaries.put(userId, summaries);
3785 if (!summaries.containsKey(pkg)) {
3786 // Add summary
3787 final ApplicationInfo appInfo =
3788 adjustedSbn.getNotification().extras.getParcelable(
3789 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3790 final Bundle extras = new Bundle();
3791 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003792 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04003793 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003794 new Notification.Builder(getContext(), channelId)
3795 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04003796 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04003797 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04003798 .setGroup(GroupHelper.AUTOGROUP_KEY)
3799 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3800 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3801 .setColor(adjustedSbn.getNotification().color)
3802 .setLocalOnly(true)
3803 .build();
3804 summaryNotification.extras.putAll(extras);
3805 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3806 if (appIntent != null) {
3807 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3808 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3809 }
3810 final StatusBarNotification summarySbn =
3811 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003812 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003813 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04003814 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3815 adjustedSbn.getInitialPid(), summaryNotification,
3816 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3817 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05003818 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003819 notificationRecord.getChannel());
Rohan Shah590e1b22018-04-10 23:48:47 -04003820 summaryRecord.setIsAppImportanceLocked(
3821 notificationRecord.getIsAppImportanceLocked());
Julia Reynolds8f488d32016-10-14 10:59:01 -04003822 summaries.put(pkg, summarySbn.getKey());
3823 }
3824 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003825 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04003826 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003827 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04003828 }
3829 }
3830
John Spurlock32fe4c62014-10-02 12:16:02 -04003831 private String disableNotificationEffects(NotificationRecord record) {
3832 if (mDisableNotificationEffects) {
3833 return "booleanState";
3834 }
3835 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3836 return "listenerHints";
3837 }
3838 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3839 return "callState";
3840 }
3841 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04003842 };
3843
Kweku Adams887f09c2017-11-13 17:12:20 -08003844 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
Chris Wrene4b38802015-07-07 15:54:19 -04003845 JSONObject dump = new JSONObject();
3846 try {
3847 dump.put("service", "Notification Manager");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003848 dump.put("bans", mPreferencesHelper.dumpBansJson(filter));
3849 dump.put("ranking", mPreferencesHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003850 dump.put("stats", mUsageStats.dumpJson(filter));
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003851 dump.put("channels", mPreferencesHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003852 } catch (JSONException e) {
3853 e.printStackTrace();
3854 }
3855 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04003856 }
3857
Kweku Adams887f09c2017-11-13 17:12:20 -08003858 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003859 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3860 synchronized (mNotificationLock) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003861 int N = mNotificationList.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003862 for (int i = 0; i < N; i++) {
3863 final NotificationRecord nr = mNotificationList.get(i);
3864 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3865 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3866 NotificationRecordProto.POSTED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003867 }
3868 N = mEnqueuedNotifications.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003869 for (int i = 0; i < N; i++) {
3870 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3871 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3872 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3873 NotificationRecordProto.ENQUEUED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003874 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003875 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3876 N = snoozed.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003877 for (int i = 0; i < N; i++) {
3878 final NotificationRecord nr = snoozed.get(i);
3879 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3880 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3881 NotificationRecordProto.SNOOZED);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003882 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003883
Kweku Adams93304b62017-09-20 17:03:00 -07003884 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3885 mZenModeHelper.dump(proto);
3886 for (ComponentName suppressor : mEffectsSuppressors) {
Kweku Adams99546332018-01-24 17:03:50 -08003887 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
Kweku Adams93304b62017-09-20 17:03:00 -07003888 }
3889 proto.end(zenLog);
3890
3891 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
3892 mListeners.dump(proto, filter);
3893 proto.end(listenersToken);
3894
3895 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
3896
3897 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
3898 long effectsToken = proto.start(
3899 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
3900
3901 proto.write(
3902 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
Julia Reynolds4703bac2018-09-12 10:39:30 -04003903 final ArraySet<ComponentName> listeners =
Kweku Adams93304b62017-09-20 17:03:00 -07003904 mListenersDisablingEffects.valueAt(i);
3905 for (int j = 0; j < listeners.size(); j++) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04003906 final ComponentName componentName = listeners.valueAt(i);
3907 componentName.writeToProto(proto,
3908 ListenersDisablingEffectsProto.LISTENER_COMPONENTS);
Kweku Adams93304b62017-09-20 17:03:00 -07003909 }
3910
3911 proto.end(effectsToken);
3912 }
3913
3914 long assistantsToken = proto.start(
3915 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
3916 mAssistants.dump(proto, filter);
3917 proto.end(assistantsToken);
3918
3919 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
3920 mConditionProviders.dump(proto, filter);
3921 proto.end(conditionsToken);
Kweku Adams62b42242017-09-25 12:54:02 -07003922
3923 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
3924 mRankingHelper.dump(proto, filter);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003925 mPreferencesHelper.dump(proto, filter);
Kweku Adams62b42242017-09-25 12:54:02 -07003926 proto.end(rankingToken);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003927 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003928
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003929 proto.flush();
3930 }
3931
Vishnu Naire3e4d252018-03-01 11:26:57 -08003932 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
3933 synchronized (mNotificationLock) {
3934 int N;
3935 N = mNotificationList.size();
3936 if (N > 0) {
3937 pw.println(" Notification List:");
3938 for (int i = 0; i < N; i++) {
3939 final NotificationRecord nr = mNotificationList.get(i);
3940 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3941 nr.dump(pw, " ", getContext(), filter.redact);
3942 }
3943 pw.println(" ");
3944 }
3945 }
3946 }
3947
Kweku Adams887f09c2017-11-13 17:12:20 -08003948 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
John Spurlock25e2d242014-06-27 13:58:23 -04003949 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04003950 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003951 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04003952 }
3953 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08003954 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003955 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003956
John Spurlock50806fc2014-07-15 10:22:02 -04003957 if (!zenOnly) {
3958 synchronized (mToastQueue) {
3959 N = mToastQueue.size();
3960 if (N > 0) {
3961 pw.println(" Toast Queue:");
3962 for (int i=0; i<N; i++) {
3963 mToastQueue.get(i).dump(pw, " ", filter);
3964 }
3965 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003966 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003967 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003968 }
3969
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003970 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04003971 if (!zenOnly) {
Vishnu Naire3e4d252018-03-01 11:26:57 -08003972 // Priority filters are only set when called via bugreport. If set
3973 // skip sections that are part of the critical section.
3974 if (!filter.normalPriority) {
3975 dumpNotificationRecords(pw, filter);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003976 }
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003977 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003978 N = mLights.size();
3979 if (N > 0) {
3980 pw.println(" Lights List:");
3981 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05003982 if (i == N - 1) {
3983 pw.print(" > ");
3984 } else {
3985 pw.print(" ");
3986 }
3987 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04003988 }
3989 pw.println(" ");
3990 }
John Spurlockcb566aa2014-08-03 22:58:28 -04003991 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
Julia Reynolds28149f62018-07-03 10:43:35 -04003992 pw.println(" mHasLight=" + mHasLight);
John Spurlockcb566aa2014-08-03 22:58:28 -04003993 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05003994 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3995 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003996 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04003997 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04003998 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04003999 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04004000 }
4001 pw.println(" mArchive=" + mArchive.toString());
4002 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004003 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04004004 while (iter.hasNext()) {
4005 final StatusBarNotification sbn = iter.next();
4006 if (filter != null && !filter.matches(sbn)) continue;
4007 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004008 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04004009 if (iter.hasNext()) pw.println(" ...");
4010 break;
4011 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004012 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004013
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004014 if (!zenOnly) {
4015 N = mEnqueuedNotifications.size();
4016 if (N > 0) {
4017 pw.println(" Enqueued Notification List:");
4018 for (int i = 0; i < N; i++) {
4019 final NotificationRecord nr = mEnqueuedNotifications.get(i);
4020 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4021 nr.dump(pw, " ", getContext(), filter.redact);
4022 }
4023 pw.println(" ");
4024 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004025
4026 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004027 }
4028 }
4029
John Spurlock50806fc2014-07-15 10:22:02 -04004030 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04004031 pw.println("\n Ranking Config:");
4032 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04004033
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004034 pw.println("\n Notification Preferences:");
4035 mPreferencesHelper.dump(pw, " ", filter);
4036
John Spurlock50806fc2014-07-15 10:22:02 -04004037 pw.println("\n Notification listeners:");
4038 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04004039 pw.print(" mListenerHints: "); pw.println(mListenerHints);
4040 pw.print(" mListenersDisablingEffects: (");
4041 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04004042 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07004043 final int hint = mListenersDisablingEffects.keyAt(i);
4044 if (i > 0) pw.print(';');
4045 pw.print("hint[" + hint + "]:");
4046
Julia Reynolds4703bac2018-09-12 10:39:30 -04004047 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07004048 final int listenerSize = listeners.size();
4049
4050 for (int j = 0; j < listenerSize; j++) {
4051 if (i > 0) pw.print(',');
Julia Reynolds4703bac2018-09-12 10:39:30 -04004052 final ComponentName listener = listeners.valueAt(i);
Julia Reynolds1f580572018-04-27 14:48:36 -04004053 if (listener != null) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04004054 pw.print(listener);
Julia Reynolds1f580572018-04-27 14:48:36 -04004055 }
Bryce Lee7219ada2016-04-08 10:54:23 -07004056 }
John Spurlock1fa865f2014-07-21 14:56:39 -04004057 }
4058 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05004059 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004060 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04004061 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004062
Julia Reynolds520df6e2017-02-13 09:05:10 -05004063 if (!filter.filtered || zenOnly) {
4064 pw.println("\n Zen Mode:");
4065 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
4066 mZenModeHelper.dump(pw, " ");
4067
4068 pw.println("\n Zen Log:");
4069 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004070 }
4071
John Spurlocke77bb362014-04-26 10:24:59 -04004072 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04004073 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02004074
4075 pw.println("\n Group summaries:");
4076 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
4077 NotificationRecord r = entry.getValue();
4078 pw.println(" " + entry.getKey() + " -> " + r.getKey());
4079 if (mNotificationsByKey.get(r.getKey()) != r) {
4080 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04004081 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02004082 }
4083 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004084
4085 if (!zenOnly) {
4086 pw.println("\n Usage Stats:");
4087 mUsageStats.dump(pw, " ", filter);
4088 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004089 }
4090 }
4091
Adam Lesinski182f73f2013-12-05 16:48:06 -08004092 /**
4093 * The private API only accessible to the system process.
4094 */
4095 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
4096 @Override
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04004097 public NotificationChannel getNotificationChannel(String pkg, int uid, String
4098 channelId) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004099 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false);
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04004100 }
4101
4102 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004103 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004104 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004105 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004106 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004107 }
Christoph Studer365e4c32014-09-18 20:35:36 +02004108
4109 @Override
4110 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
4111 int userId) {
4112 checkCallerIsSystem();
Julia Reynolds564273f2018-09-13 15:53:11 -04004113 mHandler.post(() -> {
4114 synchronized (mNotificationLock) {
4115 // strip flag from all enqueued notifications. listeners will be informed
4116 // in post runnable.
4117 List<NotificationRecord> enqueued = findNotificationsByListLocked(
4118 mEnqueuedNotifications, pkg, null, notificationId, userId);
4119 for (int i = 0; i < enqueued.size(); i++) {
4120 removeForegroundServiceFlagLocked(enqueued.get(i));
4121 }
4122
4123 // if posted notification exists, strip its flag and tell listeners
4124 NotificationRecord r = findNotificationByListLocked(
4125 mNotificationList, pkg, null, notificationId, userId);
4126 if (r != null) {
4127 removeForegroundServiceFlagLocked(r);
4128 mRankingHelper.sort(mNotificationList);
4129 mListeners.notifyPostedLocked(r, r);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004130 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004131 }
4132 });
4133 }
4134
Julia Reynolds88860ce2017-06-01 16:55:49 -04004135 @GuardedBy("mNotificationLock")
Julia Reynolds564273f2018-09-13 15:53:11 -04004136 private void removeForegroundServiceFlagLocked(NotificationRecord r) {
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004137 if (r == null) {
4138 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02004139 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004140 StatusBarNotification sbn = r.sbn;
4141 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
4142 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
4143 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
4144 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
4145 sbn.getNotification().flags =
Julia Reynoldse5c60452018-04-30 14:41:36 -04004146 (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
Christoph Studer365e4c32014-09-18 20:35:36 +02004147 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004148 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004149
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004150 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04004151 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004152 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04004153 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08004154 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
4155 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04004156 }
Dianne Hackborn41203752012-08-31 14:05:51 -07004157
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004158 if (pkg == null || notification == null) {
4159 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
4160 + " id=" + id + " notification=" + notification);
4161 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004162
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004163 final int userId = ActivityManager.handleIncomingUser(callingPid,
4164 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
4165 final UserHandle user = UserHandle.of(userId);
4166
4167 // Can throw a SecurityException if the calling uid doesn't have permission to post
4168 // as "pkg"
4169 final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
4170
4171 checkRestrictedCategories(notification);
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004172
Julia Reynoldse46bb372016-03-17 11:05:58 -04004173 // Fix the notification as best we can.
4174 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004175 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06004176 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
Julia Reynoldse0d711f2017-09-01 08:50:47 -04004177 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
Julia Reynoldse071abd2017-03-22 10:52:11 -04004178 Notification.addFieldsFromContext(ai, notification);
Julia Reynolds4db59552017-06-30 13:34:01 -04004179
4180 int canColorize = mPackageManagerClient.checkPermission(
4181 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
4182 if (canColorize == PERMISSION_GRANTED) {
4183 notification.flags |= Notification.FLAG_CAN_COLORIZE;
4184 } else {
4185 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
4186 }
4187
Julia Reynoldse46bb372016-03-17 11:05:58 -04004188 } catch (NameNotFoundException e) {
4189 Slog.e(TAG, "Cannot create a context for sending app", e);
4190 return;
4191 }
4192
Chris Wren888b7a82016-06-17 15:47:19 -04004193 mUsageStats.registerEnqueuedByApp(pkg);
4194
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004195 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04004196 String channelId = notification.getChannelId();
4197 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
4198 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05004199 }
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004200 final NotificationChannel channel = mPreferencesHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004201 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004202 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004203 final String noChannelStr = "No Channel found for "
4204 + "pkg=" + pkg
4205 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04004206 + ", id=" + id
4207 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004208 + ", opPkg=" + opPkg
4209 + ", callingUid=" + callingUid
4210 + ", userId=" + userId
4211 + ", incomingUserId=" + incomingUserId
4212 + ", notificationUid=" + notificationUid
4213 + ", notification=" + notification;
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004214 Log.e(TAG, noChannelStr);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004215 boolean appNotificationsOff = mPreferencesHelper.getImportance(pkg, notificationUid)
Beverly5d4564b2018-04-10 20:09:23 -04004216 == NotificationManager.IMPORTANCE_NONE;
4217
4218 if (!appNotificationsOff) {
4219 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
4220 "Failed to post notification on channel \"" + channelId + "\"\n" +
4221 "See log for more details");
4222 }
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004223 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004224 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004225
Chris Wrena61f1792016-08-04 11:24:42 -04004226 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004227 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004228 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004229 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004230 r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
Chris Wrena61f1792016-08-04 11:24:42 -04004231
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004232 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4233 final boolean fgServiceShown = channel.isFgServiceShown();
4234 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
4235 || !fgServiceShown)
4236 && (r.getImportance() == IMPORTANCE_MIN
4237 || r.getImportance() == IMPORTANCE_NONE)) {
4238 // Increase the importance of foreground service notifications unless the user had
4239 // an opinion otherwise (and the channel hasn't yet shown a fg service).
4240 if (TextUtils.isEmpty(channelId)
4241 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004242 r.setSystemImportance(IMPORTANCE_LOW);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004243 } else {
4244 channel.setImportance(IMPORTANCE_LOW);
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004245 r.setSystemImportance(IMPORTANCE_LOW);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004246 if (!fgServiceShown) {
4247 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
4248 channel.setFgServiceShown(true);
4249 }
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004250 mPreferencesHelper.updateNotificationChannel(
4251 pkg, notificationUid, channel, false);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004252 r.updateNotificationChannel(channel);
4253 }
4254 } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
4255 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4256 channel.setFgServiceShown(true);
Julia Reynolds8617e4e2017-09-18 16:52:37 -04004257 r.updateNotificationChannel(channel);
4258 }
4259 }
4260
Julia Reynolds5e702192017-08-18 09:22:40 -04004261 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
4262 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004263 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07004264 }
4265
Felipe Lemedd85da62016-06-28 11:29:54 -07004266 // Whitelist pending intents.
4267 if (notification.allPendingIntents != null) {
4268 final int intentCount = notification.allPendingIntents.size();
4269 if (intentCount > 0) {
4270 final ActivityManagerInternal am = LocalServices
4271 .getService(ActivityManagerInternal.class);
4272 final long duration = LocalServices.getService(
4273 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
4274 for (int i = 0; i < intentCount; i++) {
4275 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4276 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07004277 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4278 WHITELIST_TOKEN, duration);
Felipe Lemedd85da62016-06-28 11:29:54 -07004279 }
4280 }
4281 }
4282 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07004283
Chris Wren47633422016-01-22 09:56:59 -05004284 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004285 }
4286
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04004287 private void doChannelWarningToast(CharSequence toastText) {
Julia Reynoldsbba26b12018-10-11 09:21:11 -04004288 Binder.withCleanCallingIdentity(() -> {
4289 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
4290 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
4291 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4292 if (warningEnabled) {
4293 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
4294 Toast.LENGTH_SHORT);
4295 toast.show();
4296 }
4297 });
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004298 }
4299
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004300 @VisibleForTesting
4301 int resolveNotificationUid(String callingPkg, String targetPkg,
4302 int callingUid, int userId) {
Julia Reynoldsb6634872018-09-25 13:19:53 -04004303 if (userId == UserHandle.USER_ALL) {
4304 userId = USER_SYSTEM;
4305 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004306 // posted from app A on behalf of app A
Julia Reynoldsb6634872018-09-25 13:19:53 -04004307 if (isCallerSameApp(targetPkg, callingUid, userId)
Julia Reynoldsecc1b572018-10-01 16:19:24 -04004308 && (TextUtils.equals(callingPkg, targetPkg)
4309 || isCallerSameApp(callingPkg, callingUid, userId))) {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004310 return callingUid;
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004311 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004312
4313 int targetUid = -1;
4314 try {
4315 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
4316 } catch (NameNotFoundException e) {
4317 /* ignore */
4318 }
4319 // posted from app A on behalf of app B
4320 if (targetUid != -1 && (isCallerAndroid(callingPkg, callingUid)
4321 || mPreferencesHelper.isDelegateAllowed(
4322 targetPkg, targetUid, callingPkg, callingUid))) {
4323 return targetUid;
4324 }
4325
Julia Reynoldsecc1b572018-10-01 16:19:24 -04004326 throw new SecurityException("Caller " + callingPkg + ":" + callingUid
4327 + " cannot post for pkg " + targetPkg + " in user " + userId);
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004328 }
4329
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004330 /**
4331 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4332 *
4333 * Has side effects.
4334 */
Julia Reynoldsac98aea2018-10-25 16:54:27 -04004335 private boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04004336 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004337 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004338 final boolean isSystemNotification =
Julia Reynoldsac98aea2018-10-25 16:54:27 -04004339 isUidSystemOrPhone(uid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004340 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
4341
4342 // Limit the number of notifications that any given package except the android
4343 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
4344 if (!isSystemNotification && !isNotificationFromListener) {
4345 synchronized (mNotificationLock) {
Julia Reynoldsac98aea2018-10-25 16:54:27 -04004346 final int callingUid = Binder.getCallingUid();
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004347 if (mNotificationsByKey.get(r.sbn.getKey()) == null
Julia Reynoldsac98aea2018-10-25 16:54:27 -04004348 && isCallerInstantApp(callingUid, userId)) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004349 // Ephemeral apps have some special constraints for notifications.
4350 // They are not allowed to create new notifications however they are allowed to
4351 // update notifications created by the system (e.g. a foreground service
4352 // notification).
4353 throw new SecurityException("Instant app " + pkg
4354 + " cannot create notifications");
4355 }
4356
4357 // rate limit updates that aren't completed progress notifications
4358 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04004359 && !r.getNotification().hasCompletedProgress()
4360 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004361
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004362 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
4363 if (appEnqueueRate > mMaxPackageEnqueueRate) {
4364 mUsageStats.registerOverRateQuota(pkg);
4365 final long now = SystemClock.elapsedRealtime();
4366 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
4367 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04004368 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004369 mLastOverRateLogTime = now;
4370 }
4371 return false;
4372 }
4373 }
4374
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004375 // limit the number of outstanding notificationrecords an app can have
4376 int count = getNotificationCountLocked(pkg, userId, id, tag);
4377 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
4378 mUsageStats.registerOverCountQuota(pkg);
4379 Slog.e(TAG, "Package has already posted or enqueued " + count
4380 + " notifications. Not showing more. package=" + pkg);
4381 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004382 }
4383 }
4384 }
4385
4386 // snoozed apps
4387 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05004388 MetricsLogger.action(r.getLogMaker()
4389 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
4390 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004391 if (DBG) {
4392 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
4393 }
4394 mSnoozeHelper.update(userId, r);
4395 savePolicyFile();
4396 return false;
4397 }
4398
4399
4400 // blocked apps
4401 if (isBlocked(r, mUsageStats)) {
4402 return false;
4403 }
4404
4405 return true;
4406 }
4407
Andreas Gampea36dc622018-02-05 17:19:22 -08004408 @GuardedBy("mNotificationLock")
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004409 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
4410 String excludedTag) {
4411 int count = 0;
4412 final int N = mNotificationList.size();
4413 for (int i = 0; i < N; i++) {
4414 final NotificationRecord existing = mNotificationList.get(i);
4415 if (existing.sbn.getPackageName().equals(pkg)
4416 && existing.sbn.getUserId() == userId) {
4417 if (existing.sbn.getId() == excludedId
4418 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
4419 continue;
4420 }
4421 count++;
4422 }
4423 }
4424 final int M = mEnqueuedNotifications.size();
4425 for (int i = 0; i < M; i++) {
4426 final NotificationRecord existing = mEnqueuedNotifications.get(i);
4427 if (existing.sbn.getPackageName().equals(pkg)
4428 && existing.sbn.getUserId() == userId) {
4429 count++;
4430 }
4431 }
4432 return count;
4433 }
4434
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004435 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
Beverly3c707b42018-09-14 09:49:07 -04004436 if (isBlocked(r)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004437 Slog.e(TAG, "Suppressing notification from package by user request.");
4438 usageStats.registerBlocked(r);
Beverly3c707b42018-09-14 09:49:07 -04004439 return true;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004440 }
Beverly3c707b42018-09-14 09:49:07 -04004441 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004442 }
4443
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004444 private boolean isBlocked(NotificationRecord r) {
4445 final String pkg = r.sbn.getPackageName();
4446 final int callingUid = r.sbn.getUid();
4447 return mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
4448 || mPreferencesHelper.getImportance(pkg, callingUid)
4449 == NotificationManager.IMPORTANCE_NONE
4450 || r.getImportance() == NotificationManager.IMPORTANCE_NONE;
4451 }
4452
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004453 protected class SnoozeNotificationRunnable implements Runnable {
4454 private final String mKey;
4455 private final long mDuration;
4456 private final String mSnoozeCriterionId;
4457
4458 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
4459 mKey = key;
4460 mDuration = duration;
4461 mSnoozeCriterionId = snoozeCriterionId;
4462 }
4463
4464 @Override
4465 public void run() {
4466 synchronized (mNotificationLock) {
4467 final NotificationRecord r = findNotificationByKeyLocked(mKey);
4468 if (r != null) {
4469 snoozeLocked(r);
4470 }
4471 }
4472 }
4473
Julia Reynolds88860ce2017-06-01 16:55:49 -04004474 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004475 void snoozeLocked(NotificationRecord r) {
4476 if (r.sbn.isGroup()) {
4477 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
4478 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
4479 if (r.getNotification().isGroupSummary()) {
4480 // snooze summary and all children
4481 for (int i = 0; i < groupNotifications.size(); i++) {
4482 snoozeNotificationLocked(groupNotifications.get(i));
4483 }
4484 } else {
4485 // if there is a valid summary for this group, and we are snoozing the only
4486 // child, also snooze the summary
4487 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
4488 if (groupNotifications.size() != 2) {
4489 snoozeNotificationLocked(r);
4490 } else {
4491 // snooze summary and the one child
4492 for (int i = 0; i < groupNotifications.size(); i++) {
4493 snoozeNotificationLocked(groupNotifications.get(i));
4494 }
4495 }
4496 } else {
4497 snoozeNotificationLocked(r);
4498 }
4499 }
4500 } else {
4501 // just snooze the one notification
4502 snoozeNotificationLocked(r);
4503 }
4504 }
4505
Julia Reynolds88860ce2017-06-01 16:55:49 -04004506 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004507 void snoozeNotificationLocked(NotificationRecord r) {
4508 MetricsLogger.action(r.getLogMaker()
4509 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4510 .setType(MetricsEvent.TYPE_CLOSE)
Chris Wren21a2e722017-10-02 17:44:53 -04004511 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
4512 mDuration)
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004513 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4514 mSnoozeCriterionId == null ? 0 : 1));
Julia Reynolds0839c022017-06-15 15:24:01 -04004515 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004516 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004517 updateLightsLocked();
4518 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004519 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004520 mSnoozeHelper.snooze(r);
4521 } else {
4522 mSnoozeHelper.snooze(r, mDuration);
4523 }
Julia Reynolds503ed942017-10-04 16:04:56 -04004524 r.recordSnoozed();
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004525 savePolicyFile();
4526 }
4527 }
4528
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004529 protected class CancelNotificationRunnable implements Runnable {
4530 private final int mCallingUid;
4531 private final int mCallingPid;
4532 private final String mPkg;
4533 private final String mTag;
4534 private final int mId;
4535 private final int mMustHaveFlags;
4536 private final int mMustNotHaveFlags;
4537 private final boolean mSendDelete;
4538 private final int mUserId;
4539 private final int mReason;
4540 private final int mRank;
4541 private final int mCount;
4542 private final ManagedServiceInfo mListener;
4543
4544 CancelNotificationRunnable(final int callingUid, final int callingPid,
4545 final String pkg, final String tag, final int id,
4546 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
4547 final int userId, final int reason, int rank, int count,
4548 final ManagedServiceInfo listener) {
4549 this.mCallingUid = callingUid;
4550 this.mCallingPid = callingPid;
4551 this.mPkg = pkg;
4552 this.mTag = tag;
4553 this.mId = id;
4554 this.mMustHaveFlags = mustHaveFlags;
4555 this.mMustNotHaveFlags = mustNotHaveFlags;
4556 this.mSendDelete = sendDelete;
4557 this.mUserId = userId;
4558 this.mReason = reason;
4559 this.mRank = rank;
4560 this.mCount = count;
4561 this.mListener = listener;
4562 }
4563
4564 @Override
4565 public void run() {
4566 String listenerName = mListener == null ? null : mListener.component.toShortString();
4567 if (DBG) {
4568 EventLogTags.writeNotificationCancel(mCallingUid, mCallingPid, mPkg, mId, mTag,
4569 mUserId, mMustHaveFlags, mMustNotHaveFlags, mReason, listenerName);
4570 }
4571
4572 synchronized (mNotificationLock) {
4573 // Look for the notification, searching both the posted and enqueued lists.
4574 NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId);
4575 if (r != null) {
4576 // The notification was found, check if it should be removed.
4577
4578 // Ideally we'd do this in the caller of this method. However, that would
4579 // require the caller to also find the notification.
4580 if (mReason == REASON_CLICK) {
4581 mUsageStats.registerClickedByUser(r);
4582 }
4583
4584 if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) {
4585 return;
4586 }
4587 if ((r.getNotification().flags & mMustNotHaveFlags) != 0) {
4588 return;
4589 }
4590
4591 // Cancel the notification.
4592 boolean wasPosted = removeFromNotificationListsLocked(r);
4593 cancelNotificationLocked(
4594 r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName);
4595 cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
4596 mSendDelete, null);
4597 updateLightsLocked();
4598 } else {
4599 // No notification was found, assume that it is snoozed and cancel it.
4600 if (mReason != REASON_SNOOZED) {
4601 final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId);
4602 if (wasSnoozed) {
4603 savePolicyFile();
4604 }
4605 }
4606 }
4607 }
4608 }
4609 }
4610
Julia Reynoldsbaff4002016-12-15 11:34:26 -05004611 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05004612 private final NotificationRecord r;
4613 private final int userId;
4614
4615 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
4616 this.userId = userId;
4617 this.r = r;
4618 };
4619
4620 @Override
4621 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004622 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05004623 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05004624 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05004625
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004626 final StatusBarNotification n = r.sbn;
4627 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
4628 NotificationRecord old = mNotificationsByKey.get(n.getKey());
4629 if (old != null) {
4630 // Retain ranking information from previous record
4631 r.copyRankingInformation(old);
4632 }
4633
4634 final int callingUid = n.getUid();
4635 final int callingPid = n.getInitialPid();
4636 final Notification notification = n.getNotification();
4637 final String pkg = n.getPackageName();
4638 final int id = n.getId();
4639 final String tag = n.getTag();
4640
4641 // Handle grouped notifications and bail out early if we
4642 // can to avoid extracting signals.
4643 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
4644
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004645 // if this is a group child, unsnooze parent summary
4646 if (n.isGroup() && notification.isGroupChild()) {
4647 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
4648 }
4649
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004650 // This conditional is a dirty hack to limit the logging done on
4651 // behalf of the download manager without affecting other apps.
4652 if (!pkg.equals("com.android.providers.downloads")
4653 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
4654 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05004655 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004656 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05004657 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004658 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
4659 pkg, id, tag, userId, notification.toString(),
4660 enqueueStatus);
4661 }
Chris Wren6676dab2016-12-21 18:26:27 -05004662
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004663 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05004664
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004665 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004666 if (mAssistants.isEnabled()) {
4667 mAssistants.onNotificationEnqueued(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004668 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004669 DELAY_FOR_ASSISTANT_TIME);
4670 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004671 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004672 }
4673 }
4674 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004675 }
4676
Beverly5a20a5e2018-03-06 15:02:44 -05004677 @GuardedBy("mNotificationLock")
4678 private boolean isPackageSuspendedLocked(NotificationRecord r) {
4679 final String pkg = r.sbn.getPackageName();
4680 final int callingUid = r.sbn.getUid();
4681
4682 return isPackageSuspendedForUser(pkg, callingUid);
4683 }
4684
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004685 protected class PostNotificationRunnable implements Runnable {
4686 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004687
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004688 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004689 this.key = key;
4690 }
4691
4692 @Override
4693 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004694 synchronized (mNotificationLock) {
4695 try {
4696 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004697 int N = mEnqueuedNotifications.size();
4698 for (int i = 0; i < N; i++) {
4699 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4700 if (Objects.equals(key, enqueued.getKey())) {
4701 r = enqueued;
4702 break;
Chris Wren6676dab2016-12-21 18:26:27 -05004703 }
Chris Wren6676dab2016-12-21 18:26:27 -05004704 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004705 if (r == null) {
4706 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
4707 return;
4708 }
Beverly5a20a5e2018-03-06 15:02:44 -05004709
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004710 if (isBlocked(r)) {
4711 Slog.i(TAG, "notification blocked by assistant request");
4712 return;
4713 }
4714
Beverly3c707b42018-09-14 09:49:07 -04004715 final boolean isPackageSuspended = isPackageSuspendedLocked(r);
4716 r.setHidden(isPackageSuspended);
4717 if (isPackageSuspended) {
4718 mUsageStats.registerSuspendedByAdmin(r);
4719 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004720 NotificationRecord old = mNotificationsByKey.get(key);
4721 final StatusBarNotification n = r.sbn;
4722 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05004723 int index = indexOfNotificationLocked(n.getKey());
4724 if (index < 0) {
4725 mNotificationList.add(r);
4726 mUsageStats.registerPostedByApp(r);
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004727 r.setInterruptive(isVisuallyInterruptive(null, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004728 } else {
4729 old = mNotificationList.get(index);
4730 mNotificationList.set(index, r);
4731 mUsageStats.registerUpdatedByApp(r, old);
4732 // Make sure we don't lose the foreground service state.
4733 notification.flags |=
Julia Reynoldse5c60452018-04-30 14:41:36 -04004734 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
Chris Wren6676dab2016-12-21 18:26:27 -05004735 r.isUpdate = true;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04004736 r.setTextChanged(isVisuallyInterruptive(old, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004737 }
4738
4739 mNotificationsByKey.put(n.getKey(), r);
4740
4741 // Ensure if this is a foreground service that the proper additional
4742 // flags are set.
Julia Reynoldse5c60452018-04-30 14:41:36 -04004743 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
Chris Wren6676dab2016-12-21 18:26:27 -05004744 notification.flags |= Notification.FLAG_ONGOING_EVENT
4745 | Notification.FLAG_NO_CLEAR;
4746 }
4747
4748 applyZenModeLocked(r);
4749 mRankingHelper.sort(mNotificationList);
4750
4751 if (notification.getSmallIcon() != null) {
4752 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06004753 mListeners.notifyPostedLocked(r, old);
Brad Stenningd2e7a972018-10-01 09:08:42 -07004754 if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()))
4755 && !isCritical(r)) {
Julia Reynolds8aebf352017-06-26 11:35:33 -04004756 mHandler.post(new Runnable() {
4757 @Override
4758 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04004759 mGroupHelper.onNotificationPosted(
4760 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04004761 }
4762 });
4763 }
Chris Wren6676dab2016-12-21 18:26:27 -05004764 } else {
4765 Slog.e(TAG, "Not posting notification without small icon: " + notification);
4766 if (old != null && !old.isCanceled) {
Beverly5a20a5e2018-03-06 15:02:44 -05004767 mListeners.notifyRemovedLocked(r,
Julia Reynolds503ed942017-10-04 16:04:56 -04004768 NotificationListenerService.REASON_ERROR, null);
Chris Wren6676dab2016-12-21 18:26:27 -05004769 mHandler.post(new Runnable() {
4770 @Override
4771 public void run() {
4772 mGroupHelper.onNotificationRemoved(n);
4773 }
4774 });
4775 }
4776 // ATTENTION: in a future release we will bail out here
4777 // so that we do not play sounds, show lights, etc. for invalid
4778 // notifications
4779 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
4780 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05004781 }
Chris Wren47633422016-01-22 09:56:59 -05004782
Beverly5a20a5e2018-03-06 15:02:44 -05004783 if (!r.isHidden()) {
4784 buzzBeepBlinkLocked(r);
4785 }
Julia Reynolds1fac86e2018-03-07 08:30:37 -05004786 maybeRecordInterruptionLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004787 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004788 int N = mEnqueuedNotifications.size();
4789 for (int i = 0; i < N; i++) {
4790 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4791 if (Objects.equals(key, enqueued.getKey())) {
4792 mEnqueuedNotifications.remove(i);
4793 break;
4794 }
4795 }
Chris Wren6676dab2016-12-21 18:26:27 -05004796 }
Chris Wren47633422016-01-22 09:56:59 -05004797 }
4798 }
4799 }
4800
Christoph Studer265c1052014-07-23 17:14:33 +02004801 /**
Julia Reynolds7217dc92018-03-07 12:12:09 -05004802 * If the notification differs enough visually, consider it a new interruptive notification.
4803 */
4804 @GuardedBy("mNotificationLock")
4805 @VisibleForTesting
4806 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
Julia Reynolds760fa762018-06-19 15:39:23 -04004807 // Ignore summary updates because we don't display most of the information.
4808 if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
4809 if (DEBUG_INTERRUPTIVENESS) {
4810 Log.v(TAG, "INTERRUPTIVENESS: "
4811 + r.getKey() + " is not interruptive: summary");
4812 }
4813 return false;
4814 }
4815
Dan Sandler7d67bd42018-05-15 14:06:38 -04004816 if (old == null) {
4817 if (DEBUG_INTERRUPTIVENESS) {
4818 Log.v(TAG, "INTERRUPTIVENESS: "
4819 + r.getKey() + " is interruptive: new notification");
4820 }
4821 return true;
4822 }
4823
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004824 if (r == null) {
4825 if (DEBUG_INTERRUPTIVENESS) {
4826 Log.v(TAG, "INTERRUPTIVENESS: "
4827 + r.getKey() + " is not interruptive: null");
4828 }
4829 return false;
4830 }
4831
Julia Reynolds7217dc92018-03-07 12:12:09 -05004832 Notification oldN = old.sbn.getNotification();
4833 Notification newN = r.sbn.getNotification();
Dan Sandler7d67bd42018-05-15 14:06:38 -04004834
Julia Reynolds7217dc92018-03-07 12:12:09 -05004835 if (oldN.extras == null || newN.extras == null) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004836 if (DEBUG_INTERRUPTIVENESS) {
4837 Log.v(TAG, "INTERRUPTIVENESS: "
4838 + r.getKey() + " is not interruptive: no extras");
4839 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004840 return false;
4841 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004842
4843 // Ignore visual interruptions from foreground services because users
4844 // consider them one 'session'. Count them for everything else.
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004845 if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004846 if (DEBUG_INTERRUPTIVENESS) {
4847 Log.v(TAG, "INTERRUPTIVENESS: "
4848 + r.getKey() + " is not interruptive: foreground service");
4849 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004850 return false;
4851 }
4852
Dan Sandler7d67bd42018-05-15 14:06:38 -04004853 final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
4854 final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
4855 if (!Objects.equals(oldTitle, newTitle)) {
4856 if (DEBUG_INTERRUPTIVENESS) {
4857 Log.v(TAG, "INTERRUPTIVENESS: "
4858 + r.getKey() + " is interruptive: changed title");
4859 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)",
4860 oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
4861 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)",
4862 newTitle, newTitle.getClass(), newTitle.hashCode()));
4863 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004864 return true;
4865 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004866 // Do not compare Spannables (will always return false); compare unstyled Strings
4867 final String oldText = String.valueOf(oldN.extras.get(Notification.EXTRA_TEXT));
4868 final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT));
4869 if (!Objects.equals(oldText, newText)) {
4870 if (DEBUG_INTERRUPTIVENESS) {
4871 Log.v(TAG, "INTERRUPTIVENESS: "
4872 + r.getKey() + " is interruptive: changed text");
4873 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)",
4874 oldText, oldText.getClass(), oldText.hashCode()));
4875 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)",
4876 newText, newText.getClass(), newText.hashCode()));
4877 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004878 return true;
4879 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004880 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
4881 if (DEBUG_INTERRUPTIVENESS) {
4882 Log.v(TAG, "INTERRUPTIVENESS: "
4883 + r.getKey() + " is interruptive: completed progress");
4884 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004885 return true;
4886 }
4887 // Actions
4888 if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004889 if (DEBUG_INTERRUPTIVENESS) {
4890 Log.v(TAG, "INTERRUPTIVENESS: "
4891 + r.getKey() + " is interruptive: changed actions");
4892 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004893 return true;
4894 }
4895
4896 try {
4897 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
4898 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
4899
4900 // Style based comparisons
4901 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004902 if (DEBUG_INTERRUPTIVENESS) {
4903 Log.v(TAG, "INTERRUPTIVENESS: "
4904 + r.getKey() + " is interruptive: styles differ");
4905 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004906 return true;
4907 }
4908
4909 // Remote views
4910 if (Notification.areRemoteViewsChanged(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004911 if (DEBUG_INTERRUPTIVENESS) {
4912 Log.v(TAG, "INTERRUPTIVENESS: "
4913 + r.getKey() + " is interruptive: remoteviews differ");
4914 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004915 return true;
4916 }
4917 } catch (Exception e) {
4918 Slog.w(TAG, "error recovering builder", e);
4919 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004920
Julia Reynolds7217dc92018-03-07 12:12:09 -05004921 return false;
4922 }
4923
4924 /**
Brad Stenningd2e7a972018-10-01 09:08:42 -07004925 * Check if the notification is classified as critical.
4926 *
4927 * @param record the record to test for criticality
4928 * @return {@code true} if notification is considered critical
4929 *
4930 * @see CriticalNotificationExtractor for criteria
4931 */
4932 private boolean isCritical(NotificationRecord record) {
4933 // 0 is the most critical
4934 return record.getCriticality() < CriticalNotificationExtractor.NORMAL;
4935 }
4936
4937 /**
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05004938 * Keeps the last 5 packages that have notified, by user.
4939 */
4940 @GuardedBy("mNotificationLock")
4941 @VisibleForTesting
4942 protected void logRecentLocked(NotificationRecord r) {
4943 if (r.isUpdate) {
4944 return;
4945 }
4946 ArrayList<NotifyingApp> recentAppsForUser =
4947 mRecentApps.getOrDefault(r.getUser().getIdentifier(), new ArrayList<>(6));
4948 NotifyingApp na = new NotifyingApp()
4949 .setPackage(r.sbn.getPackageName())
4950 .setUid(r.sbn.getUid())
4951 .setLastNotified(r.sbn.getPostTime());
4952 // A new notification gets an app moved to the front of the list
4953 for (int i = recentAppsForUser.size() - 1; i >= 0; i--) {
4954 NotifyingApp naExisting = recentAppsForUser.get(i);
4955 if (na.getPackage().equals(naExisting.getPackage())
4956 && na.getUid() == naExisting.getUid()) {
4957 recentAppsForUser.remove(i);
4958 break;
4959 }
4960 }
4961 // time is always increasing, so always add to the front of the list
4962 recentAppsForUser.add(0, na);
4963 if (recentAppsForUser.size() > 5) {
4964 recentAppsForUser.remove(recentAppsForUser.size() -1);
4965 }
4966 mRecentApps.put(r.getUser().getIdentifier(), recentAppsForUser);
4967 }
4968
4969 /**
Christoph Studer265c1052014-07-23 17:14:33 +02004970 * Ensures that grouped notification receive their special treatment.
4971 *
4972 * <p>Cancels group children if the new notification causes a group to lose
4973 * its summary.</p>
4974 *
4975 * <p>Updates mSummaryByGroupKey.</p>
4976 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004977 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02004978 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
4979 int callingUid, int callingPid) {
4980 StatusBarNotification sbn = r.sbn;
4981 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07004982 if (n.isGroupSummary() && !sbn.isAppGroup()) {
4983 // notifications without a group shouldn't be a summary, otherwise autobundling can
4984 // lead to bugs
4985 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
4986 }
4987
Christoph Studer265c1052014-07-23 17:14:33 +02004988 String group = sbn.getGroupKey();
4989 boolean isSummary = n.isGroupSummary();
4990
4991 Notification oldN = old != null ? old.sbn.getNotification() : null;
4992 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
4993 boolean oldIsSummary = old != null && oldN.isGroupSummary();
4994
4995 if (oldIsSummary) {
4996 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
4997 if (removedSummary != old) {
4998 String removedKey =
4999 removedSummary != null ? removedSummary.getKey() : "<null>";
5000 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
5001 ", removed=" + removedKey);
5002 }
5003 }
5004 if (isSummary) {
5005 mSummaryByGroupKey.put(group, r);
5006 }
5007
5008 // Clear out group children of the old notification if the update
5009 // causes the group summary to go away. This happens when the old
5010 // notification was a summary and the new one isn't, or when the old
5011 // notification was a summary and its group key changed.
5012 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04005013 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
5014 null);
Christoph Studer265c1052014-07-23 17:14:33 +02005015 }
5016 }
5017
Chris Wren93bb8b82016-03-29 14:35:05 -04005018 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04005019 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05005020 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04005021 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05005022 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
5023 REQUEST_CODE_TIMEOUT,
5024 new Intent(ACTION_NOTIFICATION_TIMEOUT)
5025 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
5026 .appendPath(record.getKey()).build())
5027 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
5028 .putExtra(EXTRA_KEY, record.getKey()),
5029 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05005030 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04005031 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05005032 }
5033 }
5034
5035 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04005036 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04005037 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04005038 boolean buzz = false;
5039 boolean beep = false;
5040 boolean blink = false;
5041
Chris Wrena3446562014-06-03 18:11:47 -04005042 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04005043 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04005044
5045 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04005046 final boolean aboveThreshold =
5047 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04005048
5049 // Remember if this notification already owns the notification channels.
5050 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
5051 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04005052 // These are set inside the conditional if the notification is allowed to make noise.
5053 boolean hasValidVibrate = false;
5054 boolean hasValidSound = false;
Julia Reynolds94187562017-10-10 13:58:49 -04005055 boolean sentAccessibilityEvent = false;
5056 // If the notification will appear in the status bar, it should send an accessibility
5057 // event
5058 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
5059 sendAccessibilityEvent(notification, record.sbn.getPackageName());
5060 sentAccessibilityEvent = true;
5061 }
Chris Wrena3446562014-06-03 18:11:47 -04005062
Julia Reynolds76c096d2017-06-19 08:16:04 -04005063 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04005064
Julia Reynolds76c096d2017-06-19 08:16:04 -04005065 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04005066 Uri soundUri = record.getSound();
5067 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
5068 long[] vibration = record.getVibration();
5069 // Demote sound to vibration if vibration missing & phone in vibration mode.
5070 if (vibration == null
5071 && hasValidSound
5072 && (mAudioManager.getRingerModeInternal()
Julia Reynolds85896572017-09-20 12:54:52 -04005073 == AudioManager.RINGER_MODE_VIBRATE)
5074 && mAudioManager.getStreamVolume(
5075 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04005076 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04005077 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04005078 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01005079
Julia Reynolds76c096d2017-06-19 08:16:04 -04005080 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
Julia Reynolds76c096d2017-06-19 08:16:04 -04005081 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04005082 if (!sentAccessibilityEvent) {
5083 sendAccessibilityEvent(notification, record.sbn.getPackageName());
5084 sentAccessibilityEvent = true;
5085 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005086 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04005087 if (hasValidSound) {
5088 mSoundNotificationKey = key;
5089 if (mInCall) {
5090 playInCallNotification();
5091 beep = true;
5092 } else {
5093 beep = playSound(record, soundUri);
5094 }
5095 }
Chris Wren93bb8b82016-03-29 14:35:05 -04005096
Julia Reynolds7c96b582017-05-25 12:35:36 -04005097 final boolean ringerModeSilent =
5098 mAudioManager.getRingerModeInternal()
5099 == AudioManager.RINGER_MODE_SILENT;
5100 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
5101 mVibrateNotificationKey = key;
5102
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005103 buzz = playVibration(record, vibration, hasValidSound);
Julia Reynolds7c96b582017-05-25 12:35:36 -04005104 }
Tyler Gunn48f86272018-07-03 12:38:49 -07005105 } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
5106 hasValidSound = false;
Chris Wrena3446562014-06-03 18:11:47 -04005107 }
5108 }
Chris Wren93bb8b82016-03-29 14:35:05 -04005109 }
5110 // If a notification is updated to remove the actively playing sound or vibrate,
5111 // cancel that feedback now
5112 if (wasBeep && !hasValidSound) {
5113 clearSoundLocked();
5114 }
5115 if (wasBuzz && !hasValidVibrate) {
5116 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04005117 }
5118
5119 // light
5120 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04005121 boolean wasShowLights = mLights.remove(key);
Julia Reynolds28149f62018-07-03 10:43:35 -04005122 if (canShowLightsLocked(record, aboveThreshold)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04005123 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04005124 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04005125 if (mUseAttentionLight) {
5126 mAttentionLight.pulse();
5127 }
Chris Wren82ba59d2015-06-05 11:23:44 -04005128 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04005129 } else if (wasShowLights) {
5130 updateLightsLocked();
5131 }
Chris Wren82ba59d2015-06-05 11:23:44 -04005132 if (buzz || beep || blink) {
Julia Reynolds28149f62018-07-03 10:43:35 -04005133 // Ignore summary updates because we don't display most of the information.
5134 if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) {
5135 if (DEBUG_INTERRUPTIVENESS) {
5136 Log.v(TAG, "INTERRUPTIVENESS: "
5137 + record.getKey() + " is not interruptive: summary");
5138 }
5139 } else {
5140 if (DEBUG_INTERRUPTIVENESS) {
5141 Log.v(TAG, "INTERRUPTIVENESS: "
5142 + record.getKey() + " is interruptive: alerted");
5143 }
5144 record.setInterruptive(true);
5145 }
Julia Reynolds445cfa82017-05-08 15:41:45 -04005146 MetricsLogger.action(record.getLogMaker()
5147 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
5148 .setType(MetricsEvent.TYPE_OPEN)
5149 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
5150 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04005151 }
Chris Wrena3446562014-06-03 18:11:47 -04005152 }
5153
Julia Reynolds88860ce2017-06-01 16:55:49 -04005154 @GuardedBy("mNotificationLock")
Julia Reynolds28149f62018-07-03 10:43:35 -04005155 boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
5156 // device lacks light
5157 if (!mHasLight) {
5158 return false;
5159 }
5160 // user turned lights off globally
5161 if (!mNotificationPulseEnabled) {
5162 return false;
5163 }
5164 // the notification/channel has no light
5165 if (record.getLight() == null) {
5166 return false;
5167 }
5168 // unimportant notification
5169 if (!aboveThreshold) {
5170 return false;
5171 }
5172 // suppressed due to DND
5173 if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
5174 return false;
5175 }
5176 // Suppressed because it's a silent update
5177 final Notification notification = record.getNotification();
5178 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
5179 return false;
5180 }
5181 // Suppressed because another notification in its group handles alerting
5182 if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
5183 return false;
5184 }
5185 // not if in call or the screen's on
5186 if (mInCall || mScreenOn) {
5187 return false;
5188 }
5189
5190 return true;
5191 }
5192
5193 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005194 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04005195 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005196 final Notification notification = record.getNotification();
Julia Reynolds28149f62018-07-03 10:43:35 -04005197 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005198 return true;
5199 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005200
Julia Reynolds76c096d2017-06-19 08:16:04 -04005201 // muted by listener
5202 final String disableEffects = disableNotificationEffects(record);
5203 if (disableEffects != null) {
5204 ZenLog.traceDisableEffects(record, disableEffects);
5205 return true;
5206 }
5207
5208 // suppressed due to DND
5209 if (record.isIntercepted()) {
5210 return true;
5211 }
5212
5213 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005214 if (record.sbn.isGroup()) {
Julia Reynolds79dfdd62018-04-17 15:36:33 -04005215 if (notification.suppressAlertingDueToGrouping()) {
5216 return true;
5217 }
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005218 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005219
Julia Reynolds65b85cf2017-07-20 09:19:20 -04005220 // Suppressed for being too recently noisy
5221 final String pkg = record.sbn.getPackageName();
5222 if (mUsageStats.isAlertRateLimited(pkg)) {
5223 Slog.e(TAG, "Muting recently noisy " + record.getKey());
5224 return true;
5225 }
5226
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005227 return false;
5228 }
5229
Julia Reynolds0c299d42016-11-15 14:37:04 -05005230 private boolean playSound(final NotificationRecord record, Uri soundUri) {
5231 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
Jean-Michel Triviec2bb182018-03-23 18:04:00 -07005232 // play notifications if there is no user of exclusive audio focus
5233 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
5234 // VIBRATE ringer mode)
5235 if (!mAudioManager.isAudioFocusExclusive()
5236 && (mAudioManager.getStreamVolume(
5237 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05005238 final long identity = Binder.clearCallingIdentity();
5239 try {
5240 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5241 if (player != null) {
5242 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
5243 + " with attributes " + record.getAudioAttributes());
5244 player.playAsync(soundUri, record.sbn.getUser(), looping,
5245 record.getAudioAttributes());
5246 return true;
5247 }
5248 } catch (RemoteException e) {
5249 } finally {
5250 Binder.restoreCallingIdentity(identity);
5251 }
5252 }
5253 return false;
5254 }
5255
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005256 private boolean playVibration(final NotificationRecord record, long[] vibration,
5257 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005258 // Escalate privileges so we can use the vibrator even if the
5259 // notifying app does not have the VIBRATE permission.
5260 long identity = Binder.clearCallingIdentity();
5261 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005262 final VibrationEffect effect;
5263 try {
5264 final boolean insistent =
5265 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
5266 effect = VibrationEffect.createWaveform(
5267 vibration, insistent ? 0 : -1 /*repeatIndex*/);
5268 } catch (IllegalArgumentException e) {
5269 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
5270 Arrays.toString(vibration));
5271 return false;
5272 }
5273 if (delayVibForSound) {
5274 new Thread(() -> {
5275 // delay the vibration by the same amount as the notification sound
5276 final int waitMs = mAudioManager.getFocusRampTimeMs(
5277 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
5278 record.getAudioAttributes());
5279 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
5280 try {
5281 Thread.sleep(waitMs);
5282 } catch (InterruptedException e) { }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04005283 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01005284 effect, "Notification (delayed)", record.getAudioAttributes());
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005285 }).start();
5286 } else {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04005287 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01005288 effect, "Notification", record.getAudioAttributes());
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005289 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005290 return true;
5291 } finally{
5292 Binder.restoreCallingIdentity(identity);
5293 }
5294 }
5295
Julia Reynolds7c96b582017-05-25 12:35:36 -04005296 private boolean isNotificationForCurrentUser(NotificationRecord record) {
5297 final int currentUser;
5298 final long token = Binder.clearCallingIdentity();
5299 try {
5300 currentUser = ActivityManager.getCurrentUser();
5301 } finally {
5302 Binder.restoreCallingIdentity(token);
5303 }
5304 return (record.getUserId() == UserHandle.USER_ALL ||
5305 record.getUserId() == currentUser ||
5306 mUserProfiles.isCurrentProfile(record.getUserId()));
5307 }
5308
Beverly5d463b62017-07-26 14:13:40 -04005309 protected void playInCallNotification() {
Beverly28c3d162018-06-28 11:37:53 -04005310 if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL
5311 && Settings.Secure.getInt(getContext().getContentResolver(),
5312 Settings.Secure.IN_CALL_NOTIFICATION_ENABLED, 1) != 0) {
5313 new Thread() {
5314 @Override
5315 public void run() {
5316 final long identity = Binder.clearCallingIdentity();
5317 try {
5318 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5319 if (player != null) {
5320 if (mCallNotificationToken != null) {
5321 player.stop(mCallNotificationToken);
5322 }
5323 mCallNotificationToken = new Binder();
5324 player.play(mCallNotificationToken, mInCallNotificationUri,
5325 mInCallNotificationAudioAttributes,
5326 mInCallNotificationVolume, false);
luochaojiang50e5273c2018-04-16 16:55:03 +08005327 }
Beverly28c3d162018-06-28 11:37:53 -04005328 } catch (RemoteException e) {
5329 } finally {
5330 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01005331 }
Marta Białka39c992f2011-03-10 10:27:24 +01005332 }
Beverly28c3d162018-06-28 11:37:53 -04005333 }.start();
5334 }
Marta Białka39c992f2011-03-10 10:27:24 +01005335 }
5336
Julia Reynolds88860ce2017-06-01 16:55:49 -04005337 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005338 void showNextToastLocked() {
5339 ToastRecord record = mToastQueue.get(0);
5340 while (record != null) {
5341 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
5342 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005343 record.callback.show(record.token);
Robert Carr997427342018-02-28 18:06:10 -08005344 scheduleDurationReachedLocked(record);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005345 return;
5346 } catch (RemoteException e) {
5347 Slog.w(TAG, "Object died trying to show notification " + record.callback
5348 + " in package " + record.pkg);
5349 // remove it from the list and let the process die
5350 int index = mToastQueue.indexOf(record);
5351 if (index >= 0) {
5352 mToastQueue.remove(index);
5353 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005354 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005355 if (mToastQueue.size() > 0) {
5356 record = mToastQueue.get(0);
5357 } else {
5358 record = null;
5359 }
5360 }
5361 }
5362 }
5363
Julia Reynolds88860ce2017-06-01 16:55:49 -04005364 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005365 void cancelToastLocked(int index) {
5366 ToastRecord record = mToastQueue.get(index);
5367 try {
5368 record.callback.hide();
5369 } catch (RemoteException e) {
5370 Slog.w(TAG, "Object died trying to hide notification " + record.callback
5371 + " in package " + record.pkg);
5372 // don't worry about this, we're about to remove it from
5373 // the list anyway
5374 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005375
5376 ToastRecord lastToast = mToastQueue.remove(index);
Robert Carr997427342018-02-28 18:06:10 -08005377
5378 mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
Jeff Chang48ecef42018-08-09 16:31:59 +08005379 lastToast.displayId);
Robert Carr997427342018-02-28 18:06:10 -08005380 // We passed 'false' for 'removeWindows' so that the client has time to stop
5381 // rendering (as hide above is a one-way message), otherwise we could crash
5382 // a client which was actively using a surface made from the token. However
5383 // we need to schedule a timeout to make sure the token is eventually killed
5384 // one way or another.
Jeff Chang48ecef42018-08-09 16:31:59 +08005385 scheduleKillTokenTimeout(lastToast);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005386
5387 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005388 if (mToastQueue.size() > 0) {
5389 // Show the next one. If the callback fails, this will remove
5390 // it from the list, so don't assume that the list hasn't changed
5391 // after this point.
5392 showNextToastLocked();
5393 }
5394 }
5395
Jeff Chang48ecef42018-08-09 16:31:59 +08005396 void finishTokenLocked(IBinder t, int displayId) {
Robert Carr997427342018-02-28 18:06:10 -08005397 mHandler.removeCallbacksAndMessages(t);
5398 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
5399 // remaining surfaces as either the client has called finishToken indicating
5400 // it has successfully removed the views, or the client has timed out
5401 // at which point anything goes.
Jeff Chang48ecef42018-08-09 16:31:59 +08005402 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */, displayId);
Robert Carr997427342018-02-28 18:06:10 -08005403 }
5404
Julia Reynolds88860ce2017-06-01 16:55:49 -04005405 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08005406 private void scheduleDurationReachedLocked(ToastRecord r)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005407 {
5408 mHandler.removeCallbacksAndMessages(r);
Robert Carr997427342018-02-28 18:06:10 -08005409 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005410 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
5411 mHandler.sendMessageDelayed(m, delay);
5412 }
5413
Robert Carr997427342018-02-28 18:06:10 -08005414 private void handleDurationReached(ToastRecord record)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005415 {
5416 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
5417 synchronized (mToastQueue) {
5418 int index = indexOfToastLocked(record.pkg, record.callback);
5419 if (index >= 0) {
5420 cancelToastLocked(index);
5421 }
5422 }
5423 }
5424
Julia Reynolds88860ce2017-06-01 16:55:49 -04005425 @GuardedBy("mToastQueue")
Jeff Chang48ecef42018-08-09 16:31:59 +08005426 private void scheduleKillTokenTimeout(ToastRecord r)
Robert Carr997427342018-02-28 18:06:10 -08005427 {
Jeff Chang48ecef42018-08-09 16:31:59 +08005428 mHandler.removeCallbacksAndMessages(r);
5429 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, r);
Robert Carr3406d462018-03-15 16:19:07 -07005430 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
Robert Carr997427342018-02-28 18:06:10 -08005431 }
5432
Jeff Chang48ecef42018-08-09 16:31:59 +08005433 private void handleKillTokenTimeout(ToastRecord record)
Robert Carr997427342018-02-28 18:06:10 -08005434 {
Jeff Chang48ecef42018-08-09 16:31:59 +08005435 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.token);
Robert Carr997427342018-02-28 18:06:10 -08005436 synchronized (mToastQueue) {
Jeff Chang48ecef42018-08-09 16:31:59 +08005437 finishTokenLocked(record.token, record.displayId);
Robert Carr997427342018-02-28 18:06:10 -08005438 }
5439 }
5440
5441 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005442 int indexOfToastLocked(String pkg, ITransientNotification callback)
5443 {
5444 IBinder cbak = callback.asBinder();
5445 ArrayList<ToastRecord> list = mToastQueue;
5446 int len = list.size();
5447 for (int i=0; i<len; i++) {
5448 ToastRecord r = list.get(i);
Beverly Taia7ed0ab2018-06-11 14:50:36 +00005449 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08005450 return i;
5451 }
5452 }
5453 return -1;
5454 }
5455
Julia Reynolds88860ce2017-06-01 16:55:49 -04005456 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005457 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005458 {
5459 int toastCount = 0; // toasts from this pid
5460 ArrayList<ToastRecord> list = mToastQueue;
5461 int N = list.size();
5462 for (int i=0; i<N; i++) {
5463 ToastRecord r = list.get(i);
5464 if (r.pid == pid) {
5465 toastCount++;
5466 }
5467 }
5468 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07005469 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08005470 } catch (RemoteException e) {
5471 // Shouldn't happen.
5472 }
5473 }
5474
Chris Wrenf9536642014-04-17 10:01:54 -04005475 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005476 if (!(message.obj instanceof RankingReconsideration)) return;
5477 RankingReconsideration recon = (RankingReconsideration) message.obj;
5478 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04005479 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005480 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005481 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
5482 if (record == null) {
5483 return;
Chris Wrenf9536642014-04-17 10:01:54 -04005484 }
Chris Wren333a61c2014-05-28 16:40:57 -04005485 int indexBefore = findNotificationRecordIndexLocked(record);
5486 boolean interceptBefore = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005487 float contactAffinityBefore = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005488 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04005489 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04005490 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04005491 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04005492 int indexAfter = findNotificationRecordIndexLocked(record);
5493 boolean interceptAfter = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005494 float contactAffinityAfter = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005495 int visibilityAfter = record.getPackageVisibilityOverride();
5496 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
5497 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005498 if (interceptBefore && !interceptAfter
5499 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
Chris Wrena3446562014-06-03 18:11:47 -04005500 buzzBeepBlinkLocked(record);
5501 }
Chris Wrenf9536642014-04-17 10:01:54 -04005502 }
Chris Wren333a61c2014-05-28 16:40:57 -04005503 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005504 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04005505 }
5506 }
5507
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005508 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04005509 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005510 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04005511 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005512 // Any field that can change via one of the extractors needs to be added here.
5513 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005514 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05005515 boolean[] showBadges = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005516 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
5517 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
5518 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
5519 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Julia Reynolds503ed942017-10-04 16:04:56 -04005520 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005521 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
Tony Mak628cb932018-06-19 18:30:41 +01005522 ArrayList<ArrayList<Notification.Action>> smartActionsBefore = new ArrayList<>(N);
Tony Makc9acf672018-07-20 13:58:24 +02005523 ArrayList<ArrayList<CharSequence>> smartRepliesBefore = new ArrayList<>(N);
Chris Wren54bbef42014-07-09 18:37:56 -04005524 for (int i = 0; i < N; i++) {
5525 final NotificationRecord r = mNotificationList.get(i);
5526 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005527 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05005528 showBadges[i] = r.canShowBadge();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005529 channelBefore.add(r.getChannel());
5530 groupKeyBefore.add(r.getGroupKey());
5531 overridePeopleBefore.add(r.getPeopleOverride());
5532 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Julia Reynolds503ed942017-10-04 16:04:56 -04005533 userSentimentBefore.add(r.getUserSentiment());
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005534 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
Tony Mak628cb932018-06-19 18:30:41 +01005535 smartActionsBefore.add(r.getSmartActions());
Tony Makc9acf672018-07-20 13:58:24 +02005536 smartRepliesBefore.add(r.getSmartReplies());
Chris Wren54bbef42014-07-09 18:37:56 -04005537 mRankingHelper.extractSignals(r);
5538 }
Chris Wren19a02b02015-12-22 10:34:22 -05005539 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04005540 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005541 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005542 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05005543 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005544 || showBadges[i] != r.canShowBadge()
5545 || !Objects.equals(channelBefore.get(i), r.getChannel())
5546 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
5547 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
Julia Reynolds503ed942017-10-04 16:04:56 -04005548 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005549 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
5550 || !Objects.equals(suppressVisuallyBefore.get(i),
Tony Mak628cb932018-06-19 18:30:41 +01005551 r.getSuppressedVisualEffects())
Tony Makc9acf672018-07-20 13:58:24 +02005552 || !Objects.equals(smartActionsBefore.get(i), r.getSmartActions())
5553 || !Objects.equals(smartRepliesBefore.get(i), r.getSmartReplies())) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005554 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04005555 return;
5556 }
5557 }
5558 }
5559 }
5560
Julia Reynolds88860ce2017-06-01 16:55:49 -04005561 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005562 private void recordCallerLocked(NotificationRecord record) {
5563 if (mZenModeHelper.isCall(record)) {
5564 mZenModeHelper.recordCaller(record);
5565 }
5566 }
5567
Christoph Studerd5092bc2014-07-03 17:47:58 +02005568 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04005569 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005570 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02005571 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005572 if (record.isIntercepted()) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05005573 record.setSuppressedVisualEffects(
5574 mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
Julia Reynolds445cfa82017-05-08 15:41:45 -04005575 } else {
5576 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005577 }
Chris Wren333a61c2014-05-28 16:40:57 -04005578 }
5579
Julia Reynolds88860ce2017-06-01 16:55:49 -04005580 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04005581 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04005582 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04005583 }
5584
Chris Wrenf9536642014-04-17 10:01:54 -04005585 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005586 synchronized (mNotificationLock) {
Beverly5a20a5e2018-03-06 15:02:44 -05005587 mListeners.notifyRankingUpdateLocked(null);
Chris Wrenf9536642014-04-17 10:01:54 -04005588 }
5589 }
5590
John Spurlockd8afe3c2014-08-01 14:04:07 -04005591 private void scheduleListenerHintsChanged(int state) {
5592 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
5593 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04005594 }
5595
Christoph Studer85a384b2014-08-27 20:16:15 +02005596 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
5597 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
5598 mHandler.obtainMessage(
5599 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
5600 listenerInterruptionFilter,
5601 0).sendToTarget();
5602 }
5603
John Spurlockd8afe3c2014-08-01 14:04:07 -04005604 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005605 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005606 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005607 }
5608 }
5609
Christoph Studer85a384b2014-08-27 20:16:15 +02005610 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005611 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02005612 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
5613 }
5614 }
5615
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005616 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08005617 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005618 public WorkerHandler(Looper looper) {
5619 super(looper);
5620 }
5621
Adam Lesinski182f73f2013-12-05 16:48:06 -08005622 @Override
5623 public void handleMessage(Message msg)
5624 {
5625 switch (msg.what)
5626 {
Robert Carr997427342018-02-28 18:06:10 -08005627 case MESSAGE_DURATION_REACHED:
5628 handleDurationReached((ToastRecord)msg.obj);
5629 break;
5630 case MESSAGE_FINISH_TOKEN_TIMEOUT:
Jeff Chang48ecef42018-08-09 16:31:59 +08005631 handleKillTokenTimeout((ToastRecord)msg.obj);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005632 break;
John Spurlock056c5192014-04-20 21:52:01 -04005633 case MESSAGE_SAVE_POLICY_FILE:
5634 handleSavePolicyFile();
5635 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005636 case MESSAGE_SEND_RANKING_UPDATE:
5637 handleSendRankingUpdate();
5638 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04005639 case MESSAGE_LISTENER_HINTS_CHANGED:
5640 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04005641 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02005642 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
5643 handleListenerInterruptionFilterChanged(msg.arg1);
5644 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005645 }
5646 }
5647
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005648 protected void scheduleSendRankingUpdate() {
5649 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
5650 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
5651 sendMessage(m);
5652 }
5653 }
5654
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005655 protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable) {
5656 if (!hasCallbacks(cancelRunnable)) {
5657 sendMessage(Message.obtain(this, cancelRunnable));
5658 }
5659 }
Chris Wrenf9536642014-04-17 10:01:54 -04005660 }
5661
Chris Wren51017d02015-12-15 15:34:46 -05005662 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04005663 {
Chris Wren51017d02015-12-15 15:34:46 -05005664 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04005665 super(looper);
5666 }
5667
5668 @Override
5669 public void handleMessage(Message msg) {
5670 switch (msg.what) {
5671 case MESSAGE_RECONSIDER_RANKING:
5672 handleRankingReconsideration(msg);
5673 break;
Chris Wren51017d02015-12-15 15:34:46 -05005674 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005675 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04005676 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08005677 }
5678 }
Chris Wren51017d02015-12-15 15:34:46 -05005679
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005680 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05005681 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05005682 Message msg = Message.obtain();
5683 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05005684 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05005685 }
5686
5687 public void requestReconsideration(RankingReconsideration recon) {
5688 Message m = Message.obtain(this,
5689 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
5690 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
5691 sendMessageDelayed(m, delay);
5692 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08005693 }
5694
Adam Lesinski182f73f2013-12-05 16:48:06 -08005695 // Notifications
5696 // ============================================================================
5697 static int clamp(int x, int low, int high) {
5698 return (x < low) ? low : ((x > high) ? high : x);
5699 }
5700
5701 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
Eugene Suslad4128ec2017-12-04 19:48:41 +00005702 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07005703 return;
5704 }
5705
5706 AccessibilityEvent event =
5707 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
5708 event.setPackageName(packageName);
5709 event.setClassName(Notification.class.getName());
5710 event.setParcelableData(notification);
5711 CharSequence tickerText = notification.tickerText;
5712 if (!TextUtils.isEmpty(tickerText)) {
5713 event.getText().add(tickerText);
5714 }
5715
Julia Reynolds94187562017-10-10 13:58:49 -04005716 mAccessibilityManager.sendAccessibilityEvent(event);
svetoslavganov75986cf2009-05-14 22:28:01 -07005717 }
5718
Julia Reynolds0839c022017-06-15 15:24:01 -04005719 /**
5720 * Removes all NotificationsRecords with the same key as the given notification record
5721 * from both lists. Do not call this method while iterating over either list.
5722 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005723 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04005724 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
5725 // Remove from both lists, either list could have a separate Record for what is
5726 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005727 boolean wasPosted = false;
5728 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04005729 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
5730 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005731 mNotificationList.remove(recordInList);
5732 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005733 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005734 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005735 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005736 != null) {
5737 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005738 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005739 return wasPosted;
5740 }
5741
5742 @GuardedBy("mNotificationLock")
5743 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04005744 boolean wasPosted, String listenerName) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005745 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName);
5746 }
5747
5748 @GuardedBy("mNotificationLock")
5749 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
5750 int rank, int count, boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04005751 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005752
5753 // Record caller.
5754 recordCallerLocked(r);
5755
Julia Reynolds503ed942017-10-04 16:04:56 -04005756 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
5757 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
5758 }
5759
Joe Onorato46439ce2010-11-19 13:56:21 -08005760 // tell the app
5761 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005762 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08005763 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005764 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08005765 } catch (PendingIntent.CanceledException ex) {
5766 // do nothing - there's no relevant way to recover, and
5767 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04005768 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08005769 }
5770 }
5771 }
5772
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005773 // Only cancel these if this notification actually got to be posted.
5774 if (wasPosted) {
5775 // status bar
5776 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005777 if (reason != REASON_SNOOZED) {
5778 r.isCanceled = true;
5779 }
Beverly5a20a5e2018-03-06 15:02:44 -05005780 mListeners.notifyRemovedLocked(r, reason, r.getStats());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005781 mHandler.post(new Runnable() {
5782 @Override
5783 public void run() {
5784 mGroupHelper.onNotificationRemoved(r.sbn);
5785 }
5786 });
5787 }
5788
5789 // sound
5790 if (canceledKey.equals(mSoundNotificationKey)) {
5791 mSoundNotificationKey = null;
5792 final long identity = Binder.clearCallingIdentity();
5793 try {
5794 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5795 if (player != null) {
5796 player.stopAsync();
5797 }
5798 } catch (RemoteException e) {
5799 } finally {
5800 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04005801 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005802 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005803
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005804 // vibrate
5805 if (canceledKey.equals(mVibrateNotificationKey)) {
5806 mVibrateNotificationKey = null;
5807 long identity = Binder.clearCallingIdentity();
5808 try {
5809 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005810 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005811 finally {
5812 Binder.restoreCallingIdentity(identity);
5813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005814 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005815
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005816 // light
5817 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005818 }
5819
Christoph Studer546bec82014-03-14 12:17:12 +01005820 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04005821 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01005822 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005823 case REASON_CANCEL:
5824 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005825 case REASON_LISTENER_CANCEL:
5826 case REASON_LISTENER_CANCEL_ALL:
5827 mUsageStats.registerDismissedByUser(r);
5828 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05005829 case REASON_APP_CANCEL:
5830 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005831 mUsageStats.registerRemovedByApp(r);
5832 break;
Christoph Studer546bec82014-03-14 12:17:12 +01005833 }
5834
Christoph Studer265c1052014-07-23 17:14:33 +02005835 String groupKey = r.getGroupKey();
5836 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005837 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02005838 mSummaryByGroupKey.remove(groupKey);
5839 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04005840 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
5841 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
5842 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04005843 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005844
Daniel Sandler23d7c702013-03-07 16:32:06 -05005845 // Save it for users of getHistoricalNotifications()
5846 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02005847
Chris Wren6650e572015-05-15 17:19:25 -04005848 final long now = System.currentTimeMillis();
Julia Reynolds3dfdde02018-10-08 09:17:56 -04005849 final LogMaker logMaker = r.getItemLogMaker()
Chris Wren9eb5e102017-01-26 13:15:06 -05005850 .setType(MetricsEvent.TYPE_DISMISS)
Dieter Hsud39f0d52018-04-14 02:08:30 +08005851 .setSubtype(reason);
5852 if (rank != -1 && count != -1) {
5853 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
5854 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
5855 }
5856 MetricsLogger.action(logMaker);
Chris Wrene6ddb8a2015-05-27 15:21:00 -04005857 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Dieter Hsud39f0d52018-04-14 02:08:30 +08005858 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
5859 rank, count, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005860 }
5861
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005862 @VisibleForTesting
5863 void updateUriPermissions(@Nullable NotificationRecord newRecord,
5864 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) {
5865 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey();
5866 if (DBG) Slog.d(TAG, key + ": updating permissions");
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005867
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005868 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null;
5869 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null;
5870
5871 // Shortcut when no Uris involved
5872 if (newUris == null && oldUris == null) {
5873 return;
5874 }
5875
5876 // Inherit any existing owner
5877 IBinder permissionOwner = null;
5878 if (newRecord != null && permissionOwner == null) {
5879 permissionOwner = newRecord.permissionOwner;
5880 }
5881 if (oldRecord != null && permissionOwner == null) {
5882 permissionOwner = oldRecord.permissionOwner;
5883 }
5884
5885 // If we have Uris to grant, but no owner yet, go create one
5886 if (newUris != null && permissionOwner == null) {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07005887 if (DBG) Slog.d(TAG, key + ": creating owner");
5888 permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005889 }
5890
5891 // If we have no Uris to grant, but an existing owner, go destroy it
5892 if (newUris == null && permissionOwner != null) {
5893 final long ident = Binder.clearCallingIdentity();
5894 try {
5895 if (DBG) Slog.d(TAG, key + ": destroying owner");
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07005896 mUgmInternal.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005897 UserHandle.getUserId(oldRecord.getUid()));
5898 permissionOwner = null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005899 } finally {
5900 Binder.restoreCallingIdentity(ident);
5901 }
5902 }
5903
5904 // Grant access to new Uris
5905 if (newUris != null && permissionOwner != null) {
5906 for (int i = 0; i < newUris.size(); i++) {
5907 final Uri uri = newUris.valueAt(i);
5908 if (oldUris == null || !oldUris.contains(uri)) {
5909 if (DBG) Slog.d(TAG, key + ": granting " + uri);
5910 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
5911 targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005912 }
5913 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005914 }
5915
5916 // Revoke access to old Uris
5917 if (oldUris != null && permissionOwner != null) {
5918 for (int i = 0; i < oldUris.size(); i++) {
5919 final Uri uri = oldUris.valueAt(i);
5920 if (newUris == null || !newUris.contains(uri)) {
5921 if (DBG) Slog.d(TAG, key + ": revoking " + uri);
5922 revokeUriPermission(permissionOwner, uri, oldRecord.getUid());
5923 }
5924 }
5925 }
5926
5927 if (newRecord != null) {
5928 newRecord.permissionOwner = permissionOwner;
5929 }
5930 }
5931
5932 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg,
5933 int targetUserId) {
5934 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5935
5936 final long ident = Binder.clearCallingIdentity();
5937 try {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07005938 mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005939 ContentProvider.getUriWithoutUserId(uri),
5940 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5941 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
5942 targetUserId);
5943 } catch (RemoteException ignored) {
5944 // Ignored because we're in same process
5945 } finally {
5946 Binder.restoreCallingIdentity(ident);
5947 }
5948 }
5949
5950 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUid) {
5951 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5952
5953 final long ident = Binder.clearCallingIdentity();
5954 try {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07005955 mUgmInternal.revokeUriPermissionFromOwner(
5956 owner,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005957 ContentProvider.getUriWithoutUserId(uri),
5958 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5959 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005960 } finally {
5961 Binder.restoreCallingIdentity(ident);
5962 }
5963 }
5964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005965 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07005966 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005967 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005968 */
John Spurlocke6a7d932014-03-13 12:29:00 -04005969 void cancelNotification(final int callingUid, final int callingPid,
5970 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005971 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04005972 final int userId, final int reason, final ManagedServiceInfo listener) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005973 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
5974 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
5975 }
5976
5977 /**
5978 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
5979 * and none of the {@code mustNotHaveFlags}.
5980 */
5981 void cancelNotification(final int callingUid, final int callingPid,
5982 final String pkg, final String tag, final int id,
5983 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005984 final int userId, final int reason, int rank, int count,
5985 final ManagedServiceInfo listener) {
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005986 // In enqueueNotificationInternal notifications are added by scheduling the
5987 // work on the worker handler. Hence, we also schedule the cancel on this
5988 // handler to avoid a scenario where an add notification call followed by a
5989 // remove notification call ends up in not removing the notification.
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005990 mHandler.scheduleCancelNotification(new CancelNotificationRunnable(callingUid, callingPid,
5991 pkg, tag, id, mustHaveFlags, mustNotHaveFlags, sendDelete, userId, reason, rank,
5992 count, listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005993 }
5994
5995 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07005996 * Determine whether the userId applies to the notification in question, either because
5997 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
5998 */
5999 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
6000 return
6001 // looking for USER_ALL notifications? match everything
6002 userId == UserHandle.USER_ALL
6003 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05006004 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07006005 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05006006 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07006007 }
6008
6009 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006010 * Determine whether the userId applies to the notification in question, either because
6011 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01006012 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006013 */
Kenny Guy2a764942014-04-02 13:29:20 +01006014 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00006015 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04006016 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006017 }
6018
6019 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05006020 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006021 * {@code mustHaveFlags}.
6022 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006023 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04006024 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04006025 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006026 mHandler.post(new Runnable() {
6027 @Override
6028 public void run() {
6029 String listenerName = listener == null ? null : listener.component.toShortString();
6030 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
6031 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
6032 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006033
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006034 // Why does this parameter exist? Do we actually want to execute the above if doit
6035 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08006036 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006037 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08006038 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006039
6040 synchronized (mNotificationLock) {
6041 FlagChecker flagChecker = (int flags) -> {
6042 if ((flags & mustHaveFlags) != mustHaveFlags) {
6043 return false;
6044 }
6045 if ((flags & mustNotHaveFlags) != 0) {
6046 return false;
6047 }
6048 return true;
6049 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006050 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
6051 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
6052 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04006053 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006054 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
6055 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
6056 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04006057 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006058 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02006059 }
6060 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006061 });
6062 }
6063
6064 private interface FlagChecker {
6065 // Returns false if these flags do not pass the defined flag test.
6066 public boolean apply(int flags);
6067 }
6068
Julia Reynolds88860ce2017-06-01 16:55:49 -04006069 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006070 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
6071 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
6072 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04006073 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006074 ArrayList<NotificationRecord> canceledNotifications = null;
6075 for (int i = notificationList.size() - 1; i >= 0; --i) {
6076 NotificationRecord r = notificationList.get(i);
6077 if (includeCurrentProfiles) {
6078 if (!notificationMatchesCurrentProfiles(r, userId)) {
6079 continue;
6080 }
6081 } else if (!notificationMatchesUserId(r, userId)) {
6082 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006083 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006084 // Don't remove notifications to all, if there's no package name specified
6085 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
6086 continue;
6087 }
6088 if (!flagChecker.apply(r.getFlags())) {
6089 continue;
6090 }
6091 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
6092 continue;
6093 }
6094 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
6095 continue;
6096 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006097 if (canceledNotifications == null) {
6098 canceledNotifications = new ArrayList<>();
6099 }
Julia Reynolds0839c022017-06-15 15:24:01 -04006100 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04006101 mNotificationsByKey.remove(r.getKey());
Julia Reynoldsfd4099d2018-08-21 11:06:06 -04006102 r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006103 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04006104 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006105 }
6106 if (canceledNotifications != null) {
6107 final int M = canceledNotifications.size();
6108 for (int i = 0; i < M; i++) {
6109 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04006110 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006111 }
6112 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006113 }
6114 }
6115
Julia Reynolds50989772017-02-23 14:32:16 -05006116 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006117 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05006118 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05006119 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05006120 return;
6121 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05006122
Julia Reynolds79672302017-01-12 08:30:16 -05006123 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05006124 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
6125 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05006126 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006127 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006128 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006129 }
6130
6131 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
6132 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006133 if (DBG) {
6134 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
6135 }
Julia Reynolds79672302017-01-12 08:30:16 -05006136 mSnoozeHelper.repost(key);
6137 savePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006138 }
6139
Julia Reynolds88860ce2017-06-01 16:55:49 -04006140 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07006141 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04006142 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006143 mHandler.post(new Runnable() {
6144 @Override
6145 public void run() {
6146 synchronized (mNotificationLock) {
6147 String listenerName =
6148 listener == null ? null : listener.component.toShortString();
6149 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
6150 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01006151
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006152 FlagChecker flagChecker = (int flags) -> {
6153 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
6154 != 0) {
6155 return false;
6156 }
6157 return true;
6158 };
6159
6160 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
6161 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
6162 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04006163 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006164 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
6165 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
6166 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04006167 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006168 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00006169 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006170 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006171 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006172 }
6173
Christoph Studere4ef156b2014-07-04 18:41:57 +02006174 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04006175 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02006176 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04006177 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02006178 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02006179 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02006180 return;
6181 }
6182
6183 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02006184
6185 if (pkg == null) {
6186 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
6187 return;
6188 }
6189
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006190 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04006191 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006192 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04006193 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006194 }
6195
Julia Reynolds88860ce2017-06-01 16:55:49 -04006196 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006197 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
6198 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04006199 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006200 final String pkg = parentNotification.sbn.getPackageName();
6201 final int userId = parentNotification.getUserId();
6202 final int reason = REASON_GROUP_SUMMARY_CANCELED;
6203 for (int i = notificationList.size() - 1; i >= 0; i--) {
6204 final NotificationRecord childR = notificationList.get(i);
6205 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04006206 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006207 childR.getGroupKey().equals(parentNotification.getGroupKey())
Julia Reynoldse5c60452018-04-30 14:41:36 -04006208 && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
Beverly40239d92017-07-07 10:20:41 -04006209 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02006210 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
6211 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04006212 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04006213 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04006214 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02006215 }
6216 }
6217 }
6218
Julia Reynolds88860ce2017-06-01 16:55:49 -04006219 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08006220 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006221 {
The Android Open Source Project10592532009-03-18 17:39:46 -07006222 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05006223 NotificationRecord ledNotification = null;
6224 while (ledNotification == null && !mLights.isEmpty()) {
6225 final String owner = mLights.get(mLights.size() - 1);
6226 ledNotification = mNotificationsByKey.get(owner);
6227 if (ledNotification == null) {
6228 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
6229 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006230 }
6231 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006232
Mike Lockwood63b5ad92011-08-30 09:55:30 -04006233 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05006234 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05006235 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07006236 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006237 NotificationRecord.Light light = ledNotification.getLight();
6238 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05006239 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006240 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
6241 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05006242 }
The Android Open Source Project10592532009-03-18 17:39:46 -07006243 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006244 }
6245
Julia Reynolds88860ce2017-06-01 16:55:49 -04006246 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006247 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
6248 String groupKey, int userId) {
6249 List<NotificationRecord> records = new ArrayList<>();
6250 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
6251 records.addAll(
6252 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
6253 return records;
6254 }
6255
6256
Julia Reynolds88860ce2017-06-01 16:55:49 -04006257 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006258 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
6259 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
6260 List<NotificationRecord> records = new ArrayList<>();
6261 final int len = list.size();
6262 for (int i = 0; i < len; i++) {
6263 NotificationRecord r = list.get(i);
6264 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
6265 && r.sbn.getPackageName().equals(pkg)) {
6266 records.add(r);
6267 }
6268 }
6269 return records;
6270 }
6271
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006272 // Searches both enqueued and posted notifications by key.
6273 // TODO: need to combine a bunch of these getters with slightly different behavior.
6274 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04006275 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006276 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006277 NotificationRecord r;
6278 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
6279 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006280 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006281 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
6282 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006283 }
6284 return null;
6285 }
6286
Julia Reynolds88860ce2017-06-01 16:55:49 -04006287 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006288 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006289 NotificationRecord r;
6290 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
6291 return r;
6292 }
6293 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
6294 != null) {
6295 return r;
6296 }
6297 return null;
6298 }
6299
Julia Reynolds88860ce2017-06-01 16:55:49 -04006300 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006301 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006302 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006303 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006304 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006305 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01006306 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
6307 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006308 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006309 }
6310 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006311 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006312 }
6313
Julia Reynolds88860ce2017-06-01 16:55:49 -04006314 @GuardedBy("mNotificationLock")
Julia Reynolds564273f2018-09-13 15:53:11 -04006315 private List<NotificationRecord> findNotificationsByListLocked(
6316 ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) {
6317 List<NotificationRecord> matching = new ArrayList<>();
6318 final int len = list.size();
6319 for (int i = 0; i < len; i++) {
6320 NotificationRecord r = list.get(i);
6321 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
6322 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
6323 matching.add(r);
6324 }
6325 }
6326 return matching;
6327 }
6328
6329 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006330 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04006331 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006332 final int N = list.size();
6333 for (int i = 0; i < N; i++) {
6334 if (key.equals(list.get(i).getKey())) {
6335 return list.get(i);
6336 }
6337 }
6338 return null;
6339 }
6340
Julia Reynolds88860ce2017-06-01 16:55:49 -04006341 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02006342 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02006343 final int N = mNotificationList.size();
6344 for (int i = 0; i < N; i++) {
6345 if (key.equals(mNotificationList.get(i).getKey())) {
6346 return i;
6347 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02006348 }
Christoph Studerc5115552014-06-12 20:22:31 +02006349 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02006350 }
6351
Beverly5a20a5e2018-03-06 15:02:44 -05006352 @VisibleForTesting
6353 protected void hideNotificationsForPackages(String[] pkgs) {
6354 synchronized (mNotificationLock) {
6355 List<String> pkgList = Arrays.asList(pkgs);
6356 List<NotificationRecord> changedNotifications = new ArrayList<>();
6357 int numNotifications = mNotificationList.size();
6358 for (int i = 0; i < numNotifications; i++) {
6359 NotificationRecord rec = mNotificationList.get(i);
6360 if (pkgList.contains(rec.sbn.getPackageName())) {
6361 rec.setHidden(true);
6362 changedNotifications.add(rec);
6363 }
6364 }
6365
6366 mListeners.notifyHiddenLocked(changedNotifications);
6367 }
6368 }
6369
6370 @VisibleForTesting
6371 protected void unhideNotificationsForPackages(String[] pkgs) {
6372 synchronized (mNotificationLock) {
6373 List<String> pkgList = Arrays.asList(pkgs);
6374 List<NotificationRecord> changedNotifications = new ArrayList<>();
6375 int numNotifications = mNotificationList.size();
6376 for (int i = 0; i < numNotifications; i++) {
6377 NotificationRecord rec = mNotificationList.get(i);
6378 if (pkgList.contains(rec.sbn.getPackageName())) {
6379 rec.setHidden(false);
6380 changedNotifications.add(rec);
6381 }
6382 }
6383
6384 mListeners.notifyUnhiddenLocked(changedNotifications);
6385 }
6386 }
6387
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006388 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006389 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006390 updateLightsLocked();
6391 }
6392 }
John Spurlocke677d712014-02-13 12:52:19 -05006393
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006394 protected boolean isCallingUidSystem() {
6395 final int uid = Binder.getCallingUid();
6396 return uid == Process.SYSTEM_UID;
6397 }
6398
6399 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04006400 final int appid = UserHandle.getAppId(uid);
6401 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
6402 }
John Spurlockb408e8e2014-04-23 21:12:45 -04006403
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006404 // TODO: Most calls should probably move to isCallerSystem.
6405 protected boolean isCallerSystemOrPhone() {
6406 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04006407 }
6408
Julia Reynoldsb852e562017-06-06 16:14:18 -04006409 private void checkCallerIsSystemOrShell() {
6410 if (Binder.getCallingUid() == Process.SHELL_UID) {
6411 return;
6412 }
6413 checkCallerIsSystem();
6414 }
6415
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006416 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006417 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006418 return;
6419 }
6420 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
6421 }
6422
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006423 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006424 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006425 return;
6426 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04006427 checkCallerIsSameApp(pkg);
6428 }
6429
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006430 private boolean isCallerAndroid(String callingPkg, int uid) {
6431 return isUidSystemOrPhone(uid) && callingPkg != null
6432 && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg);
6433 }
6434
Brad Stenning8c991ea2018-07-31 13:33:01 -07006435 /**
6436 * Check if the notification is of a category type that is restricted to system use only,
6437 * if so throw SecurityException
6438 */
6439 private void checkRestrictedCategories(final Notification notification) {
6440 try {
6441 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) {
6442 return;
6443 }
6444 } catch (RemoteException re) {
6445 if (DBG) Log.e(TAG, "Unable to confirm if it's safe to skip category "
6446 + "restrictions check thus the check will be done anyway");
6447 }
6448 if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category)
6449 || Notification.CATEGORY_CAR_WARNING.equals(notification.category)
6450 || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) {
6451 checkCallerIsSystem();
6452 }
6453 }
6454
Julia Reynoldsb6634872018-09-25 13:19:53 -04006455 @VisibleForTesting
Julia Reynoldsac98aea2018-10-25 16:54:27 -04006456 boolean isCallerInstantApp(int callingUid, int userId) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08006457 // System is always allowed to act for ephemeral apps.
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006458 if (isUidSystemOrPhone(callingUid)) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08006459 return false;
6460 }
6461
Chad Brubaker6b68f102017-01-27 13:39:00 -08006462 try {
Julia Reynoldsac98aea2018-10-25 16:54:27 -04006463 final String pkg = mPackageManager.getNameForUid(callingUid);
6464 mAppOps.checkPackage(callingUid, pkg);
Chad Brubaker6b68f102017-01-27 13:39:00 -08006465
Julia Reynoldsac98aea2018-10-25 16:54:27 -04006466 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId);
6467 if (ai == null) {
6468 throw new SecurityException("Unknown package " + pkg);
6469 }
6470 return ai.isInstantApp();
6471 } catch (RemoteException re) {
6472 throw new SecurityException("Unknown uid " + callingUid, re);
6473 }
Chad Brubaker6b68f102017-01-27 13:39:00 -08006474 }
6475
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006476 private void checkCallerIsSameApp(String pkg) {
Julia Reynoldsb6634872018-09-25 13:19:53 -04006477 checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId());
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006478 }
6479
Julia Reynoldsb6634872018-09-25 13:19:53 -04006480 private void checkCallerIsSameApp(String pkg, int uid, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04006481 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006482 ApplicationInfo ai = mPackageManager.getApplicationInfo(
Julia Reynoldsb6634872018-09-25 13:19:53 -04006483 pkg, 0, userId);
Dan Sandler09afc2e2014-07-18 14:29:20 -04006484 if (ai == null) {
6485 throw new SecurityException("Unknown package " + pkg);
6486 }
John Spurlock7340fc82014-04-24 18:50:12 -04006487 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006488 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04006489 + pkg + " which is owned by uid " + ai.uid);
6490 }
6491 } catch (RemoteException re) {
6492 throw new SecurityException("Unknown package " + pkg + "\n" + re);
6493 }
6494 }
6495
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006496 private boolean isCallerSameApp(String pkg) {
6497 try {
6498 checkCallerIsSameApp(pkg);
6499 return true;
6500 } catch (SecurityException e) {
6501 return false;
6502 }
6503 }
6504
Julia Reynoldsb6634872018-09-25 13:19:53 -04006505 private boolean isCallerSameApp(String pkg, int uid, int userId) {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006506 try {
Julia Reynoldsb6634872018-09-25 13:19:53 -04006507 checkCallerIsSameApp(pkg, uid, userId);
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006508 return true;
6509 } catch (SecurityException e) {
6510 return false;
6511 }
6512 }
6513
John Spurlock32fe4c62014-10-02 12:16:02 -04006514 private static String callStateToString(int state) {
6515 switch (state) {
6516 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
6517 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
6518 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
6519 default: return "CALL_STATE_UNKNOWN_" + state;
6520 }
6521 }
6522
6523 private void listenForCallState() {
6524 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
6525 @Override
6526 public void onCallStateChanged(int state, String incomingNumber) {
6527 if (mCallState == state) return;
6528 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
6529 mCallState = state;
6530 }
6531 }, PhoneStateListener.LISTEN_CALL_STATE);
6532 }
6533
Christoph Studer05ad4822014-05-16 14:16:03 +02006534 /**
6535 * Generates a NotificationRankingUpdate from 'sbns', considering only
6536 * notifications visible to the given listener.
6537 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006538 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04006539 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04006540 final int N = mNotificationList.size();
6541 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02006542 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05006543 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04006544 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006545 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006546 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05006547 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006548 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05006549 Bundle overridePeople = new Bundle();
6550 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006551 Bundle showBadge = new Bundle();
Julia Reynolds503ed942017-10-04 16:04:56 -04006552 Bundle userSentiment = new Bundle();
Beverly5a20a5e2018-03-06 15:02:44 -05006553 Bundle hidden = new Bundle();
Tony Mak628cb932018-06-19 18:30:41 +01006554 Bundle smartActions = new Bundle();
Tony Makc9acf672018-07-20 13:58:24 +02006555 Bundle smartReplies = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04006556 for (int i = 0; i < N; i++) {
6557 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02006558 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006559 continue;
6560 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006561 final String key = record.sbn.getKey();
6562 keys.add(key);
6563 importance.add(record.getImportance());
6564 if (record.getImportanceExplanation() != null) {
6565 explanation.putCharSequence(key, record.getImportanceExplanation());
6566 }
Chris Wren333a61c2014-05-28 16:40:57 -04006567 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006568 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006569
Christoph Studer05ad4822014-05-16 14:16:03 +02006570 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006571 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006572 if (record.getPackageVisibilityOverride()
6573 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006574 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006575 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04006576 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05006577 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05006578 overridePeople.putStringArrayList(key, record.getPeopleOverride());
6579 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05006580 showBadge.putBoolean(key, record.canShowBadge());
Julia Reynolds503ed942017-10-04 16:04:56 -04006581 userSentiment.putInt(key, record.getUserSentiment());
Beverly5a20a5e2018-03-06 15:02:44 -05006582 hidden.putBoolean(key, record.isHidden());
Tony Mak628cb932018-06-19 18:30:41 +01006583 smartActions.putParcelableArrayList(key, record.getSmartActions());
Tony Makc9acf672018-07-20 13:58:24 +02006584 smartReplies.putCharSequenceArrayList(key, record.getSmartReplies());
Christoph Studer05ad4822014-05-16 14:16:03 +02006585 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006586 final int M = keys.size();
6587 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02006588 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05006589 int[] importanceAr = new int[M];
6590 for (int i = 0; i < M; i++) {
6591 importanceAr[i] = importance.get(i);
6592 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006593 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05006594 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Tony Mak628cb932018-06-19 18:30:41 +01006595 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden,
Tony Makc9acf672018-07-20 13:58:24 +02006596 smartActions, smartReplies);
Christoph Studer05ad4822014-05-16 14:16:03 +02006597 }
6598
Julia Reynoldsda781472017-04-12 09:41:16 -04006599 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006600 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04006601 mCompanionManager = getCompanionManager();
6602 }
6603 // Companion mgr doesn't exist on all device types
6604 if (mCompanionManager == null) {
6605 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006606 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006607 long identity = Binder.clearCallingIdentity();
6608 try {
6609 List<String> associations = mCompanionManager.getAssociations(
6610 info.component.getPackageName(), info.userid);
6611 if (!ArrayUtils.isEmpty(associations)) {
6612 return true;
6613 }
6614 } catch (SecurityException se) {
6615 // Not a privileged listener
6616 } catch (RemoteException re) {
6617 Slog.e(TAG, "Cannot reach companion device service", re);
6618 } catch (Exception e) {
6619 Slog.e(TAG, "Cannot verify listener " + info, e);
6620 } finally {
6621 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006622 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006623 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006624 }
6625
Julia Reynolds727a7282017-04-13 10:54:01 -04006626 protected ICompanionDeviceManager getCompanionManager() {
6627 return ICompanionDeviceManager.Stub.asInterface(
6628 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
6629 }
6630
Christoph Studercef37cf2014-07-25 14:18:17 +02006631 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
6632 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
6633 return false;
6634 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07006635 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02006636 return true;
6637 }
6638
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00006639 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Beverly2be7a052018-03-27 11:37:58 -04006640 final long identity = Binder.clearCallingIdentity();
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006641 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006642 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006643 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006644 } catch (RemoteException re) {
6645 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00006646 } catch (IllegalArgumentException ex) {
6647 // Package not found.
6648 return false;
Beverly2be7a052018-03-27 11:37:58 -04006649 } finally {
6650 Binder.restoreCallingIdentity(identity);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006651 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006652 }
6653
Kristian Monsen30f59b22018-04-09 10:27:16 +02006654 @VisibleForTesting
6655 boolean canUseManagedServices(String pkg) {
6656 boolean canUseManagedServices = !mActivityManager.isLowRamDevice()
Julia Reynoldse1816412017-10-24 10:39:11 -04006657 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
Kristian Monsen30f59b22018-04-09 10:27:16 +02006658
6659 for (String whitelisted : getContext().getResources().getStringArray(
6660 R.array.config_allowedManagedServicesOnLowRamDevices)) {
6661 if (whitelisted.equals(pkg)) {
6662 canUseManagedServices = true;
6663 }
6664 }
6665
6666 return canUseManagedServices;
Julia Reynoldse1816412017-10-24 10:39:11 -04006667 }
6668
Chris Wren47633422016-01-22 09:56:59 -05006669 private class TrimCache {
6670 StatusBarNotification heavy;
6671 StatusBarNotification sbnClone;
6672 StatusBarNotification sbnCloneLight;
6673
6674 TrimCache(StatusBarNotification sbn) {
6675 heavy = sbn;
6676 }
6677
6678 StatusBarNotification ForListener(ManagedServiceInfo info) {
6679 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
6680 if (sbnCloneLight == null) {
6681 sbnCloneLight = heavy.cloneLight();
6682 }
6683 return sbnCloneLight;
6684 } else {
6685 if (sbnClone == null) {
6686 sbnClone = heavy.clone();
6687 }
6688 return sbnClone;
6689 }
6690 }
6691 }
6692
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006693 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006694 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05006695
Julia Reynolds7380d872018-01-12 10:28:26 -05006696 public NotificationAssistants(Context context, Object lock, UserProfiles up,
6697 IPackageManager pm) {
6698 super(context, lock, up, pm);
Chris Wren51017d02015-12-15 15:34:46 -05006699 }
6700
6701 @Override
6702 protected Config getConfig() {
6703 Config c = new Config();
Julia Reynolds503ed942017-10-04 16:04:56 -04006704 c.caption = "notification assistant";
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006705 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006706 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006707 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
6708 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05006709 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006710 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05006711 return c;
6712 }
6713
6714 @Override
6715 protected IInterface asInterface(IBinder binder) {
6716 return INotificationListener.Stub.asInterface(binder);
6717 }
6718
6719 @Override
6720 protected boolean checkType(IInterface service) {
6721 return service instanceof INotificationListener;
6722 }
6723
6724 @Override
6725 protected void onServiceAdded(ManagedServiceInfo info) {
6726 mListeners.registerGuestService(info);
6727 }
6728
6729 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006730 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05006731 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
6732 mListeners.unregisterService(removed.service, removed.userid);
6733 }
Chris Wren47633422016-01-22 09:56:59 -05006734
Julia Reynoldsef934fd2018-02-01 14:39:17 -05006735 @Override
6736 public void onUserUnlocked(int user) {
6737 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04006738 // force rebind the assistant, as it might be keeping its own state in user locked
6739 // storage
6740 rebindServices(true, user);
Julia Reynoldsef934fd2018-02-01 14:39:17 -05006741 }
6742
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04006743 protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
6744 // There should be only one, but it's a list, so while we enforce
6745 // singularity elsewhere, we keep it general here, to avoid surprises.
6746 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
6747 ArrayList<String> keys = new ArrayList<>(records.size());
6748 for (NotificationRecord r : records) {
6749 boolean sbnVisible = isVisibleToListener(r.sbn, info)
6750 && info.isSameUser(r.getUserId());
6751 if (sbnVisible) {
6752 keys.add(r.getKey());
6753 }
6754 }
6755
6756 if (!keys.isEmpty()) {
6757 mHandler.post(() -> notifySeen(info, keys));
6758 }
6759 }
6760 }
6761
6762 private void notifySeen(final ManagedServiceInfo info,
6763 final ArrayList<String> keys) {
6764 final INotificationListener assistant = (INotificationListener) info.service;
6765 try {
6766 assistant.onNotificationsSeen(keys);
6767 } catch (RemoteException ex) {
6768 Log.e(TAG, "unable to notify assistant (seen): " + assistant, ex);
6769 }
6770 }
6771
Chris Wren47633422016-01-22 09:56:59 -05006772 public void onNotificationEnqueued(final NotificationRecord r) {
6773 final StatusBarNotification sbn = r.sbn;
6774 TrimCache trimCache = new TrimCache(sbn);
6775
Chris Wren47633422016-01-22 09:56:59 -05006776 // There should be only one, but it's a list, so while we enforce
6777 // singularity elsewhere, we keep it general here, to avoid surprises.
Julia Reynolds00314d92017-04-14 10:01:24 -04006778 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04006779 boolean sbnVisible = isVisibleToListener(sbn, info)
6780 && info.isSameUser(r.getUserId());
Chris Wren47633422016-01-22 09:56:59 -05006781 if (!sbnVisible) {
6782 continue;
6783 }
6784
Chris Wren47633422016-01-22 09:56:59 -05006785 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006786 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05006787 @Override
6788 public void run() {
Julia Reynolds901bf282018-08-14 10:09:36 -04006789 notifyEnqueued(info, sbnToPost, r.getChannel());
Chris Wren47633422016-01-22 09:56:59 -05006790 }
6791 });
6792 }
6793 }
6794
6795 private void notifyEnqueued(final ManagedServiceInfo info,
Julia Reynolds901bf282018-08-14 10:09:36 -04006796 final StatusBarNotification sbn, final NotificationChannel channel) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006797 final INotificationListener assistant = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05006798 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6799 try {
Julia Reynolds901bf282018-08-14 10:09:36 -04006800 assistant.onNotificationEnqueuedWithChannel(sbnHolder, channel);
Chris Wren47633422016-01-22 09:56:59 -05006801 } catch (RemoteException ex) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006802 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Chris Wren47633422016-01-22 09:56:59 -05006803 }
6804 }
6805
Julia Reynolds79672302017-01-12 08:30:16 -05006806 /**
6807 * asynchronously notify the assistant that a notification has been snoozed until a
6808 * context
6809 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006810 @GuardedBy("mNotificationLock")
Julia Reynolds79672302017-01-12 08:30:16 -05006811 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
6812 final String snoozeCriterionId) {
6813 TrimCache trimCache = new TrimCache(sbn);
Julia Reynolds00314d92017-04-14 10:01:24 -04006814 for (final ManagedServiceInfo info : getServices()) {
Julia Reynolds503ed942017-10-04 16:04:56 -04006815 boolean sbnVisible = isVisibleToListener(sbn, info);
6816 if (!sbnVisible) {
6817 continue;
6818 }
Julia Reynolds79672302017-01-12 08:30:16 -05006819 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
6820 mHandler.post(new Runnable() {
6821 @Override
6822 public void run() {
6823 final INotificationListener assistant =
6824 (INotificationListener) info.service;
6825 StatusBarNotificationHolder sbnHolder
6826 = new StatusBarNotificationHolder(sbnToPost);
6827 try {
6828 assistant.onNotificationSnoozedUntilContext(
6829 sbnHolder, snoozeCriterionId);
6830 } catch (RemoteException ex) {
6831 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
6832 }
6833 }
6834 });
6835 }
6836 }
6837
Chris Wren47633422016-01-22 09:56:59 -05006838 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04006839 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05006840 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006841
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04006842 protected void ensureAssistant() {
6843 final List<UserInfo> activeUsers = mUm.getUsers(true);
6844 for (UserInfo userInfo : activeUsers) {
6845 int userId = userInfo.getUserHandle().getIdentifier();
6846 if (getAllowedPackages(userId).isEmpty()) {
6847 Slog.d(TAG, "Approving default notification assistant for user " + userId);
6848 readDefaultAssistant(userId);
6849 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006850 }
6851 }
Chris Wren51017d02015-12-15 15:34:46 -05006852 }
6853
John Spurlock7340fc82014-04-24 18:50:12 -04006854 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006855 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04006856
Christoph Studerb82bc782014-08-20 14:29:43 +02006857 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
6858
Julia Reynoldsb852e562017-06-06 16:14:18 -04006859 public NotificationListeners(IPackageManager pm) {
6860 super(getContext(), mNotificationLock, mUserProfiles, pm);
6861
John Spurlock7340fc82014-04-24 18:50:12 -04006862 }
6863
6864 @Override
Amith Yamasanie5bfeee2018-09-05 18:52:35 -07006865 protected int getBindFlags() {
6866 // Most of the same flags as the base, but also add BIND_ADJUST_BELOW_PERCEPTIBLE
6867 // because too many 3P apps could be kept in memory as notification listeners and
6868 // cause extreme memory pressure.
6869 // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation.
6870 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
6871 | BIND_ADJUST_BELOW_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
6872 }
6873
6874 @Override
John Spurlock7340fc82014-04-24 18:50:12 -04006875 protected Config getConfig() {
6876 Config c = new Config();
6877 c.caption = "notification listener";
6878 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006879 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04006880 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
6881 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
6882 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
6883 c.clientLabel = R.string.notification_listener_binding_label;
6884 return c;
6885 }
6886
6887 @Override
6888 protected IInterface asInterface(IBinder binder) {
6889 return INotificationListener.Stub.asInterface(binder);
6890 }
6891
6892 @Override
Chris Wren51017d02015-12-15 15:34:46 -05006893 protected boolean checkType(IInterface service) {
6894 return service instanceof INotificationListener;
6895 }
6896
6897 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04006898 public void onServiceAdded(ManagedServiceInfo info) {
6899 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04006900 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006901 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04006902 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006903 }
John Spurlock7340fc82014-04-24 18:50:12 -04006904 try {
Chris Wren333a61c2014-05-28 16:40:57 -04006905 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04006906 } catch (RemoteException e) {
6907 // we tried
6908 }
6909 }
6910
John Spurlock1fa865f2014-07-21 14:56:39 -04006911 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006912 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04006913 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07006914 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006915 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01006916 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04006917 }
Christoph Studerb82bc782014-08-20 14:29:43 +02006918 mLightTrimListeners.remove(removed);
6919 }
6920
Julia Reynolds88860ce2017-06-01 16:55:49 -04006921 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02006922 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
6923 if (trim == TRIM_LIGHT) {
6924 mLightTrimListeners.add(info);
6925 } else {
6926 mLightTrimListeners.remove(info);
6927 }
6928 }
6929
6930 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
6931 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04006932 }
6933
John Spurlock7340fc82014-04-24 18:50:12 -04006934 /**
6935 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02006936 *
6937 * <p>
6938 * Also takes care of removing a notification that has been visible to a listener before,
6939 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04006940 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006941 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006942 public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
6943 notifyPostedLocked(r, old, true);
Beverly5a20a5e2018-03-06 15:02:44 -05006944 }
6945
6946 /**
6947 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
6948 * targetting <= O_MR1
6949 */
6950 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006951 private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
Beverly5a20a5e2018-03-06 15:02:44 -05006952 boolean notifyAllListeners) {
Christoph Studerb82bc782014-08-20 14:29:43 +02006953 // Lazily initialized snapshots of the notification.
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006954 StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006955 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Chris Wren47633422016-01-22 09:56:59 -05006956 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02006957
Julia Reynolds00314d92017-04-14 10:01:24 -04006958 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02006959 boolean sbnVisible = isVisibleToListener(sbn, info);
6960 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
6961 // This notification hasn't been and still isn't visible -> ignore.
6962 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006963 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04006964 }
Beverly5a20a5e2018-03-06 15:02:44 -05006965 // If the notification is hidden, don't notifyPosted listeners targeting < P.
6966 // Instead, those listeners will receive notifyPosted when the notification is
6967 // unhidden.
6968 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
6969 continue;
6970 }
6971
6972 // If we shouldn't notify all listeners, this means the hidden state of
6973 // a notification was changed. Don't notifyPosted listeners targeting >= P.
6974 // Instead, those listeners will receive notifyRankingUpdate.
6975 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6976 continue;
6977 }
6978
Chris Wren333a61c2014-05-28 16:40:57 -04006979 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02006980
6981 // This notification became invisible -> remove the old one.
6982 if (oldSbnVisible && !sbnVisible) {
6983 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
6984 mHandler.post(new Runnable() {
6985 @Override
6986 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04006987 notifyRemoved(
6988 info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02006989 }
6990 });
Christoph Studer05ad4822014-05-16 14:16:03 +02006991 continue;
6992 }
Christoph Studercef37cf2014-07-25 14:18:17 +02006993
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006994 // Grant access before listener is notified
6995 final int targetUserId = (info.userid == UserHandle.USER_ALL)
6996 ? UserHandle.USER_SYSTEM : info.userid;
6997 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006998
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006999 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02007000 mHandler.post(new Runnable() {
7001 @Override
7002 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02007003 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02007004 }
7005 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00007006 }
7007 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00007008
John Spurlock7340fc82014-04-24 18:50:12 -04007009 /**
7010 * asynchronously notify all listeners about a removed notification
7011 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007012 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05007013 public void notifyRemovedLocked(NotificationRecord r, int reason,
Julia Reynolds503ed942017-10-04 16:04:56 -04007014 NotificationStats notificationStats) {
Beverly5a20a5e2018-03-06 15:02:44 -05007015 final StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007016
John Spurlock7340fc82014-04-24 18:50:12 -04007017 // make a copy in case changes are made to the underlying Notification object
7018 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
7019 // notification
7020 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04007021 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02007022 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02007023 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04007024 }
Beverly5a20a5e2018-03-06 15:02:44 -05007025
7026 // don't notifyRemoved for listeners targeting < P
7027 // if not for reason package suspended
7028 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
7029 && info.targetSdkVersion < Build.VERSION_CODES.P) {
7030 continue;
7031 }
7032
7033 // don't notifyRemoved for listeners targeting >= P
7034 // if the reason is package suspended
7035 if (reason == REASON_PACKAGE_SUSPENDED
7036 && info.targetSdkVersion >= Build.VERSION_CODES.P) {
7037 continue;
7038 }
7039
Julia Reynolds503ed942017-10-04 16:04:56 -04007040 // Only assistants can get stats
7041 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
7042 ? notificationStats : null;
Chris Wren333a61c2014-05-28 16:40:57 -04007043 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02007044 mHandler.post(new Runnable() {
7045 @Override
7046 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04007047 notifyRemoved(info, sbnLight, update, stats, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02007048 }
7049 });
Chris Wrenf9536642014-04-17 10:01:54 -04007050 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007051
7052 // Revoke access after all listeners have been updated
7053 mHandler.post(() -> {
7054 updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM);
7055 });
Chris Wrenf9536642014-04-17 10:01:54 -04007056 }
7057
7058 /**
Beverly5a20a5e2018-03-06 15:02:44 -05007059 * Asynchronously notify all listeners about a reordering of notifications
7060 * unless changedHiddenNotifications is populated.
7061 * If changedHiddenNotifications is populated, there was a change in the hidden state
7062 * of the notifications. In this case, we only send updates to listeners that
7063 * target >= P.
Chris Wrenf9536642014-04-17 10:01:54 -04007064 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007065 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05007066 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
7067 boolean isHiddenRankingUpdate = changedHiddenNotifications != null
7068 && changedHiddenNotifications.size() > 0;
7069
Julia Reynolds00314d92017-04-14 10:01:24 -04007070 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02007071 if (!serviceInfo.isEnabledForCurrentProfiles()) {
7072 continue;
7073 }
Beverly5a20a5e2018-03-06 15:02:44 -05007074
7075 boolean notifyThisListener = false;
7076 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
7077 Build.VERSION_CODES.P) {
7078 for (NotificationRecord rec : changedHiddenNotifications) {
7079 if (isVisibleToListener(rec.sbn, serviceInfo)) {
7080 notifyThisListener = true;
7081 break;
7082 }
John Spurlock7340fc82014-04-24 18:50:12 -04007083 }
Beverly5a20a5e2018-03-06 15:02:44 -05007084 }
7085
7086 if (notifyThisListener || !isHiddenRankingUpdate) {
7087 final NotificationRankingUpdate update = makeRankingUpdateLocked(
7088 serviceInfo);
7089
7090 mHandler.post(new Runnable() {
7091 @Override
7092 public void run() {
7093 notifyRankingUpdate(serviceInfo, update);
7094 }
7095 });
7096 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007097 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007098 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007099
Julia Reynolds88860ce2017-06-01 16:55:49 -04007100 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04007101 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04007102 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04007103 if (!serviceInfo.isEnabledForCurrentProfiles()) {
7104 continue;
7105 }
7106 mHandler.post(new Runnable() {
7107 @Override
7108 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04007109 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04007110 }
7111 });
7112 }
7113 }
7114
Beverly5a20a5e2018-03-06 15:02:44 -05007115 /**
7116 * asynchronously notify relevant listeners their notification is hidden
7117 * NotificationListenerServices that target P+:
7118 * NotificationListenerService#notifyRankingUpdateLocked()
7119 * NotificationListenerServices that target <= P:
7120 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
7121 */
7122 @GuardedBy("mNotificationLock")
7123 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
7124 if (changedNotifications == null || changedNotifications.size() == 0) {
7125 return;
7126 }
7127
7128 notifyRankingUpdateLocked(changedNotifications);
7129
7130 // for listeners that target < P, notifyRemoveLocked
7131 int numChangedNotifications = changedNotifications.size();
7132 for (int i = 0; i < numChangedNotifications; i++) {
7133 NotificationRecord rec = changedNotifications.get(i);
7134 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
7135 }
7136 }
7137
7138 /**
7139 * asynchronously notify relevant listeners their notification is unhidden
7140 * NotificationListenerServices that target P+:
7141 * NotificationListenerService#notifyRankingUpdateLocked()
7142 * NotificationListenerServices that target <= P:
7143 * NotificationListeners#notifyPostedLocked()
7144 */
7145 @GuardedBy("mNotificationLock")
7146 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
7147 if (changedNotifications == null || changedNotifications.size() == 0) {
7148 return;
7149 }
7150
7151 notifyRankingUpdateLocked(changedNotifications);
7152
7153 // for listeners that target < P, notifyPostedLocked
7154 int numChangedNotifications = changedNotifications.size();
7155 for (int i = 0; i < numChangedNotifications; i++) {
7156 NotificationRecord rec = changedNotifications.get(i);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007157 mListeners.notifyPostedLocked(rec, rec, false);
Beverly5a20a5e2018-03-06 15:02:44 -05007158 }
7159 }
7160
Christoph Studer85a384b2014-08-27 20:16:15 +02007161 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04007162 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02007163 if (!serviceInfo.isEnabledForCurrentProfiles()) {
7164 continue;
7165 }
7166 mHandler.post(new Runnable() {
7167 @Override
7168 public void run() {
7169 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
7170 }
7171 });
7172 }
7173 }
7174
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007175 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007176 final NotificationChannel channel, final int modificationType) {
7177 if (channel == null) {
7178 return;
7179 }
7180 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04007181 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007182 continue;
7183 }
Julia Reynolds018aa622017-04-20 11:31:30 -04007184
Eugene Suslaa25d17f2017-08-24 11:28:08 -07007185 BackgroundThread.getHandler().post(() -> {
7186 if (hasCompanionDevice(serviceInfo)) {
7187 notifyNotificationChannelChanged(
7188 serviceInfo, pkg, user, channel, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04007189 }
7190 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007191 }
7192 }
7193
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007194 protected void notifyNotificationChannelGroupChanged(
7195 final String pkg, final UserHandle user, final NotificationChannelGroup group,
7196 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007197 if (group == null) {
7198 return;
7199 }
7200 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04007201 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007202 continue;
7203 }
Julia Reynolds018aa622017-04-20 11:31:30 -04007204
Eugene Suslaa25d17f2017-08-24 11:28:08 -07007205 BackgroundThread.getHandler().post(() -> {
7206 if (hasCompanionDevice(serviceInfo)) {
7207 notifyNotificationChannelGroupChanged(
7208 serviceInfo, pkg, user, group, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04007209 }
7210 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007211 }
7212 }
7213
Christoph Studercef37cf2014-07-25 14:18:17 +02007214 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02007215 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04007216 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007217 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04007218 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07007219 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04007220 } catch (RemoteException ex) {
7221 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
7222 }
7223 }
7224
Christoph Studercef37cf2014-07-25 14:18:17 +02007225 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds503ed942017-10-04 16:04:56 -04007226 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04007227 if (!info.enabledAndUserMatches(sbn.getUserId())) {
7228 return;
7229 }
Christoph Studer05ad4822014-05-16 14:16:03 +02007230 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007231 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04007232 try {
Julia Reynolds503ed942017-10-04 16:04:56 -04007233 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04007234 } catch (RemoteException ex) {
7235 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04007236 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007237 }
Chris Wrenf9536642014-04-17 10:01:54 -04007238
Christoph Studer05ad4822014-05-16 14:16:03 +02007239 private void notifyRankingUpdate(ManagedServiceInfo info,
7240 NotificationRankingUpdate rankingUpdate) {
7241 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04007242 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02007243 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04007244 } catch (RemoteException ex) {
7245 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
7246 }
7247 }
John Spurlock1fa865f2014-07-21 14:56:39 -04007248
John Spurlockd8afe3c2014-08-01 14:04:07 -04007249 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04007250 final INotificationListener listener = (INotificationListener) info.service;
7251 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04007252 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04007253 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04007254 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04007255 }
7256 }
Justin Koh38156c52014-06-04 13:57:49 -07007257
Christoph Studer85a384b2014-08-27 20:16:15 +02007258 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
7259 int interruptionFilter) {
7260 final INotificationListener listener = (INotificationListener) info.service;
7261 try {
7262 listener.onInterruptionFilterChanged(interruptionFilter);
7263 } catch (RemoteException ex) {
7264 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
7265 }
7266 }
7267
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007268 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007269 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007270 final int modificationType) {
7271 final INotificationListener listener = (INotificationListener) info.service;
7272 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007273 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007274 } catch (RemoteException ex) {
7275 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
7276 }
7277 }
7278
7279 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007280 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007281 final int modificationType) {
7282 final INotificationListener listener = (INotificationListener) info.service;
7283 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007284 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007285 } catch (RemoteException ex) {
7286 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
7287 }
7288 }
7289
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007290 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07007291 if (packageName == null) {
7292 return false;
7293 }
7294 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007295 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04007296 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07007297 if (packageName.equals(serviceInfo.component.getPackageName())) {
7298 return true;
7299 }
7300 }
7301 }
7302 return false;
7303 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007304 }
John Spurlock25e2d242014-06-27 13:58:23 -04007305
7306 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04007307 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04007308 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04007309 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04007310 public long since;
7311 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04007312 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05007313 public boolean proto = false;
Vishnu Naire3e4d252018-03-01 11:26:57 -08007314 public boolean criticalPriority = false;
7315 public boolean normalPriority = false;
John Spurlock25e2d242014-06-27 13:58:23 -04007316
Kweku Adams887f09c2017-11-13 17:12:20 -08007317 @NonNull
John Spurlock25e2d242014-06-27 13:58:23 -04007318 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04007319 final DumpFilter filter = new DumpFilter();
7320 for (int ai = 0; ai < args.length; ai++) {
7321 final String a = args[ai];
Kweku Adams62b42242017-09-25 12:54:02 -07007322 if ("--proto".equals(a)) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05007323 filter.proto = true;
Kweku Adams62b42242017-09-25 12:54:02 -07007324 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
Dan Sandlera1770312015-07-10 13:59:29 -04007325 filter.redact = false;
7326 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
7327 if (ai < args.length-1) {
7328 ai++;
7329 filter.pkgFilter = args[ai].trim().toLowerCase();
7330 if (filter.pkgFilter.isEmpty()) {
7331 filter.pkgFilter = null;
7332 } else {
7333 filter.filtered = true;
7334 }
7335 }
7336 } else if ("--zen".equals(a) || "zen".equals(a)) {
7337 filter.filtered = true;
7338 filter.zen = true;
7339 } else if ("--stats".equals(a)) {
7340 filter.stats = true;
7341 if (ai < args.length-1) {
7342 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01007343 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04007344 } else {
7345 filter.since = 0;
7346 }
Vishnu Naire3e4d252018-03-01 11:26:57 -08007347 } else if (PRIORITY_ARG.equals(a)) {
7348 // Bugreport will call the service twice with priority arguments, first to dump
7349 // critical sections and then non critical ones. Set approriate filters
7350 // to generate the desired data.
7351 if (ai < args.length - 1) {
7352 ai++;
7353 switch (args[ai]) {
7354 case PRIORITY_ARG_CRITICAL:
7355 filter.criticalPriority = true;
7356 break;
7357 case PRIORITY_ARG_NORMAL:
7358 filter.normalPriority = true;
7359 break;
7360 }
7361 }
Dan Sandlera1770312015-07-10 13:59:29 -04007362 }
John Spurlock25e2d242014-06-27 13:58:23 -04007363 }
Dan Sandlera1770312015-07-10 13:59:29 -04007364 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04007365 }
7366
7367 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04007368 if (!filtered) return true;
7369 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04007370 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04007371 }
7372
7373 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04007374 if (!filtered) return true;
7375 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04007376 }
7377
7378 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04007379 if (!filtered) return true;
7380 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04007381 }
7382
7383 @Override
7384 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04007385 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04007386 }
7387 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07007388
Beverly5a20a5e2018-03-06 15:02:44 -05007389 @VisibleForTesting
7390 protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
7391 // only use for testing: mimic receive broadcast that package is (un)suspended
7392 // but does not actually (un)suspend the package
7393 final Bundle extras = new Bundle();
7394 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
7395 new String[]{pkg});
7396
7397 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
Beverly3c707b42018-09-14 09:49:07 -04007398 : Intent.ACTION_PACKAGES_UNSUSPENDED;
Beverly5a20a5e2018-03-06 15:02:44 -05007399 final Intent intent = new Intent(action);
7400 intent.putExtras(extras);
7401
7402 mPackageIntentReceiver.onReceive(getContext(), intent);
7403 }
7404
Griff Hazen84a00ea2014-09-02 17:10:47 -07007405 /**
7406 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
7407 * binder without sending large amounts of data over a oneway transaction.
7408 */
7409 private static final class StatusBarNotificationHolder
7410 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07007411 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007412
7413 public StatusBarNotificationHolder(StatusBarNotification value) {
7414 mValue = value;
7415 }
7416
Griff Hazene9aac5f2014-09-05 20:04:09 -07007417 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07007418 @Override
7419 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07007420 StatusBarNotification value = mValue;
7421 mValue = null;
7422 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007423 }
7424 }
John Spurlock7c74f782015-06-04 13:01:42 -04007425
Julia Reynoldsb852e562017-06-06 16:14:18 -04007426 private class ShellCmd extends ShellCommand {
7427 public static final String USAGE = "help\n"
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007428 + "allow_listener COMPONENT [user_id]\n"
7429 + "disallow_listener COMPONENT [user_id]\n"
Julia Reynolds7380d872018-01-12 10:28:26 -05007430 + "allow_assistant COMPONENT\n"
Julia Reynoldseb3dca72017-07-11 10:39:58 -04007431 + "remove_assistant COMPONENT\n"
Julia Reynoldsb852e562017-06-06 16:14:18 -04007432 + "allow_dnd PACKAGE\n"
Beverly5a20a5e2018-03-06 15:02:44 -05007433 + "disallow_dnd PACKAGE\n"
7434 + "suspend_package PACKAGE\n"
7435 + "unsuspend_package PACKAGE";
John Spurlock7c74f782015-06-04 13:01:42 -04007436
Julia Reynoldsb852e562017-06-06 16:14:18 -04007437 @Override
7438 public int onCommand(String cmd) {
Felipe Leme68d80412017-07-14 11:18:08 -07007439 if (cmd == null) {
7440 return handleDefaultCommands(cmd);
7441 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007442 final PrintWriter pw = getOutPrintWriter();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04007443 try {
Julia Reynoldsb852e562017-06-06 16:14:18 -04007444 switch (cmd) {
7445 case "allow_dnd": {
7446 getBinderService().setNotificationPolicyAccessGranted(
7447 getNextArgRequired(), true);
John Spurlock7c74f782015-06-04 13:01:42 -04007448 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04007449 break;
7450
7451 case "disallow_dnd": {
7452 getBinderService().setNotificationPolicyAccessGranted(
7453 getNextArgRequired(), false);
7454 }
7455 break;
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007456 case "allow_listener": {
7457 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7458 if (cn == null) {
7459 pw.println("Invalid listener - must be a ComponentName");
7460 return -1;
7461 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007462 String userId = getNextArg();
7463 if (userId == null) {
7464 getBinderService().setNotificationListenerAccessGranted(cn, true);
7465 } else {
7466 getBinderService().setNotificationListenerAccessGrantedForUser(
7467 cn, Integer.parseInt(userId), true);
7468 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007469 }
7470 break;
7471 case "disallow_listener": {
7472 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7473 if (cn == null) {
7474 pw.println("Invalid listener - must be a ComponentName");
7475 return -1;
7476 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007477 String userId = getNextArg();
7478 if (userId == null) {
7479 getBinderService().setNotificationListenerAccessGranted(cn, false);
7480 } else {
7481 getBinderService().setNotificationListenerAccessGrantedForUser(
7482 cn, Integer.parseInt(userId), false);
7483 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007484 }
7485 break;
Julia Reynoldseb3dca72017-07-11 10:39:58 -04007486 case "allow_assistant": {
7487 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7488 if (cn == null) {
7489 pw.println("Invalid assistant - must be a ComponentName");
7490 return -1;
7491 }
7492 getBinderService().setNotificationAssistantAccessGranted(cn, true);
7493 }
7494 break;
7495 case "disallow_assistant": {
7496 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7497 if (cn == null) {
7498 pw.println("Invalid assistant - must be a ComponentName");
7499 return -1;
7500 }
7501 getBinderService().setNotificationAssistantAccessGranted(cn, false);
7502 }
7503 break;
Beverly5a20a5e2018-03-06 15:02:44 -05007504 case "suspend_package": {
7505 // only use for testing
7506 simulatePackageSuspendBroadcast(true, getNextArgRequired());
7507 }
7508 break;
7509 case "unsuspend_package": {
7510 // only use for testing
7511 simulatePackageSuspendBroadcast(false, getNextArgRequired());
7512 }
7513 break;
Julia Reynoldsb852e562017-06-06 16:14:18 -04007514 default:
7515 return handleDefaultCommands(cmd);
John Spurlock7c74f782015-06-04 13:01:42 -04007516 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007517 } catch (Exception e) {
7518 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
Julia Reynoldsb852e562017-06-06 16:14:18 -04007519 Slog.e(TAG, "Error running shell command", e);
John Spurlock7c74f782015-06-04 13:01:42 -04007520 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04007521 return 0;
John Spurlock7c74f782015-06-04 13:01:42 -04007522 }
7523
Julia Reynoldsb852e562017-06-06 16:14:18 -04007524 @Override
7525 public void onHelp() {
7526 getOutPrintWriter().println(USAGE);
John Spurlock7c74f782015-06-04 13:01:42 -04007527 }
7528 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007529}