blob: b404c41c211dd8521205597c079cd62db9f48769 [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
Beverlyff2df9b2018-10-10 16:54:10 -04003402 @Override
3403 public Policy getConsolidatedNotificationPolicy() {
3404 final long identity = Binder.clearCallingIdentity();
3405 try {
3406 return mZenModeHelper.getConsolidatedNotificationPolicy();
3407 } finally {
3408 Binder.restoreCallingIdentity(identity);
3409 }
3410 }
3411
Beverly6697eff2017-12-14 15:00:27 -05003412 /**
3413 * Sets the notification policy. Apps that target API levels below
Beverly98ef61b2018-02-15 10:36:28 -05003414 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
Beverlyd6964762018-02-16 14:07:03 -05003415 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3416 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3417 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
Beverly6697eff2017-12-14 15:00:27 -05003418 */
John Spurlock1fc476d2015-04-14 16:05:20 -04003419 @Override
John Spurlock80774932015-05-07 17:38:50 -04003420 public void setNotificationPolicy(String pkg, Policy policy) {
3421 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04003422 final long identity = Binder.clearCallingIdentity();
3423 try {
Beverly6697eff2017-12-14 15:00:27 -05003424 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3425 0, UserHandle.getUserId(MY_UID));
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003426 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
Beverly6697eff2017-12-14 15:00:27 -05003427
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06003428 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
Beverly98ef61b2018-02-15 10:36:28 -05003429 int priorityCategories = policy.priorityCategories;
3430 // ignore alarm and media values from new policy
3431 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
Beverlyd6964762018-02-16 14:07:03 -05003432 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3433 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003434 // use user-designated values
Beverlyd6964762018-02-16 14:07:03 -05003435 priorityCategories |= currPolicy.priorityCategories
3436 & Policy.PRIORITY_CATEGORY_ALARMS;
3437 priorityCategories |= currPolicy.priorityCategories
3438 & Policy.PRIORITY_CATEGORY_MEDIA;
3439 priorityCategories |= currPolicy.priorityCategories
3440 & Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003441
Beverly6697eff2017-12-14 15:00:27 -05003442 policy = new Policy(priorityCategories,
3443 policy.priorityCallSenders, policy.priorityMessageSenders,
3444 policy.suppressedVisualEffects);
3445 }
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003446 int newVisualEffects = calculateSuppressedVisualEffects(
3447 policy, currPolicy, applicationInfo.targetSdkVersion);
3448 policy = new Policy(policy.priorityCategories,
3449 policy.priorityCallSenders, policy.priorityMessageSenders,
3450 newVisualEffects);
Beverly5e073222018-03-08 10:36:25 -05003451 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
John Spurlock1fc476d2015-04-14 16:05:20 -04003452 mZenModeHelper.setNotificationPolicy(policy);
Beverly6697eff2017-12-14 15:00:27 -05003453 } catch (RemoteException e) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003454 } finally {
3455 Binder.restoreCallingIdentity(identity);
3456 }
3457 }
Chris Wren51017d02015-12-15 15:34:46 -05003458
3459 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003460 public List<String> getEnabledNotificationListenerPackages() {
3461 checkCallerIsSystem();
3462 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3463 }
3464
3465 @Override
3466 public List<ComponentName> getEnabledNotificationListeners(int userId) {
3467 checkCallerIsSystem();
3468 return mListeners.getAllowedComponents(userId);
3469 }
3470
3471 @Override
3472 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3473 Preconditions.checkNotNull(listener);
3474 checkCallerIsSystemOrSameApp(listener.getPackageName());
3475 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3476 getCallingUserHandle().getIdentifier());
3477 }
3478
3479 @Override
3480 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3481 int userId) {
3482 Preconditions.checkNotNull(listener);
3483 checkCallerIsSystem();
3484 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3485 userId);
3486 }
3487
3488 @Override
3489 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3490 Preconditions.checkNotNull(assistant);
3491 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003492 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04003493 getCallingUserHandle().getIdentifier());
3494 }
3495
3496 @Override
3497 public void setNotificationListenerAccessGranted(ComponentName listener,
3498 boolean granted) throws RemoteException {
3499 setNotificationListenerAccessGrantedForUser(
3500 listener, getCallingUserHandle().getIdentifier(), granted);
3501 }
3502
3503 @Override
3504 public void setNotificationAssistantAccessGranted(ComponentName assistant,
3505 boolean granted) throws RemoteException {
3506 setNotificationAssistantAccessGrantedForUser(
3507 assistant, getCallingUserHandle().getIdentifier(), granted);
3508 }
3509
3510 @Override
3511 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3512 boolean granted) throws RemoteException {
3513 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04003514 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003515 final long identity = Binder.clearCallingIdentity();
3516 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003517 if (mAllowedManagedServicePackages.test(listener.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003518 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3519 userId, false, granted);
3520 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3521 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003522
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003523 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds92febc32017-10-26 11:30:31 -04003524 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003525 .setPackage(listener.getPackageName())
3526 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003527 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003528
3529 savePolicyFile();
3530 }
3531 } finally {
3532 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003533 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003534 }
3535
3536 @Override
3537 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3538 int userId, boolean granted) throws RemoteException {
3539 Preconditions.checkNotNull(assistant);
Julia Reynolds0d217642017-08-11 11:26:04 -04003540 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003541 final long identity = Binder.clearCallingIdentity();
3542 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003543 if (mAllowedManagedServicePackages.test(assistant.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003544 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
3545 userId, false, granted);
3546 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
3547 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003548
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003549 getContext().sendBroadcastAsUser(new Intent(
3550 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3551 .setPackage(assistant.getPackageName())
3552 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003553 UserHandle.of(userId), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003554
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003555 savePolicyFile();
3556 }
3557 } finally {
3558 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003559 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003560 }
3561
3562 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003563 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003564 Adjustment adjustment) {
3565 boolean foundEnqueued = false;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003566 final long identity = Binder.clearCallingIdentity();
3567 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003568 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003569 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003570 int N = mEnqueuedNotifications.size();
3571 for (int i = 0; i < N; i++) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003572 final NotificationRecord r = mEnqueuedNotifications.get(i);
3573 if (Objects.equals(adjustment.getKey(), r.getKey())
Julia Reynolds70aaea72018-07-13 13:38:34 -04003574 && Objects.equals(adjustment.getUser(), r.getUserId())
3575 && mAssistants.isSameUser(token, r.getUserId())) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003576 applyAdjustment(r, adjustment);
3577 r.applyAdjustments();
3578 foundEnqueued = true;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003579 break;
3580 }
3581 }
Julia Reynolds666ccf02018-06-18 10:19:20 -04003582 if (!foundEnqueued) {
3583 // adjustment arrived too late to apply to enqueued; apply to posted
3584 applyAdjustmentFromAssistant(token, adjustment);
3585 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003586 }
3587 } finally {
3588 Binder.restoreCallingIdentity(identity);
3589 }
3590 }
3591
3592 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003593 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003594 Adjustment adjustment) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003595 List<Adjustment> adjustments = new ArrayList<>();
3596 adjustments.add(adjustment);
3597 applyAdjustmentsFromAssistant(token, adjustments);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003598 }
3599
3600 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003601 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003602 List<Adjustment> adjustments) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003603
Julia Reynoldsefcdff42018-08-09 09:42:56 -04003604 boolean needsSort = false;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003605 final long identity = Binder.clearCallingIdentity();
3606 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003607 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003608 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003609 for (Adjustment adjustment : adjustments) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003610 NotificationRecord r = mNotificationsByKey.get(adjustment.getKey());
3611 if (r != null && mAssistants.isSameUser(token, r.getUserId())) {
3612 applyAdjustment(r, adjustment);
Julia Reynoldsefcdff42018-08-09 09:42:56 -04003613 r.applyAdjustments();
3614 if (r.getImportance() == IMPORTANCE_NONE) {
3615 cancelNotificationsFromListener(token, new String[]{r.getKey()});
3616 } else {
3617 needsSort = true;
3618 }
Julia Reynolds70aaea72018-07-13 13:38:34 -04003619 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003620 }
3621 }
Julia Reynoldsefcdff42018-08-09 09:42:56 -04003622 if (needsSort) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003623 mRankingHandler.requestSort();
3624 }
Chris Wren51017d02015-12-15 15:34:46 -05003625 } finally {
3626 Binder.restoreCallingIdentity(identity);
3627 }
3628 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003629
3630 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04003631 public void updateNotificationChannelGroupFromPrivilegedListener(
3632 INotificationListener token, String pkg, UserHandle user,
3633 NotificationChannelGroup group) throws RemoteException {
3634 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003635 verifyPrivilegedListener(token, user, false);
Julia Reynolds005c8b92017-08-24 10:35:53 -04003636 createNotificationChannelGroup(
3637 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
3638 savePolicyFile();
3639 }
3640
3641 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003642 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003643 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003644 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003645 Preconditions.checkNotNull(pkg);
3646 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003647
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003648 verifyPrivilegedListener(token, user, false);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003649 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003650 }
3651
3652 @Override
3653 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003654 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3655 Preconditions.checkNotNull(pkg);
3656 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003657 verifyPrivilegedListener(token, user, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003658
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003659 return mPreferencesHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003660 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003661 }
3662
3663 @Override
3664 public ParceledListSlice<NotificationChannelGroup>
3665 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003666 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3667 Preconditions.checkNotNull(pkg);
3668 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003669 verifyPrivilegedListener(token, user, true);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003670
3671 List<NotificationChannelGroup> groups = new ArrayList<>();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003672 groups.addAll(mPreferencesHelper.getNotificationChannelGroups(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003673 pkg, getUidForPackageAndUser(pkg, user)));
3674 return new ParceledListSlice<>(groups);
3675 }
3676
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003677 private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
3678 boolean assistantAllowed) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003679 ManagedServiceInfo info;
3680 synchronized (mNotificationLock) {
3681 info = mListeners.checkServiceTokenLocked(token);
3682 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003683 if (!hasCompanionDevice(info)) {
Julia Reynolds48a6ed92018-10-22 12:52:03 -04003684 synchronized (mNotificationLock) {
3685 if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) {
3686 throw new SecurityException(info + " does not have access");
3687 }
3688 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003689 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003690 if (!info.enabledAndUserMatches(user.getIdentifier())) {
3691 throw new SecurityException(info + " does not have access");
3692 }
3693 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003694
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003695 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3696 int uid = 0;
3697 long identity = Binder.clearCallingIdentity();
3698 try {
3699 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3700 } finally {
3701 Binder.restoreCallingIdentity(identity);
3702 }
3703 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003704 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003705
3706 @Override
3707 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3708 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3709 throws RemoteException {
3710 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3711 }
John Spurlock1fc476d2015-04-14 16:05:20 -04003712 };
John Spurlocka4294292014-03-24 18:02:32 -04003713
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003714 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3715 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003716 return;
3717 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003718 if (adjustment.getSignals() != null) {
3719 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003720 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003721 }
3722 }
3723
Julia Reynolds88860ce2017-06-01 16:55:49 -04003724 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003725 void addAutogroupKeyLocked(String key) {
3726 NotificationRecord r = mNotificationsByKey.get(key);
3727 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003728 return;
3729 }
Julia Reynolds51710712017-07-19 13:48:07 -04003730 if (r.sbn.getOverrideGroupKey() == null) {
3731 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3732 EventLogTags.writeNotificationAutogrouped(key);
3733 mRankingHandler.requestSort();
3734 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003735 }
3736
Julia Reynolds88860ce2017-06-01 16:55:49 -04003737 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003738 void removeAutogroupKeyLocked(String key) {
3739 NotificationRecord r = mNotificationsByKey.get(key);
3740 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003741 return;
3742 }
Julia Reynolds51710712017-07-19 13:48:07 -04003743 if (r.sbn.getOverrideGroupKey() != null) {
3744 addAutoGroupAdjustment(r, null);
3745 EventLogTags.writeNotificationUnautogrouped(key);
3746 mRankingHandler.requestSort();
3747 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003748 }
3749
3750 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3751 Bundle signals = new Bundle();
3752 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3753 Adjustment adjustment =
3754 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3755 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003756 }
3757
3758 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04003759 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04003760 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3761 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3762 if (summaries != null && summaries.containsKey(pkg)) {
3763 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003764 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04003765 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04003766 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003767 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003768 }
3769 }
3770 }
3771
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003772 @GuardedBy("mNotificationLock")
3773 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3774 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3775 return summaries != null && summaries.containsKey(sbn.getPackageName());
3776 }
3777
Julia Reynoldse46bb372016-03-17 11:05:58 -04003778 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04003779 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3780 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003781 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003782 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3783 if (notificationRecord == null) {
3784 // The notification could have been cancelled again already. A successive
3785 // adjustment will post a summary if needed.
3786 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003787 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003788 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3789 userId = adjustedSbn.getUser().getIdentifier();
3790 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3791 if (summaries == null) {
3792 summaries = new ArrayMap<>();
3793 }
3794 mAutobundledSummaries.put(userId, summaries);
3795 if (!summaries.containsKey(pkg)) {
3796 // Add summary
3797 final ApplicationInfo appInfo =
3798 adjustedSbn.getNotification().extras.getParcelable(
3799 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3800 final Bundle extras = new Bundle();
3801 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003802 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04003803 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003804 new Notification.Builder(getContext(), channelId)
3805 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04003806 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04003807 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04003808 .setGroup(GroupHelper.AUTOGROUP_KEY)
3809 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3810 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3811 .setColor(adjustedSbn.getNotification().color)
3812 .setLocalOnly(true)
3813 .build();
3814 summaryNotification.extras.putAll(extras);
3815 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3816 if (appIntent != null) {
3817 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3818 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3819 }
3820 final StatusBarNotification summarySbn =
3821 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003822 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003823 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04003824 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3825 adjustedSbn.getInitialPid(), summaryNotification,
3826 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3827 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05003828 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003829 notificationRecord.getChannel());
Rohan Shah590e1b22018-04-10 23:48:47 -04003830 summaryRecord.setIsAppImportanceLocked(
3831 notificationRecord.getIsAppImportanceLocked());
Julia Reynolds8f488d32016-10-14 10:59:01 -04003832 summaries.put(pkg, summarySbn.getKey());
3833 }
3834 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003835 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04003836 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003837 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04003838 }
3839 }
3840
John Spurlock32fe4c62014-10-02 12:16:02 -04003841 private String disableNotificationEffects(NotificationRecord record) {
3842 if (mDisableNotificationEffects) {
3843 return "booleanState";
3844 }
3845 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3846 return "listenerHints";
3847 }
3848 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3849 return "callState";
3850 }
3851 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04003852 };
3853
Kweku Adams887f09c2017-11-13 17:12:20 -08003854 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
Chris Wrene4b38802015-07-07 15:54:19 -04003855 JSONObject dump = new JSONObject();
3856 try {
3857 dump.put("service", "Notification Manager");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003858 dump.put("bans", mPreferencesHelper.dumpBansJson(filter));
3859 dump.put("ranking", mPreferencesHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003860 dump.put("stats", mUsageStats.dumpJson(filter));
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003861 dump.put("channels", mPreferencesHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003862 } catch (JSONException e) {
3863 e.printStackTrace();
3864 }
3865 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04003866 }
3867
Kweku Adams887f09c2017-11-13 17:12:20 -08003868 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003869 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3870 synchronized (mNotificationLock) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003871 int N = mNotificationList.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003872 for (int i = 0; i < N; i++) {
3873 final NotificationRecord nr = mNotificationList.get(i);
3874 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3875 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3876 NotificationRecordProto.POSTED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003877 }
3878 N = mEnqueuedNotifications.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003879 for (int i = 0; i < N; i++) {
3880 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3881 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3882 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3883 NotificationRecordProto.ENQUEUED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003884 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003885 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3886 N = snoozed.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003887 for (int i = 0; i < N; i++) {
3888 final NotificationRecord nr = snoozed.get(i);
3889 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3890 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3891 NotificationRecordProto.SNOOZED);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003892 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003893
Kweku Adams93304b62017-09-20 17:03:00 -07003894 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3895 mZenModeHelper.dump(proto);
3896 for (ComponentName suppressor : mEffectsSuppressors) {
Kweku Adams99546332018-01-24 17:03:50 -08003897 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
Kweku Adams93304b62017-09-20 17:03:00 -07003898 }
3899 proto.end(zenLog);
3900
3901 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
3902 mListeners.dump(proto, filter);
3903 proto.end(listenersToken);
3904
3905 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
3906
3907 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
3908 long effectsToken = proto.start(
3909 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
3910
3911 proto.write(
3912 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
Julia Reynolds4703bac2018-09-12 10:39:30 -04003913 final ArraySet<ComponentName> listeners =
Kweku Adams93304b62017-09-20 17:03:00 -07003914 mListenersDisablingEffects.valueAt(i);
3915 for (int j = 0; j < listeners.size(); j++) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04003916 final ComponentName componentName = listeners.valueAt(i);
3917 componentName.writeToProto(proto,
3918 ListenersDisablingEffectsProto.LISTENER_COMPONENTS);
Kweku Adams93304b62017-09-20 17:03:00 -07003919 }
3920
3921 proto.end(effectsToken);
3922 }
3923
3924 long assistantsToken = proto.start(
3925 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
3926 mAssistants.dump(proto, filter);
3927 proto.end(assistantsToken);
3928
3929 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
3930 mConditionProviders.dump(proto, filter);
3931 proto.end(conditionsToken);
Kweku Adams62b42242017-09-25 12:54:02 -07003932
3933 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
3934 mRankingHelper.dump(proto, filter);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04003935 mPreferencesHelper.dump(proto, filter);
Kweku Adams62b42242017-09-25 12:54:02 -07003936 proto.end(rankingToken);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003937 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003938
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003939 proto.flush();
3940 }
3941
Vishnu Naire3e4d252018-03-01 11:26:57 -08003942 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
3943 synchronized (mNotificationLock) {
3944 int N;
3945 N = mNotificationList.size();
3946 if (N > 0) {
3947 pw.println(" Notification List:");
3948 for (int i = 0; i < N; i++) {
3949 final NotificationRecord nr = mNotificationList.get(i);
3950 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3951 nr.dump(pw, " ", getContext(), filter.redact);
3952 }
3953 pw.println(" ");
3954 }
3955 }
3956 }
3957
Kweku Adams887f09c2017-11-13 17:12:20 -08003958 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
John Spurlock25e2d242014-06-27 13:58:23 -04003959 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04003960 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003961 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04003962 }
3963 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08003964 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003965 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003966
John Spurlock50806fc2014-07-15 10:22:02 -04003967 if (!zenOnly) {
3968 synchronized (mToastQueue) {
3969 N = mToastQueue.size();
3970 if (N > 0) {
3971 pw.println(" Toast Queue:");
3972 for (int i=0; i<N; i++) {
3973 mToastQueue.get(i).dump(pw, " ", filter);
3974 }
3975 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003976 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003977 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003978 }
3979
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003980 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04003981 if (!zenOnly) {
Vishnu Naire3e4d252018-03-01 11:26:57 -08003982 // Priority filters are only set when called via bugreport. If set
3983 // skip sections that are part of the critical section.
3984 if (!filter.normalPriority) {
3985 dumpNotificationRecords(pw, filter);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003986 }
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003987 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003988 N = mLights.size();
3989 if (N > 0) {
3990 pw.println(" Lights List:");
3991 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05003992 if (i == N - 1) {
3993 pw.print(" > ");
3994 } else {
3995 pw.print(" ");
3996 }
3997 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04003998 }
3999 pw.println(" ");
4000 }
John Spurlockcb566aa2014-08-03 22:58:28 -04004001 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
Julia Reynolds28149f62018-07-03 10:43:35 -04004002 pw.println(" mHasLight=" + mHasLight);
John Spurlockcb566aa2014-08-03 22:58:28 -04004003 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05004004 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
4005 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04004006 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04004007 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04004008 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04004009 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04004010 }
4011 pw.println(" mArchive=" + mArchive.toString());
4012 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004013 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04004014 while (iter.hasNext()) {
4015 final StatusBarNotification sbn = iter.next();
4016 if (filter != null && !filter.matches(sbn)) continue;
4017 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004018 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04004019 if (iter.hasNext()) pw.println(" ...");
4020 break;
4021 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004022 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004023
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004024 if (!zenOnly) {
4025 N = mEnqueuedNotifications.size();
4026 if (N > 0) {
4027 pw.println(" Enqueued Notification List:");
4028 for (int i = 0; i < N; i++) {
4029 final NotificationRecord nr = mEnqueuedNotifications.get(i);
4030 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4031 nr.dump(pw, " ", getContext(), filter.redact);
4032 }
4033 pw.println(" ");
4034 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004035
4036 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004037 }
4038 }
4039
John Spurlock50806fc2014-07-15 10:22:02 -04004040 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04004041 pw.println("\n Ranking Config:");
4042 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04004043
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004044 pw.println("\n Notification Preferences:");
4045 mPreferencesHelper.dump(pw, " ", filter);
4046
John Spurlock50806fc2014-07-15 10:22:02 -04004047 pw.println("\n Notification listeners:");
4048 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04004049 pw.print(" mListenerHints: "); pw.println(mListenerHints);
4050 pw.print(" mListenersDisablingEffects: (");
4051 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04004052 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07004053 final int hint = mListenersDisablingEffects.keyAt(i);
4054 if (i > 0) pw.print(';');
4055 pw.print("hint[" + hint + "]:");
4056
Julia Reynolds4703bac2018-09-12 10:39:30 -04004057 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07004058 final int listenerSize = listeners.size();
4059
4060 for (int j = 0; j < listenerSize; j++) {
4061 if (i > 0) pw.print(',');
Julia Reynolds4703bac2018-09-12 10:39:30 -04004062 final ComponentName listener = listeners.valueAt(i);
Julia Reynolds1f580572018-04-27 14:48:36 -04004063 if (listener != null) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04004064 pw.print(listener);
Julia Reynolds1f580572018-04-27 14:48:36 -04004065 }
Bryce Lee7219ada2016-04-08 10:54:23 -07004066 }
John Spurlock1fa865f2014-07-21 14:56:39 -04004067 }
4068 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05004069 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004070 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04004071 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004072
Julia Reynolds520df6e2017-02-13 09:05:10 -05004073 if (!filter.filtered || zenOnly) {
4074 pw.println("\n Zen Mode:");
4075 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
4076 mZenModeHelper.dump(pw, " ");
4077
4078 pw.println("\n Zen Log:");
4079 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004080 }
4081
John Spurlocke77bb362014-04-26 10:24:59 -04004082 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04004083 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02004084
4085 pw.println("\n Group summaries:");
4086 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
4087 NotificationRecord r = entry.getValue();
4088 pw.println(" " + entry.getKey() + " -> " + r.getKey());
4089 if (mNotificationsByKey.get(r.getKey()) != r) {
4090 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04004091 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02004092 }
4093 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004094
4095 if (!zenOnly) {
4096 pw.println("\n Usage Stats:");
4097 mUsageStats.dump(pw, " ", filter);
4098 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004099 }
4100 }
4101
Adam Lesinski182f73f2013-12-05 16:48:06 -08004102 /**
4103 * The private API only accessible to the system process.
4104 */
4105 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
4106 @Override
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04004107 public NotificationChannel getNotificationChannel(String pkg, int uid, String
4108 channelId) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004109 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false);
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04004110 }
4111
4112 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004113 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004114 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004115 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004116 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004117 }
Christoph Studer365e4c32014-09-18 20:35:36 +02004118
4119 @Override
4120 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
4121 int userId) {
4122 checkCallerIsSystem();
Julia Reynolds564273f2018-09-13 15:53:11 -04004123 mHandler.post(() -> {
4124 synchronized (mNotificationLock) {
4125 // strip flag from all enqueued notifications. listeners will be informed
4126 // in post runnable.
4127 List<NotificationRecord> enqueued = findNotificationsByListLocked(
4128 mEnqueuedNotifications, pkg, null, notificationId, userId);
4129 for (int i = 0; i < enqueued.size(); i++) {
4130 removeForegroundServiceFlagLocked(enqueued.get(i));
4131 }
4132
4133 // if posted notification exists, strip its flag and tell listeners
4134 NotificationRecord r = findNotificationByListLocked(
4135 mNotificationList, pkg, null, notificationId, userId);
4136 if (r != null) {
4137 removeForegroundServiceFlagLocked(r);
4138 mRankingHelper.sort(mNotificationList);
4139 mListeners.notifyPostedLocked(r, r);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004140 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004141 }
4142 });
4143 }
4144
Julia Reynolds88860ce2017-06-01 16:55:49 -04004145 @GuardedBy("mNotificationLock")
Julia Reynolds564273f2018-09-13 15:53:11 -04004146 private void removeForegroundServiceFlagLocked(NotificationRecord r) {
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004147 if (r == null) {
4148 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02004149 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004150 StatusBarNotification sbn = r.sbn;
4151 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
4152 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
4153 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
4154 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
4155 sbn.getNotification().flags =
Julia Reynoldse5c60452018-04-30 14:41:36 -04004156 (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
Christoph Studer365e4c32014-09-18 20:35:36 +02004157 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004158 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004159
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004160 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04004161 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004162 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04004163 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08004164 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
4165 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04004166 }
Dianne Hackborn41203752012-08-31 14:05:51 -07004167
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004168 if (pkg == null || notification == null) {
4169 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
4170 + " id=" + id + " notification=" + notification);
4171 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004172
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004173 final int userId = ActivityManager.handleIncomingUser(callingPid,
4174 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
4175 final UserHandle user = UserHandle.of(userId);
4176
4177 // Can throw a SecurityException if the calling uid doesn't have permission to post
4178 // as "pkg"
4179 final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
4180
4181 checkRestrictedCategories(notification);
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004182
Julia Reynoldse46bb372016-03-17 11:05:58 -04004183 // Fix the notification as best we can.
4184 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004185 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06004186 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
Julia Reynoldse0d711f2017-09-01 08:50:47 -04004187 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
Julia Reynoldse071abd2017-03-22 10:52:11 -04004188 Notification.addFieldsFromContext(ai, notification);
Julia Reynolds4db59552017-06-30 13:34:01 -04004189
4190 int canColorize = mPackageManagerClient.checkPermission(
4191 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
4192 if (canColorize == PERMISSION_GRANTED) {
4193 notification.flags |= Notification.FLAG_CAN_COLORIZE;
4194 } else {
4195 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
4196 }
4197
Julia Reynoldse46bb372016-03-17 11:05:58 -04004198 } catch (NameNotFoundException e) {
4199 Slog.e(TAG, "Cannot create a context for sending app", e);
4200 return;
4201 }
4202
Chris Wren888b7a82016-06-17 15:47:19 -04004203 mUsageStats.registerEnqueuedByApp(pkg);
4204
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004205 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04004206 String channelId = notification.getChannelId();
4207 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
4208 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05004209 }
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004210 final NotificationChannel channel = mPreferencesHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004211 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004212 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004213 final String noChannelStr = "No Channel found for "
4214 + "pkg=" + pkg
4215 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04004216 + ", id=" + id
4217 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004218 + ", opPkg=" + opPkg
4219 + ", callingUid=" + callingUid
4220 + ", userId=" + userId
4221 + ", incomingUserId=" + incomingUserId
4222 + ", notificationUid=" + notificationUid
4223 + ", notification=" + notification;
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004224 Log.e(TAG, noChannelStr);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004225 boolean appNotificationsOff = mPreferencesHelper.getImportance(pkg, notificationUid)
Beverly5d4564b2018-04-10 20:09:23 -04004226 == NotificationManager.IMPORTANCE_NONE;
4227
4228 if (!appNotificationsOff) {
4229 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
4230 "Failed to post notification on channel \"" + channelId + "\"\n" +
4231 "See log for more details");
4232 }
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004233 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004234 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004235
Chris Wrena61f1792016-08-04 11:24:42 -04004236 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004237 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004238 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004239 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004240 r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
Chris Wrena61f1792016-08-04 11:24:42 -04004241
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004242 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4243 final boolean fgServiceShown = channel.isFgServiceShown();
4244 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
4245 || !fgServiceShown)
4246 && (r.getImportance() == IMPORTANCE_MIN
4247 || r.getImportance() == IMPORTANCE_NONE)) {
4248 // Increase the importance of foreground service notifications unless the user had
4249 // an opinion otherwise (and the channel hasn't yet shown a fg service).
4250 if (TextUtils.isEmpty(channelId)
4251 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004252 r.setSystemImportance(IMPORTANCE_LOW);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004253 } else {
4254 channel.setImportance(IMPORTANCE_LOW);
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004255 r.setSystemImportance(IMPORTANCE_LOW);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004256 if (!fgServiceShown) {
4257 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
4258 channel.setFgServiceShown(true);
4259 }
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004260 mPreferencesHelper.updateNotificationChannel(
4261 pkg, notificationUid, channel, false);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004262 r.updateNotificationChannel(channel);
4263 }
4264 } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
4265 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4266 channel.setFgServiceShown(true);
Julia Reynolds8617e4e2017-09-18 16:52:37 -04004267 r.updateNotificationChannel(channel);
4268 }
4269 }
4270
Julia Reynolds5e702192017-08-18 09:22:40 -04004271 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
4272 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004273 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07004274 }
4275
Felipe Lemedd85da62016-06-28 11:29:54 -07004276 // Whitelist pending intents.
4277 if (notification.allPendingIntents != null) {
4278 final int intentCount = notification.allPendingIntents.size();
4279 if (intentCount > 0) {
4280 final ActivityManagerInternal am = LocalServices
4281 .getService(ActivityManagerInternal.class);
4282 final long duration = LocalServices.getService(
4283 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
4284 for (int i = 0; i < intentCount; i++) {
4285 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4286 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07004287 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4288 WHITELIST_TOKEN, duration);
Felipe Lemedd85da62016-06-28 11:29:54 -07004289 }
4290 }
4291 }
4292 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07004293
Chris Wren47633422016-01-22 09:56:59 -05004294 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004295 }
4296
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04004297 private void doChannelWarningToast(CharSequence toastText) {
Julia Reynoldsbba26b12018-10-11 09:21:11 -04004298 Binder.withCleanCallingIdentity(() -> {
4299 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
4300 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
4301 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4302 if (warningEnabled) {
4303 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
4304 Toast.LENGTH_SHORT);
4305 toast.show();
4306 }
4307 });
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004308 }
4309
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004310 @VisibleForTesting
4311 int resolveNotificationUid(String callingPkg, String targetPkg,
4312 int callingUid, int userId) {
Julia Reynoldsb6634872018-09-25 13:19:53 -04004313 if (userId == UserHandle.USER_ALL) {
4314 userId = USER_SYSTEM;
4315 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004316 // posted from app A on behalf of app A
Julia Reynoldsb6634872018-09-25 13:19:53 -04004317 if (isCallerSameApp(targetPkg, callingUid, userId)
Julia Reynoldsecc1b572018-10-01 16:19:24 -04004318 && (TextUtils.equals(callingPkg, targetPkg)
4319 || isCallerSameApp(callingPkg, callingUid, userId))) {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004320 return callingUid;
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004321 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004322
4323 int targetUid = -1;
4324 try {
4325 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
4326 } catch (NameNotFoundException e) {
4327 /* ignore */
4328 }
4329 // posted from app A on behalf of app B
4330 if (targetUid != -1 && (isCallerAndroid(callingPkg, callingUid)
4331 || mPreferencesHelper.isDelegateAllowed(
4332 targetPkg, targetUid, callingPkg, callingUid))) {
4333 return targetUid;
4334 }
4335
Julia Reynoldsecc1b572018-10-01 16:19:24 -04004336 throw new SecurityException("Caller " + callingPkg + ":" + callingUid
4337 + " cannot post for pkg " + targetPkg + " in user " + userId);
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004338 }
4339
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004340 /**
4341 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4342 *
4343 * Has side effects.
4344 */
4345 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04004346 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004347 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004348 final boolean isSystemNotification =
4349 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004350 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
4351
4352 // Limit the number of notifications that any given package except the android
4353 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
4354 if (!isSystemNotification && !isNotificationFromListener) {
4355 synchronized (mNotificationLock) {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004356 if (mNotificationsByKey.get(r.sbn.getKey()) == null
Julia Reynoldsecc1b572018-10-01 16:19:24 -04004357 && isCallerInstantApp(pkg, Binder.getCallingUid(), userId)) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004358 // Ephemeral apps have some special constraints for notifications.
4359 // They are not allowed to create new notifications however they are allowed to
4360 // update notifications created by the system (e.g. a foreground service
4361 // notification).
4362 throw new SecurityException("Instant app " + pkg
4363 + " cannot create notifications");
4364 }
4365
4366 // rate limit updates that aren't completed progress notifications
4367 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04004368 && !r.getNotification().hasCompletedProgress()
4369 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004370
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004371 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
4372 if (appEnqueueRate > mMaxPackageEnqueueRate) {
4373 mUsageStats.registerOverRateQuota(pkg);
4374 final long now = SystemClock.elapsedRealtime();
4375 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
4376 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04004377 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004378 mLastOverRateLogTime = now;
4379 }
4380 return false;
4381 }
4382 }
4383
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004384 // limit the number of outstanding notificationrecords an app can have
4385 int count = getNotificationCountLocked(pkg, userId, id, tag);
4386 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
4387 mUsageStats.registerOverCountQuota(pkg);
4388 Slog.e(TAG, "Package has already posted or enqueued " + count
4389 + " notifications. Not showing more. package=" + pkg);
4390 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004391 }
4392 }
4393 }
4394
4395 // snoozed apps
4396 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05004397 MetricsLogger.action(r.getLogMaker()
4398 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
4399 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004400 if (DBG) {
4401 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
4402 }
4403 mSnoozeHelper.update(userId, r);
4404 savePolicyFile();
4405 return false;
4406 }
4407
4408
4409 // blocked apps
4410 if (isBlocked(r, mUsageStats)) {
4411 return false;
4412 }
4413
4414 return true;
4415 }
4416
Andreas Gampea36dc622018-02-05 17:19:22 -08004417 @GuardedBy("mNotificationLock")
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004418 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
4419 String excludedTag) {
4420 int count = 0;
4421 final int N = mNotificationList.size();
4422 for (int i = 0; i < N; i++) {
4423 final NotificationRecord existing = mNotificationList.get(i);
4424 if (existing.sbn.getPackageName().equals(pkg)
4425 && existing.sbn.getUserId() == userId) {
4426 if (existing.sbn.getId() == excludedId
4427 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
4428 continue;
4429 }
4430 count++;
4431 }
4432 }
4433 final int M = mEnqueuedNotifications.size();
4434 for (int i = 0; i < M; i++) {
4435 final NotificationRecord existing = mEnqueuedNotifications.get(i);
4436 if (existing.sbn.getPackageName().equals(pkg)
4437 && existing.sbn.getUserId() == userId) {
4438 count++;
4439 }
4440 }
4441 return count;
4442 }
4443
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004444 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
Beverly3c707b42018-09-14 09:49:07 -04004445 if (isBlocked(r)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004446 Slog.e(TAG, "Suppressing notification from package by user request.");
4447 usageStats.registerBlocked(r);
Beverly3c707b42018-09-14 09:49:07 -04004448 return true;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004449 }
Beverly3c707b42018-09-14 09:49:07 -04004450 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004451 }
4452
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004453 private boolean isBlocked(NotificationRecord r) {
4454 final String pkg = r.sbn.getPackageName();
4455 final int callingUid = r.sbn.getUid();
4456 return mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
4457 || mPreferencesHelper.getImportance(pkg, callingUid)
4458 == NotificationManager.IMPORTANCE_NONE
4459 || r.getImportance() == NotificationManager.IMPORTANCE_NONE;
4460 }
4461
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004462 protected class SnoozeNotificationRunnable implements Runnable {
4463 private final String mKey;
4464 private final long mDuration;
4465 private final String mSnoozeCriterionId;
4466
4467 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
4468 mKey = key;
4469 mDuration = duration;
4470 mSnoozeCriterionId = snoozeCriterionId;
4471 }
4472
4473 @Override
4474 public void run() {
4475 synchronized (mNotificationLock) {
4476 final NotificationRecord r = findNotificationByKeyLocked(mKey);
4477 if (r != null) {
4478 snoozeLocked(r);
4479 }
4480 }
4481 }
4482
Julia Reynolds88860ce2017-06-01 16:55:49 -04004483 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004484 void snoozeLocked(NotificationRecord r) {
4485 if (r.sbn.isGroup()) {
4486 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
4487 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
4488 if (r.getNotification().isGroupSummary()) {
4489 // snooze summary and all children
4490 for (int i = 0; i < groupNotifications.size(); i++) {
4491 snoozeNotificationLocked(groupNotifications.get(i));
4492 }
4493 } else {
4494 // if there is a valid summary for this group, and we are snoozing the only
4495 // child, also snooze the summary
4496 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
4497 if (groupNotifications.size() != 2) {
4498 snoozeNotificationLocked(r);
4499 } else {
4500 // snooze summary and the one child
4501 for (int i = 0; i < groupNotifications.size(); i++) {
4502 snoozeNotificationLocked(groupNotifications.get(i));
4503 }
4504 }
4505 } else {
4506 snoozeNotificationLocked(r);
4507 }
4508 }
4509 } else {
4510 // just snooze the one notification
4511 snoozeNotificationLocked(r);
4512 }
4513 }
4514
Julia Reynolds88860ce2017-06-01 16:55:49 -04004515 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004516 void snoozeNotificationLocked(NotificationRecord r) {
4517 MetricsLogger.action(r.getLogMaker()
4518 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4519 .setType(MetricsEvent.TYPE_CLOSE)
Chris Wren21a2e722017-10-02 17:44:53 -04004520 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
4521 mDuration)
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004522 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4523 mSnoozeCriterionId == null ? 0 : 1));
Julia Reynolds0839c022017-06-15 15:24:01 -04004524 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004525 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004526 updateLightsLocked();
4527 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004528 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004529 mSnoozeHelper.snooze(r);
4530 } else {
4531 mSnoozeHelper.snooze(r, mDuration);
4532 }
Julia Reynolds503ed942017-10-04 16:04:56 -04004533 r.recordSnoozed();
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004534 savePolicyFile();
4535 }
4536 }
4537
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004538 protected class CancelNotificationRunnable implements Runnable {
4539 private final int mCallingUid;
4540 private final int mCallingPid;
4541 private final String mPkg;
4542 private final String mTag;
4543 private final int mId;
4544 private final int mMustHaveFlags;
4545 private final int mMustNotHaveFlags;
4546 private final boolean mSendDelete;
4547 private final int mUserId;
4548 private final int mReason;
4549 private final int mRank;
4550 private final int mCount;
4551 private final ManagedServiceInfo mListener;
4552
4553 CancelNotificationRunnable(final int callingUid, final int callingPid,
4554 final String pkg, final String tag, final int id,
4555 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
4556 final int userId, final int reason, int rank, int count,
4557 final ManagedServiceInfo listener) {
4558 this.mCallingUid = callingUid;
4559 this.mCallingPid = callingPid;
4560 this.mPkg = pkg;
4561 this.mTag = tag;
4562 this.mId = id;
4563 this.mMustHaveFlags = mustHaveFlags;
4564 this.mMustNotHaveFlags = mustNotHaveFlags;
4565 this.mSendDelete = sendDelete;
4566 this.mUserId = userId;
4567 this.mReason = reason;
4568 this.mRank = rank;
4569 this.mCount = count;
4570 this.mListener = listener;
4571 }
4572
4573 @Override
4574 public void run() {
4575 String listenerName = mListener == null ? null : mListener.component.toShortString();
4576 if (DBG) {
4577 EventLogTags.writeNotificationCancel(mCallingUid, mCallingPid, mPkg, mId, mTag,
4578 mUserId, mMustHaveFlags, mMustNotHaveFlags, mReason, listenerName);
4579 }
4580
4581 synchronized (mNotificationLock) {
4582 // Look for the notification, searching both the posted and enqueued lists.
4583 NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId);
4584 if (r != null) {
4585 // The notification was found, check if it should be removed.
4586
4587 // Ideally we'd do this in the caller of this method. However, that would
4588 // require the caller to also find the notification.
4589 if (mReason == REASON_CLICK) {
4590 mUsageStats.registerClickedByUser(r);
4591 }
4592
4593 if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) {
4594 return;
4595 }
4596 if ((r.getNotification().flags & mMustNotHaveFlags) != 0) {
4597 return;
4598 }
4599
4600 // Cancel the notification.
4601 boolean wasPosted = removeFromNotificationListsLocked(r);
4602 cancelNotificationLocked(
4603 r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName);
4604 cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
4605 mSendDelete, null);
4606 updateLightsLocked();
4607 } else {
4608 // No notification was found, assume that it is snoozed and cancel it.
4609 if (mReason != REASON_SNOOZED) {
4610 final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId);
4611 if (wasSnoozed) {
4612 savePolicyFile();
4613 }
4614 }
4615 }
4616 }
4617 }
4618 }
4619
Julia Reynoldsbaff4002016-12-15 11:34:26 -05004620 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05004621 private final NotificationRecord r;
4622 private final int userId;
4623
4624 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
4625 this.userId = userId;
4626 this.r = r;
4627 };
4628
4629 @Override
4630 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004631 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05004632 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05004633 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05004634
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004635 final StatusBarNotification n = r.sbn;
4636 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
4637 NotificationRecord old = mNotificationsByKey.get(n.getKey());
4638 if (old != null) {
4639 // Retain ranking information from previous record
4640 r.copyRankingInformation(old);
4641 }
4642
4643 final int callingUid = n.getUid();
4644 final int callingPid = n.getInitialPid();
4645 final Notification notification = n.getNotification();
4646 final String pkg = n.getPackageName();
4647 final int id = n.getId();
4648 final String tag = n.getTag();
4649
4650 // Handle grouped notifications and bail out early if we
4651 // can to avoid extracting signals.
4652 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
4653
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004654 // if this is a group child, unsnooze parent summary
4655 if (n.isGroup() && notification.isGroupChild()) {
4656 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
4657 }
4658
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004659 // This conditional is a dirty hack to limit the logging done on
4660 // behalf of the download manager without affecting other apps.
4661 if (!pkg.equals("com.android.providers.downloads")
4662 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
4663 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05004664 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004665 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05004666 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004667 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
4668 pkg, id, tag, userId, notification.toString(),
4669 enqueueStatus);
4670 }
Chris Wren6676dab2016-12-21 18:26:27 -05004671
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004672 mRankingHelper.extractSignals(r);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004673 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004674 if (mAssistants.isEnabled()) {
4675 mAssistants.onNotificationEnqueued(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004676 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004677 DELAY_FOR_ASSISTANT_TIME);
4678 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004679 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004680 }
4681 }
4682 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004683 }
4684
Beverly5a20a5e2018-03-06 15:02:44 -05004685 @GuardedBy("mNotificationLock")
4686 private boolean isPackageSuspendedLocked(NotificationRecord r) {
4687 final String pkg = r.sbn.getPackageName();
4688 final int callingUid = r.sbn.getUid();
4689
4690 return isPackageSuspendedForUser(pkg, callingUid);
4691 }
4692
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004693 protected class PostNotificationRunnable implements Runnable {
4694 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004695
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004696 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004697 this.key = key;
4698 }
4699
4700 @Override
4701 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004702 synchronized (mNotificationLock) {
4703 try {
4704 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004705 int N = mEnqueuedNotifications.size();
4706 for (int i = 0; i < N; i++) {
4707 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4708 if (Objects.equals(key, enqueued.getKey())) {
4709 r = enqueued;
4710 break;
Chris Wren6676dab2016-12-21 18:26:27 -05004711 }
Chris Wren6676dab2016-12-21 18:26:27 -05004712 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004713 if (r == null) {
4714 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
4715 return;
4716 }
Beverly5a20a5e2018-03-06 15:02:44 -05004717
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004718 if (isBlocked(r)) {
4719 Slog.i(TAG, "notification blocked by assistant request");
4720 return;
4721 }
4722
Beverly3c707b42018-09-14 09:49:07 -04004723 final boolean isPackageSuspended = isPackageSuspendedLocked(r);
4724 r.setHidden(isPackageSuspended);
4725 if (isPackageSuspended) {
4726 mUsageStats.registerSuspendedByAdmin(r);
4727 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004728 NotificationRecord old = mNotificationsByKey.get(key);
4729 final StatusBarNotification n = r.sbn;
4730 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05004731 int index = indexOfNotificationLocked(n.getKey());
4732 if (index < 0) {
4733 mNotificationList.add(r);
4734 mUsageStats.registerPostedByApp(r);
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004735 r.setInterruptive(isVisuallyInterruptive(null, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004736 } else {
4737 old = mNotificationList.get(index);
4738 mNotificationList.set(index, r);
4739 mUsageStats.registerUpdatedByApp(r, old);
4740 // Make sure we don't lose the foreground service state.
4741 notification.flags |=
Julia Reynoldse5c60452018-04-30 14:41:36 -04004742 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
Chris Wren6676dab2016-12-21 18:26:27 -05004743 r.isUpdate = true;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04004744 r.setTextChanged(isVisuallyInterruptive(old, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004745 }
4746
4747 mNotificationsByKey.put(n.getKey(), r);
4748
4749 // Ensure if this is a foreground service that the proper additional
4750 // flags are set.
Julia Reynoldse5c60452018-04-30 14:41:36 -04004751 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
Chris Wren6676dab2016-12-21 18:26:27 -05004752 notification.flags |= Notification.FLAG_ONGOING_EVENT
4753 | Notification.FLAG_NO_CLEAR;
4754 }
4755
4756 applyZenModeLocked(r);
4757 mRankingHelper.sort(mNotificationList);
4758
Gus Prevasa3226492018-10-23 11:10:09 -04004759 if (!r.isHidden()) {
4760 buzzBeepBlinkLocked(r);
4761 }
4762
Chris Wren6676dab2016-12-21 18:26:27 -05004763 if (notification.getSmallIcon() != null) {
4764 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06004765 mListeners.notifyPostedLocked(r, old);
Brad Stenningd2e7a972018-10-01 09:08:42 -07004766 if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()))
4767 && !isCritical(r)) {
Julia Reynolds8aebf352017-06-26 11:35:33 -04004768 mHandler.post(new Runnable() {
4769 @Override
4770 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04004771 mGroupHelper.onNotificationPosted(
4772 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04004773 }
4774 });
4775 }
Chris Wren6676dab2016-12-21 18:26:27 -05004776 } else {
4777 Slog.e(TAG, "Not posting notification without small icon: " + notification);
4778 if (old != null && !old.isCanceled) {
Beverly5a20a5e2018-03-06 15:02:44 -05004779 mListeners.notifyRemovedLocked(r,
Julia Reynolds503ed942017-10-04 16:04:56 -04004780 NotificationListenerService.REASON_ERROR, null);
Chris Wren6676dab2016-12-21 18:26:27 -05004781 mHandler.post(new Runnable() {
4782 @Override
4783 public void run() {
4784 mGroupHelper.onNotificationRemoved(n);
4785 }
4786 });
4787 }
4788 // ATTENTION: in a future release we will bail out here
4789 // so that we do not play sounds, show lights, etc. for invalid
4790 // notifications
4791 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
4792 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05004793 }
Chris Wren47633422016-01-22 09:56:59 -05004794
Julia Reynolds1fac86e2018-03-07 08:30:37 -05004795 maybeRecordInterruptionLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004796 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004797 int N = mEnqueuedNotifications.size();
4798 for (int i = 0; i < N; i++) {
4799 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4800 if (Objects.equals(key, enqueued.getKey())) {
4801 mEnqueuedNotifications.remove(i);
4802 break;
4803 }
4804 }
Chris Wren6676dab2016-12-21 18:26:27 -05004805 }
Chris Wren47633422016-01-22 09:56:59 -05004806 }
4807 }
4808 }
4809
Christoph Studer265c1052014-07-23 17:14:33 +02004810 /**
Julia Reynolds7217dc92018-03-07 12:12:09 -05004811 * If the notification differs enough visually, consider it a new interruptive notification.
4812 */
4813 @GuardedBy("mNotificationLock")
4814 @VisibleForTesting
4815 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
Julia Reynolds760fa762018-06-19 15:39:23 -04004816 // Ignore summary updates because we don't display most of the information.
4817 if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
4818 if (DEBUG_INTERRUPTIVENESS) {
4819 Log.v(TAG, "INTERRUPTIVENESS: "
4820 + r.getKey() + " is not interruptive: summary");
4821 }
4822 return false;
4823 }
4824
Dan Sandler7d67bd42018-05-15 14:06:38 -04004825 if (old == null) {
4826 if (DEBUG_INTERRUPTIVENESS) {
4827 Log.v(TAG, "INTERRUPTIVENESS: "
4828 + r.getKey() + " is interruptive: new notification");
4829 }
4830 return true;
4831 }
4832
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004833 if (r == null) {
4834 if (DEBUG_INTERRUPTIVENESS) {
4835 Log.v(TAG, "INTERRUPTIVENESS: "
4836 + r.getKey() + " is not interruptive: null");
4837 }
4838 return false;
4839 }
4840
Julia Reynolds7217dc92018-03-07 12:12:09 -05004841 Notification oldN = old.sbn.getNotification();
4842 Notification newN = r.sbn.getNotification();
Dan Sandler7d67bd42018-05-15 14:06:38 -04004843
Julia Reynolds7217dc92018-03-07 12:12:09 -05004844 if (oldN.extras == null || newN.extras == null) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004845 if (DEBUG_INTERRUPTIVENESS) {
4846 Log.v(TAG, "INTERRUPTIVENESS: "
4847 + r.getKey() + " is not interruptive: no extras");
4848 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004849 return false;
4850 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004851
4852 // Ignore visual interruptions from foreground services because users
4853 // consider them one 'session'. Count them for everything else.
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004854 if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004855 if (DEBUG_INTERRUPTIVENESS) {
4856 Log.v(TAG, "INTERRUPTIVENESS: "
4857 + r.getKey() + " is not interruptive: foreground service");
4858 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004859 return false;
4860 }
4861
Dan Sandler7d67bd42018-05-15 14:06:38 -04004862 final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
4863 final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
4864 if (!Objects.equals(oldTitle, newTitle)) {
4865 if (DEBUG_INTERRUPTIVENESS) {
4866 Log.v(TAG, "INTERRUPTIVENESS: "
4867 + r.getKey() + " is interruptive: changed title");
4868 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)",
4869 oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
4870 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)",
4871 newTitle, newTitle.getClass(), newTitle.hashCode()));
4872 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004873 return true;
4874 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004875 // Do not compare Spannables (will always return false); compare unstyled Strings
4876 final String oldText = String.valueOf(oldN.extras.get(Notification.EXTRA_TEXT));
4877 final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT));
4878 if (!Objects.equals(oldText, newText)) {
4879 if (DEBUG_INTERRUPTIVENESS) {
4880 Log.v(TAG, "INTERRUPTIVENESS: "
4881 + r.getKey() + " is interruptive: changed text");
4882 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)",
4883 oldText, oldText.getClass(), oldText.hashCode()));
4884 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)",
4885 newText, newText.getClass(), newText.hashCode()));
4886 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004887 return true;
4888 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004889 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
4890 if (DEBUG_INTERRUPTIVENESS) {
4891 Log.v(TAG, "INTERRUPTIVENESS: "
4892 + r.getKey() + " is interruptive: completed progress");
4893 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004894 return true;
4895 }
4896 // Actions
4897 if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004898 if (DEBUG_INTERRUPTIVENESS) {
4899 Log.v(TAG, "INTERRUPTIVENESS: "
4900 + r.getKey() + " is interruptive: changed actions");
4901 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004902 return true;
4903 }
4904
4905 try {
4906 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
4907 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
4908
4909 // Style based comparisons
4910 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004911 if (DEBUG_INTERRUPTIVENESS) {
4912 Log.v(TAG, "INTERRUPTIVENESS: "
4913 + r.getKey() + " is interruptive: styles differ");
4914 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004915 return true;
4916 }
4917
4918 // Remote views
4919 if (Notification.areRemoteViewsChanged(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004920 if (DEBUG_INTERRUPTIVENESS) {
4921 Log.v(TAG, "INTERRUPTIVENESS: "
4922 + r.getKey() + " is interruptive: remoteviews differ");
4923 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004924 return true;
4925 }
4926 } catch (Exception e) {
4927 Slog.w(TAG, "error recovering builder", e);
4928 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004929
Julia Reynolds7217dc92018-03-07 12:12:09 -05004930 return false;
4931 }
4932
4933 /**
Brad Stenningd2e7a972018-10-01 09:08:42 -07004934 * Check if the notification is classified as critical.
4935 *
4936 * @param record the record to test for criticality
4937 * @return {@code true} if notification is considered critical
4938 *
4939 * @see CriticalNotificationExtractor for criteria
4940 */
4941 private boolean isCritical(NotificationRecord record) {
4942 // 0 is the most critical
4943 return record.getCriticality() < CriticalNotificationExtractor.NORMAL;
4944 }
4945
4946 /**
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05004947 * Keeps the last 5 packages that have notified, by user.
4948 */
4949 @GuardedBy("mNotificationLock")
4950 @VisibleForTesting
4951 protected void logRecentLocked(NotificationRecord r) {
4952 if (r.isUpdate) {
4953 return;
4954 }
4955 ArrayList<NotifyingApp> recentAppsForUser =
4956 mRecentApps.getOrDefault(r.getUser().getIdentifier(), new ArrayList<>(6));
4957 NotifyingApp na = new NotifyingApp()
4958 .setPackage(r.sbn.getPackageName())
4959 .setUid(r.sbn.getUid())
4960 .setLastNotified(r.sbn.getPostTime());
4961 // A new notification gets an app moved to the front of the list
4962 for (int i = recentAppsForUser.size() - 1; i >= 0; i--) {
4963 NotifyingApp naExisting = recentAppsForUser.get(i);
4964 if (na.getPackage().equals(naExisting.getPackage())
4965 && na.getUid() == naExisting.getUid()) {
4966 recentAppsForUser.remove(i);
4967 break;
4968 }
4969 }
4970 // time is always increasing, so always add to the front of the list
4971 recentAppsForUser.add(0, na);
4972 if (recentAppsForUser.size() > 5) {
4973 recentAppsForUser.remove(recentAppsForUser.size() -1);
4974 }
4975 mRecentApps.put(r.getUser().getIdentifier(), recentAppsForUser);
4976 }
4977
4978 /**
Christoph Studer265c1052014-07-23 17:14:33 +02004979 * Ensures that grouped notification receive their special treatment.
4980 *
4981 * <p>Cancels group children if the new notification causes a group to lose
4982 * its summary.</p>
4983 *
4984 * <p>Updates mSummaryByGroupKey.</p>
4985 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004986 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02004987 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
4988 int callingUid, int callingPid) {
4989 StatusBarNotification sbn = r.sbn;
4990 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07004991 if (n.isGroupSummary() && !sbn.isAppGroup()) {
4992 // notifications without a group shouldn't be a summary, otherwise autobundling can
4993 // lead to bugs
4994 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
4995 }
4996
Christoph Studer265c1052014-07-23 17:14:33 +02004997 String group = sbn.getGroupKey();
4998 boolean isSummary = n.isGroupSummary();
4999
5000 Notification oldN = old != null ? old.sbn.getNotification() : null;
5001 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
5002 boolean oldIsSummary = old != null && oldN.isGroupSummary();
5003
5004 if (oldIsSummary) {
5005 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
5006 if (removedSummary != old) {
5007 String removedKey =
5008 removedSummary != null ? removedSummary.getKey() : "<null>";
5009 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
5010 ", removed=" + removedKey);
5011 }
5012 }
5013 if (isSummary) {
5014 mSummaryByGroupKey.put(group, r);
5015 }
5016
5017 // Clear out group children of the old notification if the update
5018 // causes the group summary to go away. This happens when the old
5019 // notification was a summary and the new one isn't, or when the old
5020 // notification was a summary and its group key changed.
5021 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04005022 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
5023 null);
Christoph Studer265c1052014-07-23 17:14:33 +02005024 }
5025 }
5026
Chris Wren93bb8b82016-03-29 14:35:05 -04005027 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04005028 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05005029 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04005030 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05005031 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
5032 REQUEST_CODE_TIMEOUT,
5033 new Intent(ACTION_NOTIFICATION_TIMEOUT)
5034 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
5035 .appendPath(record.getKey()).build())
5036 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
5037 .putExtra(EXTRA_KEY, record.getKey()),
5038 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05005039 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04005040 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05005041 }
5042 }
5043
5044 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04005045 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04005046 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04005047 boolean buzz = false;
5048 boolean beep = false;
5049 boolean blink = false;
5050
Chris Wrena3446562014-06-03 18:11:47 -04005051 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04005052 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04005053
5054 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04005055 final boolean aboveThreshold =
5056 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04005057
5058 // Remember if this notification already owns the notification channels.
5059 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
5060 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04005061 // These are set inside the conditional if the notification is allowed to make noise.
5062 boolean hasValidVibrate = false;
5063 boolean hasValidSound = false;
Julia Reynolds94187562017-10-10 13:58:49 -04005064 boolean sentAccessibilityEvent = false;
5065 // If the notification will appear in the status bar, it should send an accessibility
5066 // event
5067 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
5068 sendAccessibilityEvent(notification, record.sbn.getPackageName());
5069 sentAccessibilityEvent = true;
5070 }
Chris Wrena3446562014-06-03 18:11:47 -04005071
Julia Reynolds76c096d2017-06-19 08:16:04 -04005072 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04005073
Julia Reynolds76c096d2017-06-19 08:16:04 -04005074 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04005075 Uri soundUri = record.getSound();
5076 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
5077 long[] vibration = record.getVibration();
5078 // Demote sound to vibration if vibration missing & phone in vibration mode.
5079 if (vibration == null
5080 && hasValidSound
5081 && (mAudioManager.getRingerModeInternal()
Julia Reynolds85896572017-09-20 12:54:52 -04005082 == AudioManager.RINGER_MODE_VIBRATE)
5083 && mAudioManager.getStreamVolume(
5084 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04005085 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04005086 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04005087 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01005088
Julia Reynolds76c096d2017-06-19 08:16:04 -04005089 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
Julia Reynolds76c096d2017-06-19 08:16:04 -04005090 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04005091 if (!sentAccessibilityEvent) {
5092 sendAccessibilityEvent(notification, record.sbn.getPackageName());
5093 sentAccessibilityEvent = true;
5094 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005095 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04005096 if (hasValidSound) {
5097 mSoundNotificationKey = key;
5098 if (mInCall) {
5099 playInCallNotification();
5100 beep = true;
5101 } else {
5102 beep = playSound(record, soundUri);
5103 }
5104 }
Chris Wren93bb8b82016-03-29 14:35:05 -04005105
Julia Reynolds7c96b582017-05-25 12:35:36 -04005106 final boolean ringerModeSilent =
5107 mAudioManager.getRingerModeInternal()
5108 == AudioManager.RINGER_MODE_SILENT;
5109 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
5110 mVibrateNotificationKey = key;
5111
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005112 buzz = playVibration(record, vibration, hasValidSound);
Julia Reynolds7c96b582017-05-25 12:35:36 -04005113 }
Tyler Gunn48f86272018-07-03 12:38:49 -07005114 } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
5115 hasValidSound = false;
Chris Wrena3446562014-06-03 18:11:47 -04005116 }
5117 }
Chris Wren93bb8b82016-03-29 14:35:05 -04005118 }
5119 // If a notification is updated to remove the actively playing sound or vibrate,
5120 // cancel that feedback now
5121 if (wasBeep && !hasValidSound) {
5122 clearSoundLocked();
5123 }
5124 if (wasBuzz && !hasValidVibrate) {
5125 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04005126 }
5127
5128 // light
5129 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04005130 boolean wasShowLights = mLights.remove(key);
Julia Reynolds28149f62018-07-03 10:43:35 -04005131 if (canShowLightsLocked(record, aboveThreshold)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04005132 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04005133 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04005134 if (mUseAttentionLight) {
5135 mAttentionLight.pulse();
5136 }
Chris Wren82ba59d2015-06-05 11:23:44 -04005137 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04005138 } else if (wasShowLights) {
5139 updateLightsLocked();
5140 }
Chris Wren82ba59d2015-06-05 11:23:44 -04005141 if (buzz || beep || blink) {
Julia Reynolds28149f62018-07-03 10:43:35 -04005142 // Ignore summary updates because we don't display most of the information.
5143 if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) {
5144 if (DEBUG_INTERRUPTIVENESS) {
5145 Log.v(TAG, "INTERRUPTIVENESS: "
5146 + record.getKey() + " is not interruptive: summary");
5147 }
5148 } else {
5149 if (DEBUG_INTERRUPTIVENESS) {
5150 Log.v(TAG, "INTERRUPTIVENESS: "
5151 + record.getKey() + " is interruptive: alerted");
5152 }
5153 record.setInterruptive(true);
5154 }
Julia Reynolds445cfa82017-05-08 15:41:45 -04005155 MetricsLogger.action(record.getLogMaker()
5156 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
5157 .setType(MetricsEvent.TYPE_OPEN)
5158 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
5159 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04005160 }
Gus Prevasa3226492018-10-23 11:10:09 -04005161 record.setAudiblyAlerted(buzz || beep);
Chris Wrena3446562014-06-03 18:11:47 -04005162 }
5163
Julia Reynolds88860ce2017-06-01 16:55:49 -04005164 @GuardedBy("mNotificationLock")
Julia Reynolds28149f62018-07-03 10:43:35 -04005165 boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
5166 // device lacks light
5167 if (!mHasLight) {
5168 return false;
5169 }
5170 // user turned lights off globally
5171 if (!mNotificationPulseEnabled) {
5172 return false;
5173 }
5174 // the notification/channel has no light
5175 if (record.getLight() == null) {
5176 return false;
5177 }
5178 // unimportant notification
5179 if (!aboveThreshold) {
5180 return false;
5181 }
5182 // suppressed due to DND
5183 if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
5184 return false;
5185 }
5186 // Suppressed because it's a silent update
5187 final Notification notification = record.getNotification();
5188 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
5189 return false;
5190 }
5191 // Suppressed because another notification in its group handles alerting
5192 if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
5193 return false;
5194 }
5195 // not if in call or the screen's on
5196 if (mInCall || mScreenOn) {
5197 return false;
5198 }
5199
5200 return true;
5201 }
5202
5203 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005204 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04005205 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005206 final Notification notification = record.getNotification();
Julia Reynolds28149f62018-07-03 10:43:35 -04005207 if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005208 return true;
5209 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005210
Julia Reynolds76c096d2017-06-19 08:16:04 -04005211 // muted by listener
5212 final String disableEffects = disableNotificationEffects(record);
5213 if (disableEffects != null) {
5214 ZenLog.traceDisableEffects(record, disableEffects);
5215 return true;
5216 }
5217
5218 // suppressed due to DND
5219 if (record.isIntercepted()) {
5220 return true;
5221 }
5222
5223 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005224 if (record.sbn.isGroup()) {
Julia Reynolds79dfdd62018-04-17 15:36:33 -04005225 if (notification.suppressAlertingDueToGrouping()) {
5226 return true;
5227 }
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005228 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005229
Julia Reynolds65b85cf2017-07-20 09:19:20 -04005230 // Suppressed for being too recently noisy
5231 final String pkg = record.sbn.getPackageName();
5232 if (mUsageStats.isAlertRateLimited(pkg)) {
5233 Slog.e(TAG, "Muting recently noisy " + record.getKey());
5234 return true;
5235 }
5236
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005237 return false;
5238 }
5239
Julia Reynolds0c299d42016-11-15 14:37:04 -05005240 private boolean playSound(final NotificationRecord record, Uri soundUri) {
5241 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
Jean-Michel Triviec2bb182018-03-23 18:04:00 -07005242 // play notifications if there is no user of exclusive audio focus
5243 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
5244 // VIBRATE ringer mode)
5245 if (!mAudioManager.isAudioFocusExclusive()
5246 && (mAudioManager.getStreamVolume(
5247 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05005248 final long identity = Binder.clearCallingIdentity();
5249 try {
5250 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5251 if (player != null) {
5252 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
5253 + " with attributes " + record.getAudioAttributes());
5254 player.playAsync(soundUri, record.sbn.getUser(), looping,
5255 record.getAudioAttributes());
5256 return true;
5257 }
5258 } catch (RemoteException e) {
5259 } finally {
5260 Binder.restoreCallingIdentity(identity);
5261 }
5262 }
5263 return false;
5264 }
5265
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005266 private boolean playVibration(final NotificationRecord record, long[] vibration,
5267 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005268 // Escalate privileges so we can use the vibrator even if the
5269 // notifying app does not have the VIBRATE permission.
5270 long identity = Binder.clearCallingIdentity();
5271 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005272 final VibrationEffect effect;
5273 try {
5274 final boolean insistent =
5275 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
5276 effect = VibrationEffect.createWaveform(
5277 vibration, insistent ? 0 : -1 /*repeatIndex*/);
5278 } catch (IllegalArgumentException e) {
5279 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
5280 Arrays.toString(vibration));
5281 return false;
5282 }
5283 if (delayVibForSound) {
5284 new Thread(() -> {
5285 // delay the vibration by the same amount as the notification sound
5286 final int waitMs = mAudioManager.getFocusRampTimeMs(
5287 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
5288 record.getAudioAttributes());
5289 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
5290 try {
5291 Thread.sleep(waitMs);
5292 } catch (InterruptedException e) { }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04005293 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01005294 effect, "Notification (delayed)", record.getAudioAttributes());
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005295 }).start();
5296 } else {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04005297 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01005298 effect, "Notification", record.getAudioAttributes());
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005299 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005300 return true;
5301 } finally{
5302 Binder.restoreCallingIdentity(identity);
5303 }
5304 }
5305
Julia Reynolds7c96b582017-05-25 12:35:36 -04005306 private boolean isNotificationForCurrentUser(NotificationRecord record) {
5307 final int currentUser;
5308 final long token = Binder.clearCallingIdentity();
5309 try {
5310 currentUser = ActivityManager.getCurrentUser();
5311 } finally {
5312 Binder.restoreCallingIdentity(token);
5313 }
5314 return (record.getUserId() == UserHandle.USER_ALL ||
5315 record.getUserId() == currentUser ||
5316 mUserProfiles.isCurrentProfile(record.getUserId()));
5317 }
5318
Beverly5d463b62017-07-26 14:13:40 -04005319 protected void playInCallNotification() {
Beverly28c3d162018-06-28 11:37:53 -04005320 if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL
5321 && Settings.Secure.getInt(getContext().getContentResolver(),
5322 Settings.Secure.IN_CALL_NOTIFICATION_ENABLED, 1) != 0) {
5323 new Thread() {
5324 @Override
5325 public void run() {
5326 final long identity = Binder.clearCallingIdentity();
5327 try {
5328 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5329 if (player != null) {
5330 if (mCallNotificationToken != null) {
5331 player.stop(mCallNotificationToken);
5332 }
5333 mCallNotificationToken = new Binder();
5334 player.play(mCallNotificationToken, mInCallNotificationUri,
5335 mInCallNotificationAudioAttributes,
5336 mInCallNotificationVolume, false);
luochaojiang50e5273c2018-04-16 16:55:03 +08005337 }
Beverly28c3d162018-06-28 11:37:53 -04005338 } catch (RemoteException e) {
5339 } finally {
5340 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01005341 }
Marta Białka39c992f2011-03-10 10:27:24 +01005342 }
Beverly28c3d162018-06-28 11:37:53 -04005343 }.start();
5344 }
Marta Białka39c992f2011-03-10 10:27:24 +01005345 }
5346
Julia Reynolds88860ce2017-06-01 16:55:49 -04005347 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005348 void showNextToastLocked() {
5349 ToastRecord record = mToastQueue.get(0);
5350 while (record != null) {
5351 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
5352 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005353 record.callback.show(record.token);
Robert Carr997427342018-02-28 18:06:10 -08005354 scheduleDurationReachedLocked(record);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005355 return;
5356 } catch (RemoteException e) {
5357 Slog.w(TAG, "Object died trying to show notification " + record.callback
5358 + " in package " + record.pkg);
5359 // remove it from the list and let the process die
5360 int index = mToastQueue.indexOf(record);
5361 if (index >= 0) {
5362 mToastQueue.remove(index);
5363 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005364 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005365 if (mToastQueue.size() > 0) {
5366 record = mToastQueue.get(0);
5367 } else {
5368 record = null;
5369 }
5370 }
5371 }
5372 }
5373
Julia Reynolds88860ce2017-06-01 16:55:49 -04005374 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005375 void cancelToastLocked(int index) {
5376 ToastRecord record = mToastQueue.get(index);
5377 try {
5378 record.callback.hide();
5379 } catch (RemoteException e) {
5380 Slog.w(TAG, "Object died trying to hide notification " + record.callback
5381 + " in package " + record.pkg);
5382 // don't worry about this, we're about to remove it from
5383 // the list anyway
5384 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005385
5386 ToastRecord lastToast = mToastQueue.remove(index);
Robert Carr997427342018-02-28 18:06:10 -08005387
5388 mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
Jeff Chang48ecef42018-08-09 16:31:59 +08005389 lastToast.displayId);
Robert Carr997427342018-02-28 18:06:10 -08005390 // We passed 'false' for 'removeWindows' so that the client has time to stop
5391 // rendering (as hide above is a one-way message), otherwise we could crash
5392 // a client which was actively using a surface made from the token. However
5393 // we need to schedule a timeout to make sure the token is eventually killed
5394 // one way or another.
Jeff Chang48ecef42018-08-09 16:31:59 +08005395 scheduleKillTokenTimeout(lastToast);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005396
5397 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005398 if (mToastQueue.size() > 0) {
5399 // Show the next one. If the callback fails, this will remove
5400 // it from the list, so don't assume that the list hasn't changed
5401 // after this point.
5402 showNextToastLocked();
5403 }
5404 }
5405
Jeff Chang48ecef42018-08-09 16:31:59 +08005406 void finishTokenLocked(IBinder t, int displayId) {
Robert Carr997427342018-02-28 18:06:10 -08005407 mHandler.removeCallbacksAndMessages(t);
5408 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
5409 // remaining surfaces as either the client has called finishToken indicating
5410 // it has successfully removed the views, or the client has timed out
5411 // at which point anything goes.
Jeff Chang48ecef42018-08-09 16:31:59 +08005412 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */, displayId);
Robert Carr997427342018-02-28 18:06:10 -08005413 }
5414
Julia Reynolds88860ce2017-06-01 16:55:49 -04005415 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08005416 private void scheduleDurationReachedLocked(ToastRecord r)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005417 {
5418 mHandler.removeCallbacksAndMessages(r);
Robert Carr997427342018-02-28 18:06:10 -08005419 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005420 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
5421 mHandler.sendMessageDelayed(m, delay);
5422 }
5423
Robert Carr997427342018-02-28 18:06:10 -08005424 private void handleDurationReached(ToastRecord record)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005425 {
5426 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
5427 synchronized (mToastQueue) {
5428 int index = indexOfToastLocked(record.pkg, record.callback);
5429 if (index >= 0) {
5430 cancelToastLocked(index);
5431 }
5432 }
5433 }
5434
Julia Reynolds88860ce2017-06-01 16:55:49 -04005435 @GuardedBy("mToastQueue")
Jeff Chang48ecef42018-08-09 16:31:59 +08005436 private void scheduleKillTokenTimeout(ToastRecord r)
Robert Carr997427342018-02-28 18:06:10 -08005437 {
Jeff Chang48ecef42018-08-09 16:31:59 +08005438 mHandler.removeCallbacksAndMessages(r);
5439 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, r);
Robert Carr3406d462018-03-15 16:19:07 -07005440 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
Robert Carr997427342018-02-28 18:06:10 -08005441 }
5442
Jeff Chang48ecef42018-08-09 16:31:59 +08005443 private void handleKillTokenTimeout(ToastRecord record)
Robert Carr997427342018-02-28 18:06:10 -08005444 {
Jeff Chang48ecef42018-08-09 16:31:59 +08005445 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.token);
Robert Carr997427342018-02-28 18:06:10 -08005446 synchronized (mToastQueue) {
Jeff Chang48ecef42018-08-09 16:31:59 +08005447 finishTokenLocked(record.token, record.displayId);
Robert Carr997427342018-02-28 18:06:10 -08005448 }
5449 }
5450
5451 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005452 int indexOfToastLocked(String pkg, ITransientNotification callback)
5453 {
5454 IBinder cbak = callback.asBinder();
5455 ArrayList<ToastRecord> list = mToastQueue;
5456 int len = list.size();
5457 for (int i=0; i<len; i++) {
5458 ToastRecord r = list.get(i);
Beverly Taia7ed0ab2018-06-11 14:50:36 +00005459 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08005460 return i;
5461 }
5462 }
5463 return -1;
5464 }
5465
Julia Reynolds88860ce2017-06-01 16:55:49 -04005466 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005467 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005468 {
5469 int toastCount = 0; // toasts from this pid
5470 ArrayList<ToastRecord> list = mToastQueue;
5471 int N = list.size();
5472 for (int i=0; i<N; i++) {
5473 ToastRecord r = list.get(i);
5474 if (r.pid == pid) {
5475 toastCount++;
5476 }
5477 }
5478 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07005479 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08005480 } catch (RemoteException e) {
5481 // Shouldn't happen.
5482 }
5483 }
5484
Chris Wrenf9536642014-04-17 10:01:54 -04005485 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005486 if (!(message.obj instanceof RankingReconsideration)) return;
5487 RankingReconsideration recon = (RankingReconsideration) message.obj;
5488 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04005489 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005490 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005491 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
5492 if (record == null) {
5493 return;
Chris Wrenf9536642014-04-17 10:01:54 -04005494 }
Chris Wren333a61c2014-05-28 16:40:57 -04005495 int indexBefore = findNotificationRecordIndexLocked(record);
5496 boolean interceptBefore = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005497 float contactAffinityBefore = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005498 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04005499 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04005500 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04005501 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04005502 int indexAfter = findNotificationRecordIndexLocked(record);
5503 boolean interceptAfter = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005504 float contactAffinityAfter = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005505 int visibilityAfter = record.getPackageVisibilityOverride();
5506 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
5507 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005508 if (interceptBefore && !interceptAfter
5509 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
Chris Wrena3446562014-06-03 18:11:47 -04005510 buzzBeepBlinkLocked(record);
5511 }
Chris Wrenf9536642014-04-17 10:01:54 -04005512 }
Chris Wren333a61c2014-05-28 16:40:57 -04005513 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005514 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04005515 }
5516 }
5517
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005518 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04005519 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005520 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04005521 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005522 // Any field that can change via one of the extractors needs to be added here.
5523 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005524 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05005525 boolean[] showBadges = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005526 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
5527 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
5528 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
5529 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Julia Reynolds503ed942017-10-04 16:04:56 -04005530 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005531 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
Tony Mak628cb932018-06-19 18:30:41 +01005532 ArrayList<ArrayList<Notification.Action>> smartActionsBefore = new ArrayList<>(N);
Tony Makc9acf672018-07-20 13:58:24 +02005533 ArrayList<ArrayList<CharSequence>> smartRepliesBefore = new ArrayList<>(N);
Chris Wren54bbef42014-07-09 18:37:56 -04005534 for (int i = 0; i < N; i++) {
5535 final NotificationRecord r = mNotificationList.get(i);
5536 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005537 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05005538 showBadges[i] = r.canShowBadge();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005539 channelBefore.add(r.getChannel());
5540 groupKeyBefore.add(r.getGroupKey());
5541 overridePeopleBefore.add(r.getPeopleOverride());
5542 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Julia Reynolds503ed942017-10-04 16:04:56 -04005543 userSentimentBefore.add(r.getUserSentiment());
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005544 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
Tony Mak628cb932018-06-19 18:30:41 +01005545 smartActionsBefore.add(r.getSmartActions());
Tony Makc9acf672018-07-20 13:58:24 +02005546 smartRepliesBefore.add(r.getSmartReplies());
Chris Wren54bbef42014-07-09 18:37:56 -04005547 mRankingHelper.extractSignals(r);
5548 }
Chris Wren19a02b02015-12-22 10:34:22 -05005549 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04005550 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005551 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005552 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05005553 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005554 || showBadges[i] != r.canShowBadge()
5555 || !Objects.equals(channelBefore.get(i), r.getChannel())
5556 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
5557 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
Julia Reynolds503ed942017-10-04 16:04:56 -04005558 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005559 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
5560 || !Objects.equals(suppressVisuallyBefore.get(i),
Tony Mak628cb932018-06-19 18:30:41 +01005561 r.getSuppressedVisualEffects())
Tony Makc9acf672018-07-20 13:58:24 +02005562 || !Objects.equals(smartActionsBefore.get(i), r.getSmartActions())
5563 || !Objects.equals(smartRepliesBefore.get(i), r.getSmartReplies())) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005564 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04005565 return;
5566 }
5567 }
5568 }
5569 }
5570
Julia Reynolds88860ce2017-06-01 16:55:49 -04005571 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005572 private void recordCallerLocked(NotificationRecord record) {
5573 if (mZenModeHelper.isCall(record)) {
5574 mZenModeHelper.recordCaller(record);
5575 }
5576 }
5577
Christoph Studerd5092bc2014-07-03 17:47:58 +02005578 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04005579 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005580 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02005581 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005582 if (record.isIntercepted()) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05005583 record.setSuppressedVisualEffects(
Beverlyff2df9b2018-10-10 16:54:10 -04005584 mZenModeHelper.getConsolidatedNotificationPolicy().suppressedVisualEffects);
Julia Reynolds445cfa82017-05-08 15:41:45 -04005585 } else {
5586 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005587 }
Chris Wren333a61c2014-05-28 16:40:57 -04005588 }
5589
Julia Reynolds88860ce2017-06-01 16:55:49 -04005590 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04005591 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04005592 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04005593 }
5594
Chris Wrenf9536642014-04-17 10:01:54 -04005595 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005596 synchronized (mNotificationLock) {
Beverly5a20a5e2018-03-06 15:02:44 -05005597 mListeners.notifyRankingUpdateLocked(null);
Chris Wrenf9536642014-04-17 10:01:54 -04005598 }
5599 }
5600
John Spurlockd8afe3c2014-08-01 14:04:07 -04005601 private void scheduleListenerHintsChanged(int state) {
5602 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
5603 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04005604 }
5605
Christoph Studer85a384b2014-08-27 20:16:15 +02005606 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
5607 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
5608 mHandler.obtainMessage(
5609 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
5610 listenerInterruptionFilter,
5611 0).sendToTarget();
5612 }
5613
John Spurlockd8afe3c2014-08-01 14:04:07 -04005614 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005615 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005616 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005617 }
5618 }
5619
Christoph Studer85a384b2014-08-27 20:16:15 +02005620 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005621 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02005622 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
5623 }
5624 }
5625
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005626 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08005627 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005628 public WorkerHandler(Looper looper) {
5629 super(looper);
5630 }
5631
Adam Lesinski182f73f2013-12-05 16:48:06 -08005632 @Override
5633 public void handleMessage(Message msg)
5634 {
5635 switch (msg.what)
5636 {
Robert Carr997427342018-02-28 18:06:10 -08005637 case MESSAGE_DURATION_REACHED:
5638 handleDurationReached((ToastRecord)msg.obj);
5639 break;
5640 case MESSAGE_FINISH_TOKEN_TIMEOUT:
Jeff Chang48ecef42018-08-09 16:31:59 +08005641 handleKillTokenTimeout((ToastRecord)msg.obj);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005642 break;
John Spurlock056c5192014-04-20 21:52:01 -04005643 case MESSAGE_SAVE_POLICY_FILE:
5644 handleSavePolicyFile();
5645 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005646 case MESSAGE_SEND_RANKING_UPDATE:
5647 handleSendRankingUpdate();
5648 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04005649 case MESSAGE_LISTENER_HINTS_CHANGED:
5650 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04005651 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02005652 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
5653 handleListenerInterruptionFilterChanged(msg.arg1);
5654 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005655 }
5656 }
5657
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005658 protected void scheduleSendRankingUpdate() {
5659 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
5660 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
5661 sendMessage(m);
5662 }
5663 }
5664
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005665 protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable) {
5666 if (!hasCallbacks(cancelRunnable)) {
5667 sendMessage(Message.obtain(this, cancelRunnable));
5668 }
5669 }
Chris Wrenf9536642014-04-17 10:01:54 -04005670 }
5671
Chris Wren51017d02015-12-15 15:34:46 -05005672 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04005673 {
Chris Wren51017d02015-12-15 15:34:46 -05005674 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04005675 super(looper);
5676 }
5677
5678 @Override
5679 public void handleMessage(Message msg) {
5680 switch (msg.what) {
5681 case MESSAGE_RECONSIDER_RANKING:
5682 handleRankingReconsideration(msg);
5683 break;
Chris Wren51017d02015-12-15 15:34:46 -05005684 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005685 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04005686 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08005687 }
5688 }
Chris Wren51017d02015-12-15 15:34:46 -05005689
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005690 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05005691 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05005692 Message msg = Message.obtain();
5693 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05005694 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05005695 }
5696
5697 public void requestReconsideration(RankingReconsideration recon) {
5698 Message m = Message.obtain(this,
5699 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
5700 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
5701 sendMessageDelayed(m, delay);
5702 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08005703 }
5704
Adam Lesinski182f73f2013-12-05 16:48:06 -08005705 // Notifications
5706 // ============================================================================
5707 static int clamp(int x, int low, int high) {
5708 return (x < low) ? low : ((x > high) ? high : x);
5709 }
5710
5711 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
Eugene Suslad4128ec2017-12-04 19:48:41 +00005712 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07005713 return;
5714 }
5715
5716 AccessibilityEvent event =
5717 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
5718 event.setPackageName(packageName);
5719 event.setClassName(Notification.class.getName());
5720 event.setParcelableData(notification);
5721 CharSequence tickerText = notification.tickerText;
5722 if (!TextUtils.isEmpty(tickerText)) {
5723 event.getText().add(tickerText);
5724 }
5725
Julia Reynolds94187562017-10-10 13:58:49 -04005726 mAccessibilityManager.sendAccessibilityEvent(event);
svetoslavganov75986cf2009-05-14 22:28:01 -07005727 }
5728
Julia Reynolds0839c022017-06-15 15:24:01 -04005729 /**
5730 * Removes all NotificationsRecords with the same key as the given notification record
5731 * from both lists. Do not call this method while iterating over either list.
5732 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005733 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04005734 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
5735 // Remove from both lists, either list could have a separate Record for what is
5736 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005737 boolean wasPosted = false;
5738 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04005739 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
5740 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005741 mNotificationList.remove(recordInList);
5742 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005743 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005744 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005745 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005746 != null) {
5747 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005748 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005749 return wasPosted;
5750 }
5751
5752 @GuardedBy("mNotificationLock")
5753 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04005754 boolean wasPosted, String listenerName) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005755 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName);
5756 }
5757
5758 @GuardedBy("mNotificationLock")
5759 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
5760 int rank, int count, boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04005761 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005762
5763 // Record caller.
5764 recordCallerLocked(r);
5765
Julia Reynolds503ed942017-10-04 16:04:56 -04005766 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
5767 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
5768 }
5769
Joe Onorato46439ce2010-11-19 13:56:21 -08005770 // tell the app
5771 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005772 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08005773 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005774 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08005775 } catch (PendingIntent.CanceledException ex) {
5776 // do nothing - there's no relevant way to recover, and
5777 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04005778 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08005779 }
5780 }
5781 }
5782
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005783 // Only cancel these if this notification actually got to be posted.
5784 if (wasPosted) {
5785 // status bar
5786 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005787 if (reason != REASON_SNOOZED) {
5788 r.isCanceled = true;
5789 }
Beverly5a20a5e2018-03-06 15:02:44 -05005790 mListeners.notifyRemovedLocked(r, reason, r.getStats());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005791 mHandler.post(new Runnable() {
5792 @Override
5793 public void run() {
5794 mGroupHelper.onNotificationRemoved(r.sbn);
5795 }
5796 });
5797 }
5798
5799 // sound
5800 if (canceledKey.equals(mSoundNotificationKey)) {
5801 mSoundNotificationKey = null;
5802 final long identity = Binder.clearCallingIdentity();
5803 try {
5804 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5805 if (player != null) {
5806 player.stopAsync();
5807 }
5808 } catch (RemoteException e) {
5809 } finally {
5810 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04005811 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005812 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005813
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005814 // vibrate
5815 if (canceledKey.equals(mVibrateNotificationKey)) {
5816 mVibrateNotificationKey = null;
5817 long identity = Binder.clearCallingIdentity();
5818 try {
5819 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005820 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005821 finally {
5822 Binder.restoreCallingIdentity(identity);
5823 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005824 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005825
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005826 // light
5827 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005828 }
5829
Christoph Studer546bec82014-03-14 12:17:12 +01005830 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04005831 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01005832 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005833 case REASON_CANCEL:
5834 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005835 case REASON_LISTENER_CANCEL:
5836 case REASON_LISTENER_CANCEL_ALL:
5837 mUsageStats.registerDismissedByUser(r);
5838 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05005839 case REASON_APP_CANCEL:
5840 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005841 mUsageStats.registerRemovedByApp(r);
5842 break;
Christoph Studer546bec82014-03-14 12:17:12 +01005843 }
5844
Christoph Studer265c1052014-07-23 17:14:33 +02005845 String groupKey = r.getGroupKey();
5846 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005847 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02005848 mSummaryByGroupKey.remove(groupKey);
5849 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04005850 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
5851 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
5852 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04005853 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005854
Daniel Sandler23d7c702013-03-07 16:32:06 -05005855 // Save it for users of getHistoricalNotifications()
5856 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02005857
Chris Wren6650e572015-05-15 17:19:25 -04005858 final long now = System.currentTimeMillis();
Julia Reynolds3dfdde02018-10-08 09:17:56 -04005859 final LogMaker logMaker = r.getItemLogMaker()
Chris Wren9eb5e102017-01-26 13:15:06 -05005860 .setType(MetricsEvent.TYPE_DISMISS)
Dieter Hsud39f0d52018-04-14 02:08:30 +08005861 .setSubtype(reason);
5862 if (rank != -1 && count != -1) {
5863 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
5864 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
5865 }
5866 MetricsLogger.action(logMaker);
Chris Wrene6ddb8a2015-05-27 15:21:00 -04005867 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Dieter Hsud39f0d52018-04-14 02:08:30 +08005868 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
5869 rank, count, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005870 }
5871
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005872 @VisibleForTesting
5873 void updateUriPermissions(@Nullable NotificationRecord newRecord,
5874 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) {
5875 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey();
5876 if (DBG) Slog.d(TAG, key + ": updating permissions");
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005877
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005878 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null;
5879 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null;
5880
5881 // Shortcut when no Uris involved
5882 if (newUris == null && oldUris == null) {
5883 return;
5884 }
5885
5886 // Inherit any existing owner
5887 IBinder permissionOwner = null;
5888 if (newRecord != null && permissionOwner == null) {
5889 permissionOwner = newRecord.permissionOwner;
5890 }
5891 if (oldRecord != null && permissionOwner == null) {
5892 permissionOwner = oldRecord.permissionOwner;
5893 }
5894
5895 // If we have Uris to grant, but no owner yet, go create one
5896 if (newUris != null && permissionOwner == null) {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07005897 if (DBG) Slog.d(TAG, key + ": creating owner");
5898 permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005899 }
5900
5901 // If we have no Uris to grant, but an existing owner, go destroy it
5902 if (newUris == null && permissionOwner != null) {
5903 final long ident = Binder.clearCallingIdentity();
5904 try {
5905 if (DBG) Slog.d(TAG, key + ": destroying owner");
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07005906 mUgmInternal.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005907 UserHandle.getUserId(oldRecord.getUid()));
5908 permissionOwner = null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005909 } finally {
5910 Binder.restoreCallingIdentity(ident);
5911 }
5912 }
5913
5914 // Grant access to new Uris
5915 if (newUris != null && permissionOwner != null) {
5916 for (int i = 0; i < newUris.size(); i++) {
5917 final Uri uri = newUris.valueAt(i);
5918 if (oldUris == null || !oldUris.contains(uri)) {
5919 if (DBG) Slog.d(TAG, key + ": granting " + uri);
5920 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
5921 targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005922 }
5923 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005924 }
5925
5926 // Revoke access to old Uris
5927 if (oldUris != null && permissionOwner != null) {
5928 for (int i = 0; i < oldUris.size(); i++) {
5929 final Uri uri = oldUris.valueAt(i);
5930 if (newUris == null || !newUris.contains(uri)) {
5931 if (DBG) Slog.d(TAG, key + ": revoking " + uri);
5932 revokeUriPermission(permissionOwner, uri, oldRecord.getUid());
5933 }
5934 }
5935 }
5936
5937 if (newRecord != null) {
5938 newRecord.permissionOwner = permissionOwner;
5939 }
5940 }
5941
5942 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg,
5943 int targetUserId) {
5944 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5945
5946 final long ident = Binder.clearCallingIdentity();
5947 try {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07005948 mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005949 ContentProvider.getUriWithoutUserId(uri),
5950 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5951 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
5952 targetUserId);
5953 } catch (RemoteException ignored) {
5954 // Ignored because we're in same process
5955 } finally {
5956 Binder.restoreCallingIdentity(ident);
5957 }
5958 }
5959
5960 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUid) {
5961 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5962
5963 final long ident = Binder.clearCallingIdentity();
5964 try {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07005965 mUgmInternal.revokeUriPermissionFromOwner(
5966 owner,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005967 ContentProvider.getUriWithoutUserId(uri),
5968 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5969 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005970 } finally {
5971 Binder.restoreCallingIdentity(ident);
5972 }
5973 }
5974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005975 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07005976 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005977 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005978 */
John Spurlocke6a7d932014-03-13 12:29:00 -04005979 void cancelNotification(final int callingUid, final int callingPid,
5980 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005981 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04005982 final int userId, final int reason, final ManagedServiceInfo listener) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005983 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
5984 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
5985 }
5986
5987 /**
5988 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
5989 * and none of the {@code mustNotHaveFlags}.
5990 */
5991 void cancelNotification(final int callingUid, final int callingPid,
5992 final String pkg, final String tag, final int id,
5993 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005994 final int userId, final int reason, int rank, int count,
5995 final ManagedServiceInfo listener) {
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005996 // In enqueueNotificationInternal notifications are added by scheduling the
5997 // work on the worker handler. Hence, we also schedule the cancel on this
5998 // handler to avoid a scenario where an add notification call followed by a
5999 // remove notification call ends up in not removing the notification.
Julia Reynoldsefcdff42018-08-09 09:42:56 -04006000 mHandler.scheduleCancelNotification(new CancelNotificationRunnable(callingUid, callingPid,
6001 pkg, tag, id, mustHaveFlags, mustNotHaveFlags, sendDelete, userId, reason, rank,
6002 count, listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006003 }
6004
6005 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07006006 * Determine whether the userId applies to the notification in question, either because
6007 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
6008 */
6009 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
6010 return
6011 // looking for USER_ALL notifications? match everything
6012 userId == UserHandle.USER_ALL
6013 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05006014 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07006015 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05006016 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07006017 }
6018
6019 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006020 * Determine whether the userId applies to the notification in question, either because
6021 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01006022 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006023 */
Kenny Guy2a764942014-04-02 13:29:20 +01006024 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00006025 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04006026 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006027 }
6028
6029 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05006030 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006031 * {@code mustHaveFlags}.
6032 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006033 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04006034 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04006035 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006036 mHandler.post(new Runnable() {
6037 @Override
6038 public void run() {
6039 String listenerName = listener == null ? null : listener.component.toShortString();
6040 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
6041 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
6042 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006043
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006044 // Why does this parameter exist? Do we actually want to execute the above if doit
6045 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08006046 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006047 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08006048 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006049
6050 synchronized (mNotificationLock) {
6051 FlagChecker flagChecker = (int flags) -> {
6052 if ((flags & mustHaveFlags) != mustHaveFlags) {
6053 return false;
6054 }
6055 if ((flags & mustNotHaveFlags) != 0) {
6056 return false;
6057 }
6058 return true;
6059 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006060 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
6061 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
6062 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04006063 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006064 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
6065 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
6066 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04006067 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006068 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02006069 }
6070 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006071 });
6072 }
6073
6074 private interface FlagChecker {
6075 // Returns false if these flags do not pass the defined flag test.
6076 public boolean apply(int flags);
6077 }
6078
Julia Reynolds88860ce2017-06-01 16:55:49 -04006079 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006080 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
6081 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
6082 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04006083 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006084 ArrayList<NotificationRecord> canceledNotifications = null;
6085 for (int i = notificationList.size() - 1; i >= 0; --i) {
6086 NotificationRecord r = notificationList.get(i);
6087 if (includeCurrentProfiles) {
6088 if (!notificationMatchesCurrentProfiles(r, userId)) {
6089 continue;
6090 }
6091 } else if (!notificationMatchesUserId(r, userId)) {
6092 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006093 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006094 // Don't remove notifications to all, if there's no package name specified
6095 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
6096 continue;
6097 }
6098 if (!flagChecker.apply(r.getFlags())) {
6099 continue;
6100 }
6101 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
6102 continue;
6103 }
6104 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
6105 continue;
6106 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006107 if (canceledNotifications == null) {
6108 canceledNotifications = new ArrayList<>();
6109 }
Julia Reynolds0839c022017-06-15 15:24:01 -04006110 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04006111 mNotificationsByKey.remove(r.getKey());
Julia Reynoldsfd4099d2018-08-21 11:06:06 -04006112 r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006113 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04006114 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006115 }
6116 if (canceledNotifications != null) {
6117 final int M = canceledNotifications.size();
6118 for (int i = 0; i < M; i++) {
6119 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04006120 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006121 }
6122 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006123 }
6124 }
6125
Julia Reynolds50989772017-02-23 14:32:16 -05006126 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006127 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05006128 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05006129 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05006130 return;
6131 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05006132
Julia Reynolds79672302017-01-12 08:30:16 -05006133 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05006134 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
6135 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05006136 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006137 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006138 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006139 }
6140
6141 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
6142 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006143 if (DBG) {
6144 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
6145 }
Julia Reynolds79672302017-01-12 08:30:16 -05006146 mSnoozeHelper.repost(key);
6147 savePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006148 }
6149
Julia Reynolds88860ce2017-06-01 16:55:49 -04006150 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07006151 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04006152 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006153 mHandler.post(new Runnable() {
6154 @Override
6155 public void run() {
6156 synchronized (mNotificationLock) {
6157 String listenerName =
6158 listener == null ? null : listener.component.toShortString();
6159 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
6160 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01006161
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006162 FlagChecker flagChecker = (int flags) -> {
6163 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
6164 != 0) {
6165 return false;
6166 }
6167 return true;
6168 };
6169
6170 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
6171 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
6172 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04006173 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006174 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
6175 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
6176 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04006177 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006178 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00006179 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006180 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006181 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006182 }
6183
Christoph Studere4ef156b2014-07-04 18:41:57 +02006184 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04006185 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02006186 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04006187 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02006188 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02006189 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02006190 return;
6191 }
6192
6193 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02006194
6195 if (pkg == null) {
6196 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
6197 return;
6198 }
6199
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006200 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04006201 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006202 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04006203 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006204 }
6205
Julia Reynolds88860ce2017-06-01 16:55:49 -04006206 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006207 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
6208 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04006209 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006210 final String pkg = parentNotification.sbn.getPackageName();
6211 final int userId = parentNotification.getUserId();
6212 final int reason = REASON_GROUP_SUMMARY_CANCELED;
6213 for (int i = notificationList.size() - 1; i >= 0; i--) {
6214 final NotificationRecord childR = notificationList.get(i);
6215 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04006216 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006217 childR.getGroupKey().equals(parentNotification.getGroupKey())
Julia Reynoldse5c60452018-04-30 14:41:36 -04006218 && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
Beverly40239d92017-07-07 10:20:41 -04006219 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02006220 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
6221 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04006222 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04006223 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04006224 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02006225 }
6226 }
6227 }
6228
Julia Reynolds88860ce2017-06-01 16:55:49 -04006229 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08006230 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006231 {
The Android Open Source Project10592532009-03-18 17:39:46 -07006232 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05006233 NotificationRecord ledNotification = null;
6234 while (ledNotification == null && !mLights.isEmpty()) {
6235 final String owner = mLights.get(mLights.size() - 1);
6236 ledNotification = mNotificationsByKey.get(owner);
6237 if (ledNotification == null) {
6238 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
6239 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006240 }
6241 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006242
Mike Lockwood63b5ad92011-08-30 09:55:30 -04006243 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05006244 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05006245 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07006246 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006247 NotificationRecord.Light light = ledNotification.getLight();
6248 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05006249 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006250 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
6251 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05006252 }
The Android Open Source Project10592532009-03-18 17:39:46 -07006253 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006254 }
6255
Julia Reynolds88860ce2017-06-01 16:55:49 -04006256 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006257 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
6258 String groupKey, int userId) {
6259 List<NotificationRecord> records = new ArrayList<>();
6260 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
6261 records.addAll(
6262 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
6263 return records;
6264 }
6265
6266
Julia Reynolds88860ce2017-06-01 16:55:49 -04006267 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006268 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
6269 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
6270 List<NotificationRecord> records = new ArrayList<>();
6271 final int len = list.size();
6272 for (int i = 0; i < len; i++) {
6273 NotificationRecord r = list.get(i);
6274 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
6275 && r.sbn.getPackageName().equals(pkg)) {
6276 records.add(r);
6277 }
6278 }
6279 return records;
6280 }
6281
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006282 // Searches both enqueued and posted notifications by key.
6283 // TODO: need to combine a bunch of these getters with slightly different behavior.
6284 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04006285 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006286 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006287 NotificationRecord r;
6288 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
6289 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006290 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006291 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
6292 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006293 }
6294 return null;
6295 }
6296
Julia Reynolds88860ce2017-06-01 16:55:49 -04006297 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006298 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006299 NotificationRecord r;
6300 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
6301 return r;
6302 }
6303 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
6304 != null) {
6305 return r;
6306 }
6307 return null;
6308 }
6309
Julia Reynolds88860ce2017-06-01 16:55:49 -04006310 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006311 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006312 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006313 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006314 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006315 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01006316 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
6317 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006318 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006319 }
6320 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006321 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006322 }
6323
Julia Reynolds88860ce2017-06-01 16:55:49 -04006324 @GuardedBy("mNotificationLock")
Julia Reynolds564273f2018-09-13 15:53:11 -04006325 private List<NotificationRecord> findNotificationsByListLocked(
6326 ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) {
6327 List<NotificationRecord> matching = new ArrayList<>();
6328 final int len = list.size();
6329 for (int i = 0; i < len; i++) {
6330 NotificationRecord r = list.get(i);
6331 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
6332 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
6333 matching.add(r);
6334 }
6335 }
6336 return matching;
6337 }
6338
6339 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006340 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04006341 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006342 final int N = list.size();
6343 for (int i = 0; i < N; i++) {
6344 if (key.equals(list.get(i).getKey())) {
6345 return list.get(i);
6346 }
6347 }
6348 return null;
6349 }
6350
Julia Reynolds88860ce2017-06-01 16:55:49 -04006351 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02006352 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02006353 final int N = mNotificationList.size();
6354 for (int i = 0; i < N; i++) {
6355 if (key.equals(mNotificationList.get(i).getKey())) {
6356 return i;
6357 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02006358 }
Christoph Studerc5115552014-06-12 20:22:31 +02006359 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02006360 }
6361
Beverly5a20a5e2018-03-06 15:02:44 -05006362 @VisibleForTesting
6363 protected void hideNotificationsForPackages(String[] pkgs) {
6364 synchronized (mNotificationLock) {
6365 List<String> pkgList = Arrays.asList(pkgs);
6366 List<NotificationRecord> changedNotifications = new ArrayList<>();
6367 int numNotifications = mNotificationList.size();
6368 for (int i = 0; i < numNotifications; i++) {
6369 NotificationRecord rec = mNotificationList.get(i);
6370 if (pkgList.contains(rec.sbn.getPackageName())) {
6371 rec.setHidden(true);
6372 changedNotifications.add(rec);
6373 }
6374 }
6375
6376 mListeners.notifyHiddenLocked(changedNotifications);
6377 }
6378 }
6379
6380 @VisibleForTesting
6381 protected void unhideNotificationsForPackages(String[] pkgs) {
6382 synchronized (mNotificationLock) {
6383 List<String> pkgList = Arrays.asList(pkgs);
6384 List<NotificationRecord> changedNotifications = new ArrayList<>();
6385 int numNotifications = mNotificationList.size();
6386 for (int i = 0; i < numNotifications; i++) {
6387 NotificationRecord rec = mNotificationList.get(i);
6388 if (pkgList.contains(rec.sbn.getPackageName())) {
6389 rec.setHidden(false);
6390 changedNotifications.add(rec);
6391 }
6392 }
6393
6394 mListeners.notifyUnhiddenLocked(changedNotifications);
6395 }
6396 }
6397
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006398 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006399 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006400 updateLightsLocked();
6401 }
6402 }
John Spurlocke677d712014-02-13 12:52:19 -05006403
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006404 protected boolean isCallingUidSystem() {
6405 final int uid = Binder.getCallingUid();
6406 return uid == Process.SYSTEM_UID;
6407 }
6408
6409 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04006410 final int appid = UserHandle.getAppId(uid);
6411 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
6412 }
John Spurlockb408e8e2014-04-23 21:12:45 -04006413
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006414 // TODO: Most calls should probably move to isCallerSystem.
6415 protected boolean isCallerSystemOrPhone() {
6416 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04006417 }
6418
Julia Reynoldsb852e562017-06-06 16:14:18 -04006419 private void checkCallerIsSystemOrShell() {
6420 if (Binder.getCallingUid() == Process.SHELL_UID) {
6421 return;
6422 }
6423 checkCallerIsSystem();
6424 }
6425
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006426 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006427 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006428 return;
6429 }
6430 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
6431 }
6432
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006433 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006434 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006435 return;
6436 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04006437 checkCallerIsSameApp(pkg);
6438 }
6439
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006440 private boolean isCallerAndroid(String callingPkg, int uid) {
6441 return isUidSystemOrPhone(uid) && callingPkg != null
6442 && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg);
6443 }
6444
Brad Stenning8c991ea2018-07-31 13:33:01 -07006445 /**
6446 * Check if the notification is of a category type that is restricted to system use only,
6447 * if so throw SecurityException
6448 */
6449 private void checkRestrictedCategories(final Notification notification) {
6450 try {
6451 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) {
6452 return;
6453 }
6454 } catch (RemoteException re) {
6455 if (DBG) Log.e(TAG, "Unable to confirm if it's safe to skip category "
6456 + "restrictions check thus the check will be done anyway");
6457 }
6458 if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category)
6459 || Notification.CATEGORY_CAR_WARNING.equals(notification.category)
6460 || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) {
6461 checkCallerIsSystem();
6462 }
6463 }
6464
Julia Reynoldsb6634872018-09-25 13:19:53 -04006465 @VisibleForTesting
6466 boolean isCallerInstantApp(String pkg, int callingUid, int userId) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08006467 // System is always allowed to act for ephemeral apps.
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006468 if (isUidSystemOrPhone(callingUid)) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08006469 return false;
6470 }
6471
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006472 mAppOps.checkPackage(callingUid, pkg);
Chad Brubaker6b68f102017-01-27 13:39:00 -08006473
6474 try {
Julia Reynoldsb6634872018-09-25 13:19:53 -04006475 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId);
Chad Brubaker6b68f102017-01-27 13:39:00 -08006476 if (ai == null) {
6477 throw new SecurityException("Unknown package " + pkg);
6478 }
6479 return ai.isInstantApp();
6480 } catch (RemoteException re) {
6481 throw new SecurityException("Unknown package " + pkg, re);
6482 }
6483
6484 }
6485
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006486 private void checkCallerIsSameApp(String pkg) {
Julia Reynoldsb6634872018-09-25 13:19:53 -04006487 checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId());
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006488 }
6489
Julia Reynoldsb6634872018-09-25 13:19:53 -04006490 private void checkCallerIsSameApp(String pkg, int uid, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04006491 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006492 ApplicationInfo ai = mPackageManager.getApplicationInfo(
Julia Reynoldsb6634872018-09-25 13:19:53 -04006493 pkg, 0, userId);
Dan Sandler09afc2e2014-07-18 14:29:20 -04006494 if (ai == null) {
6495 throw new SecurityException("Unknown package " + pkg);
6496 }
John Spurlock7340fc82014-04-24 18:50:12 -04006497 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006498 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04006499 + pkg + " which is owned by uid " + ai.uid);
6500 }
6501 } catch (RemoteException re) {
6502 throw new SecurityException("Unknown package " + pkg + "\n" + re);
6503 }
6504 }
6505
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006506 private boolean isCallerSameApp(String pkg) {
6507 try {
6508 checkCallerIsSameApp(pkg);
6509 return true;
6510 } catch (SecurityException e) {
6511 return false;
6512 }
6513 }
6514
Julia Reynoldsb6634872018-09-25 13:19:53 -04006515 private boolean isCallerSameApp(String pkg, int uid, int userId) {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006516 try {
Julia Reynoldsb6634872018-09-25 13:19:53 -04006517 checkCallerIsSameApp(pkg, uid, userId);
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04006518 return true;
6519 } catch (SecurityException e) {
6520 return false;
6521 }
6522 }
6523
John Spurlock32fe4c62014-10-02 12:16:02 -04006524 private static String callStateToString(int state) {
6525 switch (state) {
6526 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
6527 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
6528 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
6529 default: return "CALL_STATE_UNKNOWN_" + state;
6530 }
6531 }
6532
6533 private void listenForCallState() {
6534 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
6535 @Override
6536 public void onCallStateChanged(int state, String incomingNumber) {
6537 if (mCallState == state) return;
6538 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
6539 mCallState = state;
6540 }
6541 }, PhoneStateListener.LISTEN_CALL_STATE);
6542 }
6543
Christoph Studer05ad4822014-05-16 14:16:03 +02006544 /**
6545 * Generates a NotificationRankingUpdate from 'sbns', considering only
6546 * notifications visible to the given listener.
6547 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006548 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04006549 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04006550 final int N = mNotificationList.size();
6551 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02006552 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05006553 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04006554 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006555 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006556 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05006557 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006558 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05006559 Bundle overridePeople = new Bundle();
6560 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006561 Bundle showBadge = new Bundle();
Julia Reynolds503ed942017-10-04 16:04:56 -04006562 Bundle userSentiment = new Bundle();
Beverly5a20a5e2018-03-06 15:02:44 -05006563 Bundle hidden = new Bundle();
Tony Mak628cb932018-06-19 18:30:41 +01006564 Bundle smartActions = new Bundle();
Tony Makc9acf672018-07-20 13:58:24 +02006565 Bundle smartReplies = new Bundle();
Gus Prevasa3226492018-10-23 11:10:09 -04006566 Bundle audiblyAlerted = new Bundle();
Gus Prevas9abc5062018-10-31 16:11:04 -04006567 Bundle noisy = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04006568 for (int i = 0; i < N; i++) {
6569 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02006570 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006571 continue;
6572 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006573 final String key = record.sbn.getKey();
6574 keys.add(key);
6575 importance.add(record.getImportance());
6576 if (record.getImportanceExplanation() != null) {
6577 explanation.putCharSequence(key, record.getImportanceExplanation());
6578 }
Chris Wren333a61c2014-05-28 16:40:57 -04006579 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006580 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006581
Christoph Studer05ad4822014-05-16 14:16:03 +02006582 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006583 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006584 if (record.getPackageVisibilityOverride()
6585 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006586 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006587 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04006588 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05006589 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05006590 overridePeople.putStringArrayList(key, record.getPeopleOverride());
6591 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05006592 showBadge.putBoolean(key, record.canShowBadge());
Julia Reynolds503ed942017-10-04 16:04:56 -04006593 userSentiment.putInt(key, record.getUserSentiment());
Beverly5a20a5e2018-03-06 15:02:44 -05006594 hidden.putBoolean(key, record.isHidden());
Tony Mak628cb932018-06-19 18:30:41 +01006595 smartActions.putParcelableArrayList(key, record.getSmartActions());
Tony Makc9acf672018-07-20 13:58:24 +02006596 smartReplies.putCharSequenceArrayList(key, record.getSmartReplies());
Gus Prevasa3226492018-10-23 11:10:09 -04006597 audiblyAlerted.putBoolean(key, record.getAudiblyAlerted());
Gus Prevas9abc5062018-10-31 16:11:04 -04006598 noisy.putBoolean(key, record.getSound() != null || record.getVibration() != null);
Christoph Studer05ad4822014-05-16 14:16:03 +02006599 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006600 final int M = keys.size();
6601 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02006602 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05006603 int[] importanceAr = new int[M];
6604 for (int i = 0; i < M; i++) {
6605 importanceAr[i] = importance.get(i);
6606 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006607 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05006608 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Tony Mak628cb932018-06-19 18:30:41 +01006609 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden,
Gus Prevas9abc5062018-10-31 16:11:04 -04006610 smartActions, smartReplies, audiblyAlerted, noisy);
Christoph Studer05ad4822014-05-16 14:16:03 +02006611 }
6612
Julia Reynoldsda781472017-04-12 09:41:16 -04006613 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006614 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04006615 mCompanionManager = getCompanionManager();
6616 }
6617 // Companion mgr doesn't exist on all device types
6618 if (mCompanionManager == null) {
6619 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006620 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006621 long identity = Binder.clearCallingIdentity();
6622 try {
6623 List<String> associations = mCompanionManager.getAssociations(
6624 info.component.getPackageName(), info.userid);
6625 if (!ArrayUtils.isEmpty(associations)) {
6626 return true;
6627 }
6628 } catch (SecurityException se) {
6629 // Not a privileged listener
6630 } catch (RemoteException re) {
6631 Slog.e(TAG, "Cannot reach companion device service", re);
6632 } catch (Exception e) {
6633 Slog.e(TAG, "Cannot verify listener " + info, e);
6634 } finally {
6635 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006636 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006637 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006638 }
6639
Julia Reynolds727a7282017-04-13 10:54:01 -04006640 protected ICompanionDeviceManager getCompanionManager() {
6641 return ICompanionDeviceManager.Stub.asInterface(
6642 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
6643 }
6644
Christoph Studercef37cf2014-07-25 14:18:17 +02006645 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
6646 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
6647 return false;
6648 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07006649 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02006650 return true;
6651 }
6652
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00006653 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Beverly2be7a052018-03-27 11:37:58 -04006654 final long identity = Binder.clearCallingIdentity();
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006655 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006656 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006657 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006658 } catch (RemoteException re) {
6659 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00006660 } catch (IllegalArgumentException ex) {
6661 // Package not found.
6662 return false;
Beverly2be7a052018-03-27 11:37:58 -04006663 } finally {
6664 Binder.restoreCallingIdentity(identity);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006665 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006666 }
6667
Kristian Monsen30f59b22018-04-09 10:27:16 +02006668 @VisibleForTesting
6669 boolean canUseManagedServices(String pkg) {
6670 boolean canUseManagedServices = !mActivityManager.isLowRamDevice()
Julia Reynoldse1816412017-10-24 10:39:11 -04006671 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
Kristian Monsen30f59b22018-04-09 10:27:16 +02006672
6673 for (String whitelisted : getContext().getResources().getStringArray(
6674 R.array.config_allowedManagedServicesOnLowRamDevices)) {
6675 if (whitelisted.equals(pkg)) {
6676 canUseManagedServices = true;
6677 }
6678 }
6679
6680 return canUseManagedServices;
Julia Reynoldse1816412017-10-24 10:39:11 -04006681 }
6682
Chris Wren47633422016-01-22 09:56:59 -05006683 private class TrimCache {
6684 StatusBarNotification heavy;
6685 StatusBarNotification sbnClone;
6686 StatusBarNotification sbnCloneLight;
6687
6688 TrimCache(StatusBarNotification sbn) {
6689 heavy = sbn;
6690 }
6691
6692 StatusBarNotification ForListener(ManagedServiceInfo info) {
6693 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
6694 if (sbnCloneLight == null) {
6695 sbnCloneLight = heavy.cloneLight();
6696 }
6697 return sbnCloneLight;
6698 } else {
6699 if (sbnClone == null) {
6700 sbnClone = heavy.clone();
6701 }
6702 return sbnClone;
6703 }
6704 }
6705 }
6706
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006707 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006708 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05006709
Julia Reynolds7380d872018-01-12 10:28:26 -05006710 public NotificationAssistants(Context context, Object lock, UserProfiles up,
6711 IPackageManager pm) {
6712 super(context, lock, up, pm);
Chris Wren51017d02015-12-15 15:34:46 -05006713 }
6714
6715 @Override
6716 protected Config getConfig() {
6717 Config c = new Config();
Julia Reynolds503ed942017-10-04 16:04:56 -04006718 c.caption = "notification assistant";
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006719 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006720 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006721 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
6722 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05006723 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006724 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05006725 return c;
6726 }
6727
6728 @Override
6729 protected IInterface asInterface(IBinder binder) {
6730 return INotificationListener.Stub.asInterface(binder);
6731 }
6732
6733 @Override
6734 protected boolean checkType(IInterface service) {
6735 return service instanceof INotificationListener;
6736 }
6737
6738 @Override
6739 protected void onServiceAdded(ManagedServiceInfo info) {
6740 mListeners.registerGuestService(info);
6741 }
6742
6743 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006744 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05006745 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
6746 mListeners.unregisterService(removed.service, removed.userid);
6747 }
Chris Wren47633422016-01-22 09:56:59 -05006748
Julia Reynoldsef934fd2018-02-01 14:39:17 -05006749 @Override
6750 public void onUserUnlocked(int user) {
6751 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04006752 // force rebind the assistant, as it might be keeping its own state in user locked
6753 // storage
6754 rebindServices(true, user);
Julia Reynoldsef934fd2018-02-01 14:39:17 -05006755 }
6756
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04006757 protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
6758 // There should be only one, but it's a list, so while we enforce
6759 // singularity elsewhere, we keep it general here, to avoid surprises.
6760 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
6761 ArrayList<String> keys = new ArrayList<>(records.size());
6762 for (NotificationRecord r : records) {
6763 boolean sbnVisible = isVisibleToListener(r.sbn, info)
6764 && info.isSameUser(r.getUserId());
6765 if (sbnVisible) {
6766 keys.add(r.getKey());
6767 }
6768 }
6769
6770 if (!keys.isEmpty()) {
6771 mHandler.post(() -> notifySeen(info, keys));
6772 }
6773 }
6774 }
6775
6776 private void notifySeen(final ManagedServiceInfo info,
6777 final ArrayList<String> keys) {
6778 final INotificationListener assistant = (INotificationListener) info.service;
6779 try {
6780 assistant.onNotificationsSeen(keys);
6781 } catch (RemoteException ex) {
6782 Log.e(TAG, "unable to notify assistant (seen): " + assistant, ex);
6783 }
6784 }
6785
Chris Wren47633422016-01-22 09:56:59 -05006786 public void onNotificationEnqueued(final NotificationRecord r) {
6787 final StatusBarNotification sbn = r.sbn;
6788 TrimCache trimCache = new TrimCache(sbn);
6789
Chris Wren47633422016-01-22 09:56:59 -05006790 // There should be only one, but it's a list, so while we enforce
6791 // singularity elsewhere, we keep it general here, to avoid surprises.
Julia Reynolds00314d92017-04-14 10:01:24 -04006792 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04006793 boolean sbnVisible = isVisibleToListener(sbn, info)
6794 && info.isSameUser(r.getUserId());
Chris Wren47633422016-01-22 09:56:59 -05006795 if (!sbnVisible) {
6796 continue;
6797 }
6798
Chris Wren47633422016-01-22 09:56:59 -05006799 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006800 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05006801 @Override
6802 public void run() {
Julia Reynolds901bf282018-08-14 10:09:36 -04006803 notifyEnqueued(info, sbnToPost, r.getChannel());
Chris Wren47633422016-01-22 09:56:59 -05006804 }
6805 });
6806 }
6807 }
6808
6809 private void notifyEnqueued(final ManagedServiceInfo info,
Julia Reynolds901bf282018-08-14 10:09:36 -04006810 final StatusBarNotification sbn, final NotificationChannel channel) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006811 final INotificationListener assistant = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05006812 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6813 try {
Julia Reynolds901bf282018-08-14 10:09:36 -04006814 assistant.onNotificationEnqueuedWithChannel(sbnHolder, channel);
Chris Wren47633422016-01-22 09:56:59 -05006815 } catch (RemoteException ex) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006816 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Chris Wren47633422016-01-22 09:56:59 -05006817 }
6818 }
6819
Julia Reynolds79672302017-01-12 08:30:16 -05006820 /**
6821 * asynchronously notify the assistant that a notification has been snoozed until a
6822 * context
6823 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006824 @GuardedBy("mNotificationLock")
Julia Reynolds79672302017-01-12 08:30:16 -05006825 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
6826 final String snoozeCriterionId) {
6827 TrimCache trimCache = new TrimCache(sbn);
Julia Reynolds00314d92017-04-14 10:01:24 -04006828 for (final ManagedServiceInfo info : getServices()) {
Julia Reynolds503ed942017-10-04 16:04:56 -04006829 boolean sbnVisible = isVisibleToListener(sbn, info);
6830 if (!sbnVisible) {
6831 continue;
6832 }
Julia Reynolds79672302017-01-12 08:30:16 -05006833 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
6834 mHandler.post(new Runnable() {
6835 @Override
6836 public void run() {
6837 final INotificationListener assistant =
6838 (INotificationListener) info.service;
6839 StatusBarNotificationHolder sbnHolder
6840 = new StatusBarNotificationHolder(sbnToPost);
6841 try {
6842 assistant.onNotificationSnoozedUntilContext(
6843 sbnHolder, snoozeCriterionId);
6844 } catch (RemoteException ex) {
6845 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
6846 }
6847 }
6848 });
6849 }
6850 }
6851
Chris Wren47633422016-01-22 09:56:59 -05006852 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04006853 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05006854 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006855
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04006856 protected void ensureAssistant() {
6857 final List<UserInfo> activeUsers = mUm.getUsers(true);
6858 for (UserInfo userInfo : activeUsers) {
6859 int userId = userInfo.getUserHandle().getIdentifier();
6860 if (getAllowedPackages(userId).isEmpty()) {
6861 Slog.d(TAG, "Approving default notification assistant for user " + userId);
6862 readDefaultAssistant(userId);
6863 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006864 }
6865 }
Chris Wren51017d02015-12-15 15:34:46 -05006866 }
6867
John Spurlock7340fc82014-04-24 18:50:12 -04006868 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006869 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04006870
Christoph Studerb82bc782014-08-20 14:29:43 +02006871 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
6872
Julia Reynoldsb852e562017-06-06 16:14:18 -04006873 public NotificationListeners(IPackageManager pm) {
6874 super(getContext(), mNotificationLock, mUserProfiles, pm);
6875
John Spurlock7340fc82014-04-24 18:50:12 -04006876 }
6877
6878 @Override
Amith Yamasanie5bfeee2018-09-05 18:52:35 -07006879 protected int getBindFlags() {
6880 // Most of the same flags as the base, but also add BIND_ADJUST_BELOW_PERCEPTIBLE
6881 // because too many 3P apps could be kept in memory as notification listeners and
6882 // cause extreme memory pressure.
6883 // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation.
6884 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
6885 | BIND_ADJUST_BELOW_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
6886 }
6887
6888 @Override
John Spurlock7340fc82014-04-24 18:50:12 -04006889 protected Config getConfig() {
6890 Config c = new Config();
6891 c.caption = "notification listener";
6892 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006893 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04006894 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
6895 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
6896 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
6897 c.clientLabel = R.string.notification_listener_binding_label;
6898 return c;
6899 }
6900
6901 @Override
6902 protected IInterface asInterface(IBinder binder) {
6903 return INotificationListener.Stub.asInterface(binder);
6904 }
6905
6906 @Override
Chris Wren51017d02015-12-15 15:34:46 -05006907 protected boolean checkType(IInterface service) {
6908 return service instanceof INotificationListener;
6909 }
6910
6911 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04006912 public void onServiceAdded(ManagedServiceInfo info) {
6913 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04006914 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006915 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04006916 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006917 }
John Spurlock7340fc82014-04-24 18:50:12 -04006918 try {
Chris Wren333a61c2014-05-28 16:40:57 -04006919 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04006920 } catch (RemoteException e) {
6921 // we tried
6922 }
6923 }
6924
John Spurlock1fa865f2014-07-21 14:56:39 -04006925 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006926 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04006927 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07006928 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006929 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01006930 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04006931 }
Christoph Studerb82bc782014-08-20 14:29:43 +02006932 mLightTrimListeners.remove(removed);
6933 }
6934
Julia Reynolds88860ce2017-06-01 16:55:49 -04006935 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02006936 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
6937 if (trim == TRIM_LIGHT) {
6938 mLightTrimListeners.add(info);
6939 } else {
6940 mLightTrimListeners.remove(info);
6941 }
6942 }
6943
6944 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
6945 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04006946 }
6947
John Spurlock7340fc82014-04-24 18:50:12 -04006948 /**
6949 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02006950 *
6951 * <p>
6952 * Also takes care of removing a notification that has been visible to a listener before,
6953 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04006954 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006955 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006956 public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
6957 notifyPostedLocked(r, old, true);
Beverly5a20a5e2018-03-06 15:02:44 -05006958 }
6959
6960 /**
6961 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
6962 * targetting <= O_MR1
6963 */
6964 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006965 private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
Beverly5a20a5e2018-03-06 15:02:44 -05006966 boolean notifyAllListeners) {
Christoph Studerb82bc782014-08-20 14:29:43 +02006967 // Lazily initialized snapshots of the notification.
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006968 StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006969 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Chris Wren47633422016-01-22 09:56:59 -05006970 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02006971
Julia Reynolds00314d92017-04-14 10:01:24 -04006972 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02006973 boolean sbnVisible = isVisibleToListener(sbn, info);
6974 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
6975 // This notification hasn't been and still isn't visible -> ignore.
6976 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006977 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04006978 }
Beverly5a20a5e2018-03-06 15:02:44 -05006979 // If the notification is hidden, don't notifyPosted listeners targeting < P.
6980 // Instead, those listeners will receive notifyPosted when the notification is
6981 // unhidden.
6982 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
6983 continue;
6984 }
6985
6986 // If we shouldn't notify all listeners, this means the hidden state of
6987 // a notification was changed. Don't notifyPosted listeners targeting >= P.
6988 // Instead, those listeners will receive notifyRankingUpdate.
6989 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6990 continue;
6991 }
6992
Chris Wren333a61c2014-05-28 16:40:57 -04006993 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02006994
6995 // This notification became invisible -> remove the old one.
6996 if (oldSbnVisible && !sbnVisible) {
6997 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
6998 mHandler.post(new Runnable() {
6999 @Override
7000 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04007001 notifyRemoved(
7002 info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02007003 }
7004 });
Christoph Studer05ad4822014-05-16 14:16:03 +02007005 continue;
7006 }
Christoph Studercef37cf2014-07-25 14:18:17 +02007007
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007008 // Grant access before listener is notified
7009 final int targetUserId = (info.userid == UserHandle.USER_ALL)
7010 ? UserHandle.USER_SYSTEM : info.userid;
7011 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04007012
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007013 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02007014 mHandler.post(new Runnable() {
7015 @Override
7016 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02007017 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02007018 }
7019 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00007020 }
7021 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00007022
John Spurlock7340fc82014-04-24 18:50:12 -04007023 /**
7024 * asynchronously notify all listeners about a removed notification
7025 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007026 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05007027 public void notifyRemovedLocked(NotificationRecord r, int reason,
Julia Reynolds503ed942017-10-04 16:04:56 -04007028 NotificationStats notificationStats) {
Beverly5a20a5e2018-03-06 15:02:44 -05007029 final StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007030
John Spurlock7340fc82014-04-24 18:50:12 -04007031 // make a copy in case changes are made to the underlying Notification object
7032 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
7033 // notification
7034 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04007035 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02007036 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02007037 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04007038 }
Beverly5a20a5e2018-03-06 15:02:44 -05007039
7040 // don't notifyRemoved for listeners targeting < P
7041 // if not for reason package suspended
7042 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
7043 && info.targetSdkVersion < Build.VERSION_CODES.P) {
7044 continue;
7045 }
7046
7047 // don't notifyRemoved for listeners targeting >= P
7048 // if the reason is package suspended
7049 if (reason == REASON_PACKAGE_SUSPENDED
7050 && info.targetSdkVersion >= Build.VERSION_CODES.P) {
7051 continue;
7052 }
7053
Julia Reynolds503ed942017-10-04 16:04:56 -04007054 // Only assistants can get stats
7055 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
7056 ? notificationStats : null;
Chris Wren333a61c2014-05-28 16:40:57 -04007057 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02007058 mHandler.post(new Runnable() {
7059 @Override
7060 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04007061 notifyRemoved(info, sbnLight, update, stats, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02007062 }
7063 });
Chris Wrenf9536642014-04-17 10:01:54 -04007064 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007065
7066 // Revoke access after all listeners have been updated
7067 mHandler.post(() -> {
7068 updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM);
7069 });
Chris Wrenf9536642014-04-17 10:01:54 -04007070 }
7071
7072 /**
Beverly5a20a5e2018-03-06 15:02:44 -05007073 * Asynchronously notify all listeners about a reordering of notifications
7074 * unless changedHiddenNotifications is populated.
7075 * If changedHiddenNotifications is populated, there was a change in the hidden state
7076 * of the notifications. In this case, we only send updates to listeners that
7077 * target >= P.
Chris Wrenf9536642014-04-17 10:01:54 -04007078 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007079 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05007080 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
7081 boolean isHiddenRankingUpdate = changedHiddenNotifications != null
7082 && changedHiddenNotifications.size() > 0;
7083
Julia Reynolds00314d92017-04-14 10:01:24 -04007084 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02007085 if (!serviceInfo.isEnabledForCurrentProfiles()) {
7086 continue;
7087 }
Beverly5a20a5e2018-03-06 15:02:44 -05007088
7089 boolean notifyThisListener = false;
7090 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
7091 Build.VERSION_CODES.P) {
7092 for (NotificationRecord rec : changedHiddenNotifications) {
7093 if (isVisibleToListener(rec.sbn, serviceInfo)) {
7094 notifyThisListener = true;
7095 break;
7096 }
John Spurlock7340fc82014-04-24 18:50:12 -04007097 }
Beverly5a20a5e2018-03-06 15:02:44 -05007098 }
7099
7100 if (notifyThisListener || !isHiddenRankingUpdate) {
7101 final NotificationRankingUpdate update = makeRankingUpdateLocked(
7102 serviceInfo);
7103
7104 mHandler.post(new Runnable() {
7105 @Override
7106 public void run() {
7107 notifyRankingUpdate(serviceInfo, update);
7108 }
7109 });
7110 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007111 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007112 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007113
Julia Reynolds88860ce2017-06-01 16:55:49 -04007114 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04007115 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04007116 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04007117 if (!serviceInfo.isEnabledForCurrentProfiles()) {
7118 continue;
7119 }
7120 mHandler.post(new Runnable() {
7121 @Override
7122 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04007123 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04007124 }
7125 });
7126 }
7127 }
7128
Beverly5a20a5e2018-03-06 15:02:44 -05007129 /**
7130 * asynchronously notify relevant listeners their notification is hidden
7131 * NotificationListenerServices that target P+:
7132 * NotificationListenerService#notifyRankingUpdateLocked()
7133 * NotificationListenerServices that target <= P:
7134 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
7135 */
7136 @GuardedBy("mNotificationLock")
7137 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
7138 if (changedNotifications == null || changedNotifications.size() == 0) {
7139 return;
7140 }
7141
7142 notifyRankingUpdateLocked(changedNotifications);
7143
7144 // for listeners that target < P, notifyRemoveLocked
7145 int numChangedNotifications = changedNotifications.size();
7146 for (int i = 0; i < numChangedNotifications; i++) {
7147 NotificationRecord rec = changedNotifications.get(i);
7148 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
7149 }
7150 }
7151
7152 /**
7153 * asynchronously notify relevant listeners their notification is unhidden
7154 * NotificationListenerServices that target P+:
7155 * NotificationListenerService#notifyRankingUpdateLocked()
7156 * NotificationListenerServices that target <= P:
7157 * NotificationListeners#notifyPostedLocked()
7158 */
7159 @GuardedBy("mNotificationLock")
7160 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
7161 if (changedNotifications == null || changedNotifications.size() == 0) {
7162 return;
7163 }
7164
7165 notifyRankingUpdateLocked(changedNotifications);
7166
7167 // for listeners that target < P, notifyPostedLocked
7168 int numChangedNotifications = changedNotifications.size();
7169 for (int i = 0; i < numChangedNotifications; i++) {
7170 NotificationRecord rec = changedNotifications.get(i);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007171 mListeners.notifyPostedLocked(rec, rec, false);
Beverly5a20a5e2018-03-06 15:02:44 -05007172 }
7173 }
7174
Christoph Studer85a384b2014-08-27 20:16:15 +02007175 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04007176 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02007177 if (!serviceInfo.isEnabledForCurrentProfiles()) {
7178 continue;
7179 }
7180 mHandler.post(new Runnable() {
7181 @Override
7182 public void run() {
7183 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
7184 }
7185 });
7186 }
7187 }
7188
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007189 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007190 final NotificationChannel channel, final int modificationType) {
7191 if (channel == null) {
7192 return;
7193 }
7194 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04007195 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007196 continue;
7197 }
Julia Reynolds018aa622017-04-20 11:31:30 -04007198
Eugene Suslaa25d17f2017-08-24 11:28:08 -07007199 BackgroundThread.getHandler().post(() -> {
7200 if (hasCompanionDevice(serviceInfo)) {
7201 notifyNotificationChannelChanged(
7202 serviceInfo, pkg, user, channel, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04007203 }
7204 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007205 }
7206 }
7207
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007208 protected void notifyNotificationChannelGroupChanged(
7209 final String pkg, final UserHandle user, final NotificationChannelGroup group,
7210 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007211 if (group == null) {
7212 return;
7213 }
7214 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04007215 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007216 continue;
7217 }
Julia Reynolds018aa622017-04-20 11:31:30 -04007218
Eugene Suslaa25d17f2017-08-24 11:28:08 -07007219 BackgroundThread.getHandler().post(() -> {
7220 if (hasCompanionDevice(serviceInfo)) {
7221 notifyNotificationChannelGroupChanged(
7222 serviceInfo, pkg, user, group, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04007223 }
7224 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007225 }
7226 }
7227
Christoph Studercef37cf2014-07-25 14:18:17 +02007228 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02007229 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04007230 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 {
Griff Hazen84a00ea2014-09-02 17:10:47 -07007233 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04007234 } catch (RemoteException ex) {
7235 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
7236 }
7237 }
7238
Christoph Studercef37cf2014-07-25 14:18:17 +02007239 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds503ed942017-10-04 16:04:56 -04007240 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04007241 if (!info.enabledAndUserMatches(sbn.getUserId())) {
7242 return;
7243 }
Christoph Studer05ad4822014-05-16 14:16:03 +02007244 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007245 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04007246 try {
Julia Reynolds503ed942017-10-04 16:04:56 -04007247 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04007248 } catch (RemoteException ex) {
7249 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04007250 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007251 }
Chris Wrenf9536642014-04-17 10:01:54 -04007252
Christoph Studer05ad4822014-05-16 14:16:03 +02007253 private void notifyRankingUpdate(ManagedServiceInfo info,
7254 NotificationRankingUpdate rankingUpdate) {
7255 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04007256 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02007257 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04007258 } catch (RemoteException ex) {
7259 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
7260 }
7261 }
John Spurlock1fa865f2014-07-21 14:56:39 -04007262
John Spurlockd8afe3c2014-08-01 14:04:07 -04007263 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04007264 final INotificationListener listener = (INotificationListener) info.service;
7265 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04007266 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04007267 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04007268 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04007269 }
7270 }
Justin Koh38156c52014-06-04 13:57:49 -07007271
Christoph Studer85a384b2014-08-27 20:16:15 +02007272 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
7273 int interruptionFilter) {
7274 final INotificationListener listener = (INotificationListener) info.service;
7275 try {
7276 listener.onInterruptionFilterChanged(interruptionFilter);
7277 } catch (RemoteException ex) {
7278 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
7279 }
7280 }
7281
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007282 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007283 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007284 final int modificationType) {
7285 final INotificationListener listener = (INotificationListener) info.service;
7286 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007287 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007288 } catch (RemoteException ex) {
7289 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
7290 }
7291 }
7292
7293 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007294 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007295 final int modificationType) {
7296 final INotificationListener listener = (INotificationListener) info.service;
7297 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04007298 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007299 } catch (RemoteException ex) {
7300 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
7301 }
7302 }
7303
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007304 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07007305 if (packageName == null) {
7306 return false;
7307 }
7308 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007309 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04007310 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07007311 if (packageName.equals(serviceInfo.component.getPackageName())) {
7312 return true;
7313 }
7314 }
7315 }
7316 return false;
7317 }
Kenny Guya263e4e2014-03-03 18:24:03 +00007318 }
John Spurlock25e2d242014-06-27 13:58:23 -04007319
7320 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04007321 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04007322 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04007323 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04007324 public long since;
7325 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04007326 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05007327 public boolean proto = false;
Vishnu Naire3e4d252018-03-01 11:26:57 -08007328 public boolean criticalPriority = false;
7329 public boolean normalPriority = false;
John Spurlock25e2d242014-06-27 13:58:23 -04007330
Kweku Adams887f09c2017-11-13 17:12:20 -08007331 @NonNull
John Spurlock25e2d242014-06-27 13:58:23 -04007332 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04007333 final DumpFilter filter = new DumpFilter();
7334 for (int ai = 0; ai < args.length; ai++) {
7335 final String a = args[ai];
Kweku Adams62b42242017-09-25 12:54:02 -07007336 if ("--proto".equals(a)) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05007337 filter.proto = true;
Kweku Adams62b42242017-09-25 12:54:02 -07007338 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
Dan Sandlera1770312015-07-10 13:59:29 -04007339 filter.redact = false;
7340 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
7341 if (ai < args.length-1) {
7342 ai++;
7343 filter.pkgFilter = args[ai].trim().toLowerCase();
7344 if (filter.pkgFilter.isEmpty()) {
7345 filter.pkgFilter = null;
7346 } else {
7347 filter.filtered = true;
7348 }
7349 }
7350 } else if ("--zen".equals(a) || "zen".equals(a)) {
7351 filter.filtered = true;
7352 filter.zen = true;
7353 } else if ("--stats".equals(a)) {
7354 filter.stats = true;
7355 if (ai < args.length-1) {
7356 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01007357 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04007358 } else {
7359 filter.since = 0;
7360 }
Vishnu Naire3e4d252018-03-01 11:26:57 -08007361 } else if (PRIORITY_ARG.equals(a)) {
7362 // Bugreport will call the service twice with priority arguments, first to dump
7363 // critical sections and then non critical ones. Set approriate filters
7364 // to generate the desired data.
7365 if (ai < args.length - 1) {
7366 ai++;
7367 switch (args[ai]) {
7368 case PRIORITY_ARG_CRITICAL:
7369 filter.criticalPriority = true;
7370 break;
7371 case PRIORITY_ARG_NORMAL:
7372 filter.normalPriority = true;
7373 break;
7374 }
7375 }
Dan Sandlera1770312015-07-10 13:59:29 -04007376 }
John Spurlock25e2d242014-06-27 13:58:23 -04007377 }
Dan Sandlera1770312015-07-10 13:59:29 -04007378 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04007379 }
7380
7381 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04007382 if (!filtered) return true;
7383 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04007384 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04007385 }
7386
7387 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04007388 if (!filtered) return true;
7389 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04007390 }
7391
7392 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04007393 if (!filtered) return true;
7394 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04007395 }
7396
7397 @Override
7398 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04007399 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04007400 }
7401 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07007402
Beverly5a20a5e2018-03-06 15:02:44 -05007403 @VisibleForTesting
7404 protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
7405 // only use for testing: mimic receive broadcast that package is (un)suspended
7406 // but does not actually (un)suspend the package
7407 final Bundle extras = new Bundle();
7408 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
7409 new String[]{pkg});
7410
7411 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
Beverly3c707b42018-09-14 09:49:07 -04007412 : Intent.ACTION_PACKAGES_UNSUSPENDED;
Beverly5a20a5e2018-03-06 15:02:44 -05007413 final Intent intent = new Intent(action);
7414 intent.putExtras(extras);
7415
7416 mPackageIntentReceiver.onReceive(getContext(), intent);
7417 }
7418
Griff Hazen84a00ea2014-09-02 17:10:47 -07007419 /**
7420 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
7421 * binder without sending large amounts of data over a oneway transaction.
7422 */
7423 private static final class StatusBarNotificationHolder
7424 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07007425 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007426
7427 public StatusBarNotificationHolder(StatusBarNotification value) {
7428 mValue = value;
7429 }
7430
Griff Hazene9aac5f2014-09-05 20:04:09 -07007431 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07007432 @Override
7433 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07007434 StatusBarNotification value = mValue;
7435 mValue = null;
7436 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007437 }
7438 }
John Spurlock7c74f782015-06-04 13:01:42 -04007439
Julia Reynoldsb852e562017-06-06 16:14:18 -04007440 private class ShellCmd extends ShellCommand {
7441 public static final String USAGE = "help\n"
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007442 + "allow_listener COMPONENT [user_id]\n"
7443 + "disallow_listener COMPONENT [user_id]\n"
Julia Reynolds7380d872018-01-12 10:28:26 -05007444 + "allow_assistant COMPONENT\n"
Julia Reynoldseb3dca72017-07-11 10:39:58 -04007445 + "remove_assistant COMPONENT\n"
Julia Reynoldsb852e562017-06-06 16:14:18 -04007446 + "allow_dnd PACKAGE\n"
Beverly5a20a5e2018-03-06 15:02:44 -05007447 + "disallow_dnd PACKAGE\n"
7448 + "suspend_package PACKAGE\n"
7449 + "unsuspend_package PACKAGE";
John Spurlock7c74f782015-06-04 13:01:42 -04007450
Julia Reynoldsb852e562017-06-06 16:14:18 -04007451 @Override
7452 public int onCommand(String cmd) {
Felipe Leme68d80412017-07-14 11:18:08 -07007453 if (cmd == null) {
7454 return handleDefaultCommands(cmd);
7455 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007456 final PrintWriter pw = getOutPrintWriter();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04007457 try {
Julia Reynoldsb852e562017-06-06 16:14:18 -04007458 switch (cmd) {
7459 case "allow_dnd": {
7460 getBinderService().setNotificationPolicyAccessGranted(
7461 getNextArgRequired(), true);
John Spurlock7c74f782015-06-04 13:01:42 -04007462 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04007463 break;
7464
7465 case "disallow_dnd": {
7466 getBinderService().setNotificationPolicyAccessGranted(
7467 getNextArgRequired(), false);
7468 }
7469 break;
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007470 case "allow_listener": {
7471 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7472 if (cn == null) {
7473 pw.println("Invalid listener - must be a ComponentName");
7474 return -1;
7475 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007476 String userId = getNextArg();
7477 if (userId == null) {
7478 getBinderService().setNotificationListenerAccessGranted(cn, true);
7479 } else {
7480 getBinderService().setNotificationListenerAccessGrantedForUser(
7481 cn, Integer.parseInt(userId), true);
7482 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007483 }
7484 break;
7485 case "disallow_listener": {
7486 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7487 if (cn == null) {
7488 pw.println("Invalid listener - must be a ComponentName");
7489 return -1;
7490 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007491 String userId = getNextArg();
7492 if (userId == null) {
7493 getBinderService().setNotificationListenerAccessGranted(cn, false);
7494 } else {
7495 getBinderService().setNotificationListenerAccessGrantedForUser(
7496 cn, Integer.parseInt(userId), false);
7497 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007498 }
7499 break;
Julia Reynoldseb3dca72017-07-11 10:39:58 -04007500 case "allow_assistant": {
7501 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7502 if (cn == null) {
7503 pw.println("Invalid assistant - must be a ComponentName");
7504 return -1;
7505 }
7506 getBinderService().setNotificationAssistantAccessGranted(cn, true);
7507 }
7508 break;
7509 case "disallow_assistant": {
7510 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7511 if (cn == null) {
7512 pw.println("Invalid assistant - must be a ComponentName");
7513 return -1;
7514 }
7515 getBinderService().setNotificationAssistantAccessGranted(cn, false);
7516 }
7517 break;
Beverly5a20a5e2018-03-06 15:02:44 -05007518 case "suspend_package": {
7519 // only use for testing
7520 simulatePackageSuspendBroadcast(true, getNextArgRequired());
7521 }
7522 break;
7523 case "unsuspend_package": {
7524 // only use for testing
7525 simulatePackageSuspendBroadcast(false, getNextArgRequired());
7526 }
7527 break;
Julia Reynoldsb852e562017-06-06 16:14:18 -04007528 default:
7529 return handleDefaultCommands(cmd);
John Spurlock7c74f782015-06-04 13:01:42 -04007530 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007531 } catch (Exception e) {
7532 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
Julia Reynoldsb852e562017-06-06 16:14:18 -04007533 Slog.e(TAG, "Error running shell command", e);
John Spurlock7c74f782015-06-04 13:01:42 -04007534 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04007535 return 0;
John Spurlock7c74f782015-06-04 13:01:42 -04007536 }
7537
Julia Reynoldsb852e562017-06-06 16:14:18 -04007538 @Override
7539 public void onHelp() {
7540 getOutPrintWriter().println(USAGE);
John Spurlock7c74f782015-06-04 13:01:42 -04007541 }
7542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007543}