blob: 0897b8a52ad6ac22936d49610858528e4daffbe9 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Adam Lesinski182f73f2013-12-05 16:48:06 -080017package com.android.server.notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Julia Reynoldse5c60452018-04-30 14:41:36 -040019import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
Julia Reynoldsfc9767b2018-01-22 17:45:16 -050020import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050021import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
22import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
Julia Reynolds8617e4e2017-09-18 16:52:37 -040023import static android.app.NotificationManager.IMPORTANCE_LOW;
Julia Reynolds7c96b582017-05-25 12:35:36 -040024import static android.app.NotificationManager.IMPORTANCE_MIN;
Julia Reynolds85769912016-10-25 09:08:57 -040025import static android.app.NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -050026import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
27import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
28import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
29import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
30import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
31import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
32import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
33import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
34import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
35import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -050036import static android.content.pm.PackageManager.FEATURE_LEANBACK;
37import static android.content.pm.PackageManager.FEATURE_TELEVISION;
Julia Reynolds4db59552017-06-30 13:34:01 -040038import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Vishnu Naire3e4d252018-03-01 11:26:57 -080039import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
40import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
Julia Reynolds88a879f2017-07-26 17:06:46 -040041import static android.os.UserHandle.USER_NULL;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040042import static android.os.UserHandle.USER_SYSTEM;
Julia Reynolds73ed76b2017-04-04 17:04:38 -040043import static android.service.notification.NotificationListenerService
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050044 .HINT_HOST_DISABLE_CALL_EFFECTS;
45import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
46import static android.service.notification.NotificationListenerService
47 .HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
48import static android.service.notification.NotificationListenerService
Julia Reynolds73ed76b2017-04-04 17:04:38 -040049 .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
50import static android.service.notification.NotificationListenerService
51 .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
52import static android.service.notification.NotificationListenerService
53 .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050054import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
55import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040056import static android.service.notification.NotificationListenerService.REASON_CANCEL;
57import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050058import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040059import static android.service.notification.NotificationListenerService.REASON_CLICK;
60import static android.service.notification.NotificationListenerService.REASON_ERROR;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050061import static android.service.notification.NotificationListenerService
62 .REASON_GROUP_SUMMARY_CANCELED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050063import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
64import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
65import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
66import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
67import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
68import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
69import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
Julia Reynolds2a128742016-11-28 14:29:25 -050070import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050071import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
72import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
Christoph Studerb82bc782014-08-20 14:29:43 +020073import static android.service.notification.NotificationListenerService.TRIM_FULL;
74import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
Wale Ogunwaleac2561e2016-11-01 15:43:46 -070075import static android.view.Display.DEFAULT_DISPLAY;
76import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
svetoslavganov75986cf2009-05-14 22:28:01 -070077
Vishnu Naire3e4d252018-03-01 11:26:57 -080078import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
79import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
80import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
81
Chris Wren51017d02015-12-15 15:34:46 -050082import android.Manifest;
Julia Reynoldsa78cdff2017-04-26 10:19:25 -040083import android.annotation.NonNull;
Wei Liu97e56662016-03-04 10:52:33 -080084import android.annotation.Nullable;
Dianne Hackborn41203752012-08-31 14:05:51 -070085import android.app.ActivityManager;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070086import android.app.ActivityManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -050087import android.app.AlarmManager;
John Spurlock7340fc82014-04-24 18:50:12 -040088import android.app.AppGlobals;
Daniel Sandler4a900ac2013-01-30 14:04:10 -050089import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040090import android.app.AutomaticZenRule;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.app.IActivityManager;
92import android.app.INotificationManager;
93import android.app.ITransientNotification;
94import android.app.Notification;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040095import android.app.NotificationChannel;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050096import android.app.NotificationChannelGroup;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -050097import android.app.NotificationManager;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050098import android.app.NotificationManager.Policy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099import android.app.PendingIntent;
100import android.app.StatusBarManager;
Jason Parks50322ff2018-03-27 10:23:33 -0500101import android.app.admin.DeviceAdminInfo;
102import android.app.admin.DevicePolicyManagerInternal;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500103import android.app.backup.BackupManager;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700104import android.app.usage.UsageEvents;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700105import android.app.usage.UsageStatsManagerInternal;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400106import android.companion.ICompanionDeviceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107import android.content.BroadcastReceiver;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700108import android.content.ComponentName;
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400109import android.content.ContentProvider;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700110import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111import android.content.Context;
112import android.content.Intent;
113import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -0400114import android.content.pm.ApplicationInfo;
Kenny Guy70058402014-10-28 20:45:06 +0000115import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116import android.content.pm.PackageManager;
117import android.content.pm.PackageManager.NameNotFoundException;
Christoph Studercee44ba2014-05-20 18:36:43 +0200118import android.content.pm.ParceledListSlice;
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400119import android.content.pm.UserInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700121import android.database.ContentObserver;
Beverly5d463b62017-07-26 14:13:40 -0400122import android.media.AudioAttributes;
svetoslavganov75986cf2009-05-14 22:28:01 -0700123import android.media.AudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500124import android.media.AudioManagerInternal;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700125import android.media.IRingtonePlayer;
Kenny Guy23991102018-04-05 21:18:38 +0100126import android.metrics.LogMaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128import android.os.Binder;
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -0400129import android.os.Build;
John Spurlock2b122f42014-08-27 16:29:47 -0400130import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -0400131import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132import android.os.Handler;
Chris Wrenf9536642014-04-17 10:01:54 -0400133import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134import android.os.IBinder;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800135import android.os.IDeviceIdleController;
John Spurlock7340fc82014-04-24 18:50:12 -0400136import android.os.IInterface;
Chris Wrenf9536642014-04-17 10:01:54 -0400137import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700139import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -0700140import android.os.RemoteException;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400141import android.os.ResultReceiver;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400142import android.os.ServiceManager;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400143import android.os.ShellCallback;
144import android.os.ShellCommand;
Chris Wrenc8673a82016-05-17 17:11:29 -0400145import android.os.SystemClock;
Selim Cinekb5605e52015-02-20 18:21:41 +0100146import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700147import android.os.UserHandle;
Michael Wright71216972017-01-31 18:33:54 +0000148import android.os.VibrationEffect;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500149import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150import android.provider.Settings;
Julia Reynoldse46bb372016-03-17 11:05:58 -0400151import android.service.notification.Adjustment;
Chris Wren333a61c2014-05-28 16:40:57 -0400152import android.service.notification.Condition;
John Spurlock7340fc82014-04-24 18:50:12 -0400153import android.service.notification.IConditionProvider;
Chris Wren333a61c2014-05-28 16:40:57 -0400154import android.service.notification.INotificationListener;
Griff Hazen84a00ea2014-09-02 17:10:47 -0700155import android.service.notification.IStatusBarNotificationHolder;
Kweku Adams93304b62017-09-20 17:03:00 -0700156import android.service.notification.ListenersDisablingEffectsProto;
Julia Reynolds77b2cc92016-11-08 14:41:09 -0500157import android.service.notification.NotificationAssistantService;
John Spurlock7340fc82014-04-24 18:50:12 -0400158import android.service.notification.NotificationListenerService;
Christoph Studer05ad4822014-05-16 14:16:03 +0200159import android.service.notification.NotificationRankingUpdate;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500160import android.service.notification.NotificationRecordProto;
161import android.service.notification.NotificationServiceDumpProto;
Julia Reynolds503ed942017-10-04 16:04:56 -0400162import android.service.notification.NotificationStats;
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500163import android.service.notification.NotifyingApp;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500164import android.service.notification.SnoozeCriterion;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700165import android.service.notification.StatusBarNotification;
John Spurlock056c5192014-04-20 21:52:01 -0400166import android.service.notification.ZenModeConfig;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500167import android.service.notification.ZenModeProto;
John Spurlock32fe4c62014-10-02 12:16:02 -0400168import android.telephony.PhoneStateListener;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500169import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -0700170import android.text.TextUtils;
John Spurlocka4294292014-03-24 18:02:32 -0400171import android.util.ArrayMap;
John Spurlock1fa865f2014-07-21 14:56:39 -0400172import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700173import android.util.AtomicFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -0800175import android.util.Slog;
Bryce Lee7219ada2016-04-08 10:54:23 -0700176import android.util.SparseArray;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400177import android.util.Xml;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500178import android.util.proto.ProtoOutputStream;
svetoslavganov75986cf2009-05-14 22:28:01 -0700179import android.view.accessibility.AccessibilityEvent;
180import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181import android.widget.Toast;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000182
Scott Greenwald9a05b312013-06-28 00:37:54 -0400183import com.android.internal.R;
Julia Reynolds88860ce2017-06-01 16:55:49 -0400184import com.android.internal.annotations.GuardedBy;
Chris Wren93bb8b82016-03-29 14:35:05 -0400185import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -0500186import com.android.internal.logging.MetricsLogger;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500187import com.android.internal.logging.nano.MetricsProto;
Chris Wren9eb5e102017-01-26 13:15:06 -0500188import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Beverly70dcd002018-03-29 17:09:16 -0400189import com.android.internal.notification.SystemNotificationChannels;
Eugene Suslaa25d17f2017-08-24 11:28:08 -0700190import com.android.internal.os.BackgroundThread;
Chris Wrend1dbc922015-06-19 17:51:16 -0400191import com.android.internal.statusbar.NotificationVisibility;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400192import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600193import com.android.internal.util.DumpUtils;
John Spurlock056c5192014-04-20 21:52:01 -0400194import com.android.internal.util.FastXmlSerializer;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400195import com.android.internal.util.Preconditions;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400196import com.android.internal.util.XmlUtils;
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700197import com.android.server.DeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800198import com.android.server.EventLogTags;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700199import com.android.server.LocalServices;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800200import com.android.server.SystemService;
201import com.android.server.lights.Light;
202import com.android.server.lights.LightsManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400203import com.android.server.notification.ManagedServices.ManagedServiceInfo;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500204import com.android.server.notification.ManagedServices.UserProfiles;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700205import com.android.server.policy.PhoneWindowManager;
John Spurlockb408e8e2014-04-23 21:12:45 -0400206import com.android.server.statusbar.StatusBarManagerInternal;
Adrian Roose99bc052017-11-20 17:55:31 +0100207import com.android.server.wm.WindowManagerInternal;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800208
John Spurlockb408e8e2014-04-23 21:12:45 -0400209import libcore.io.IoUtils;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000210
Chris Wrene4b38802015-07-07 15:54:19 -0400211import org.json.JSONException;
212import org.json.JSONObject;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700213import org.xmlpull.v1.XmlPullParser;
214import org.xmlpull.v1.XmlPullParserException;
John Spurlock056c5192014-04-20 21:52:01 -0400215import org.xmlpull.v1.XmlSerializer;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700216
John Spurlock35ef0a62015-05-28 11:24:10 -0400217import java.io.ByteArrayInputStream;
218import java.io.ByteArrayOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400219import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400221import java.io.FileNotFoundException;
John Spurlock056c5192014-04-20 21:52:01 -0400222import java.io.FileOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400223import java.io.IOException;
John Spurlock35ef0a62015-05-28 11:24:10 -0400224import java.io.InputStream;
225import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100227import java.nio.charset.StandardCharsets;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500228import java.util.ArrayDeque;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229import java.util.ArrayList;
Michael Wrightbc4d0d92017-03-23 18:57:57 +0000230import java.util.Arrays;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500231import java.util.Iterator;
John Spurlock7c74f782015-06-04 13:01:42 -0400232import java.util.List;
Christoph Studer265c1052014-07-23 17:14:33 +0200233import java.util.Map.Entry;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500234import java.util.Objects;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400235import java.util.Set;
Chris Wren51017d02015-12-15 15:34:46 -0500236import java.util.concurrent.TimeUnit;
Kristian Monsen30f59b22018-04-09 10:27:16 +0200237import java.util.function.Predicate;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400238
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400239/** {@hide} */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800240public class NotificationManagerService extends SystemService {
241 static final String TAG = "NotificationService";
Christoph Studer1f32c652014-11-26 15:32:20 +0100242 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Selim Cinek40412492015-12-08 18:03:22 -0800243 public static final boolean ENABLE_CHILD_NOTIFICATIONS
244 = SystemProperties.getBoolean("debug.child_notifs", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245
Dan Sandler7d67bd42018-05-15 14:06:38 -0400246 static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
247 "debug.notification.interruptiveness", false);
248
Adam Lesinski182f73f2013-12-05 16:48:06 -0800249 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
Julia Reynolds6ad0aec2017-07-05 08:47:03 -0400250 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
Joe Onoratobd73d012010-06-04 11:44:54 -0700251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 // message codes
Robert Carr997427342018-02-28 18:06:10 -0800253 static final int MESSAGE_DURATION_REACHED = 2;
John Spurlock056c5192014-04-20 21:52:01 -0400254 static final int MESSAGE_SAVE_POLICY_FILE = 3;
Chris Wren51017d02015-12-15 15:34:46 -0500255 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
256 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
257 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
Robert Carr997427342018-02-28 18:06:10 -0800258 static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
Chris Wren51017d02015-12-15 15:34:46 -0500259
260 // ranking thread messages
261 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
262 private static final int MESSAGE_RANKING_SORT = 1001;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700264 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800265 static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800266
Robert Carr3406d462018-03-15 16:19:07 -0700267 // 1 second past the ANR timeout.
268 static final int FINISH_TOKEN_TIMEOUT = 11 * 1000;
269
Adam Lesinski182f73f2013-12-05 16:48:06 -0800270 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
Christoph Studer265c1052014-07-23 17:14:33 +0200271
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500272 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
273
Adam Lesinski182f73f2013-12-05 16:48:06 -0800274 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275
Adam Lesinski182f73f2013-12-05 16:48:06 -0800276 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler526fa0e2012-12-04 14:51:50 -0500277
Adam Lesinski182f73f2013-12-05 16:48:06 -0800278 static final boolean ENABLE_BLOCKED_TOASTS = true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400279
Christoph Studer12aeda82014-09-23 19:08:56 +0200280 // When #matchesCallFilter is called from the ringer, wait at most
281 // 3s to resolve the contacts. This timeout is required since
282 // ContactsProvider might take a long time to start up.
283 //
284 // Return STARRED_CONTACT when the timeout is hit in order to avoid
285 // missed calls in ZEN mode "Important".
286 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
287 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
288 ValidateNotificationPeople.STARRED_CONTACT;
289
Christoph Studer265c1052014-07-23 17:14:33 +0200290 /** notification_enqueue status value for a newly enqueued notification. */
291 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
292
293 /** notification_enqueue status value for an existing notification. */
294 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
295
296 /** notification_enqueue status value for an ignored notification. */
297 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
Chris Wrenc8673a82016-05-17 17:11:29 -0400298 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
Christoph Studer265c1052014-07-23 17:14:33 +0200299
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500300 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
301
Julia Reynolds2a128742016-11-28 14:29:25 -0500302 private static final String ACTION_NOTIFICATION_TIMEOUT =
303 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
304 private static final int REQUEST_CODE_TIMEOUT = 1;
305 private static final String SCHEME_TIMEOUT = "timeout";
306 private static final String EXTRA_KEY = "key";
307
Adam Lesinski182f73f2013-12-05 16:48:06 -0800308 private IActivityManager mAm;
Julia Reynolds68263d12017-06-21 14:21:19 -0400309 private ActivityManager mActivityManager;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500310 private IPackageManager mPackageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500311 private PackageManager mPackageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800312 AudioManager mAudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500313 AudioManagerInternal mAudioManagerInternal;
Wei Liu97e56662016-03-04 10:52:33 -0800314 @Nullable StatusBarManagerInternal mStatusBar;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800315 Vibrator mVibrator;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700316 private WindowManagerInternal mWindowManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -0500317 private AlarmManager mAlarmManager;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400318 private ICompanionDeviceManager mCompanionManager;
Julia Reynolds94187562017-10-10 13:58:49 -0400319 private AccessibilityManager mAccessibilityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800320 private IDeviceIdleController mDeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 final IBinder mForegroundToken = new Binder();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400323 private WorkerHandler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400324 private final HandlerThread mRankingThread = new HandlerThread("ranker",
325 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326
Adam Lesinski182f73f2013-12-05 16:48:06 -0800327 private Light mNotificationLight;
328 Light mAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800329
Daniel Sandleredbb3802012-11-13 20:49:47 -0800330 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400331 private boolean mUseAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800332 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800333
John Spurlockd8afe3c2014-08-01 14:04:07 -0400334 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400335 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500336 private String mSoundNotificationKey;
337 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338
Bryce Lee7219ada2016-04-08 10:54:23 -0700339 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400340 new SparseArray<>();
341 private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400342 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500343 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400344
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500345 // for enabling and disabling notification pulse behavior
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400346 private boolean mScreenOn = true;
Beverly5d463b62017-07-26 14:13:40 -0400347 protected boolean mInCall = false;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500348 private boolean mNotificationPulseEnabled;
349
Beverly5d463b62017-07-26 14:13:40 -0400350 private Uri mInCallNotificationUri;
351 private AudioAttributes mInCallNotificationAudioAttributes;
352 private float mInCallNotificationVolume;
luochaojiang50e5273c2018-04-16 16:55:03 +0800353 private Binder mCallNotificationToken = null;
Marta Białka39c992f2011-03-10 10:27:24 +0100354
Daniel Sandler09a247e2013-02-14 10:24:17 -0500355 // used as a mutex for access to all active notifications & listeners
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500356 final Object mNotificationLock = new Object();
Julia Reynolds0839c022017-06-15 15:24:01 -0400357 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400358 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400359 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400360 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400361 @GuardedBy("mNotificationLock")
Chris Wren6676dab2016-12-21 18:26:27 -0500362 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400363 @GuardedBy("mNotificationLock")
Julia Reynoldseae43fb2016-05-09 12:42:58 -0400364 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400365 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
Christoph Studer265c1052014-07-23 17:14:33 +0200366 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500367 final ArrayMap<Integer, ArrayList<NotifyingApp>> mRecentApps = new ArrayMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368
Chris Wren6054e612014-11-25 17:16:46 -0500369 // The last key in this list owns the hardware.
370 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700371
Adam Lesinski182f73f2013-12-05 16:48:06 -0800372 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700373 private UsageStatsManagerInternal mAppUsageStats;
Jason Parks50322ff2018-03-27 10:23:33 -0500374 private DevicePolicyManagerInternal mDpm;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500375
Griff Hazen9f637d12014-06-10 11:13:51 -0700376 private Archive mArchive;
377
John Spurlock21258a32015-05-27 18:22:55 -0400378 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400379 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400380
Daniel Sandler0da673f2012-04-11 12:33:16 -0400381 private static final int DB_VERSION = 1;
382
John Spurlock21258a32015-05-27 18:22:55 -0400383 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400384 private static final String ATTR_VERSION = "version";
385
Chris Wren54bbef42014-07-09 18:37:56 -0400386 private RankingHelper mRankingHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400387
John Spurlockb408e8e2014-04-23 21:12:45 -0400388 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400389 private NotificationListeners mListeners;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400390 private NotificationAssistants mAssistants;
John Spurlock7340fc82014-04-24 18:50:12 -0400391 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200392 private NotificationUsageStats mUsageStats;
Christoph Studer546bec82014-03-14 12:17:12 +0100393
John Spurlocke6a7d932014-03-13 12:29:00 -0400394 private static final int MY_UID = Process.myUid();
395 private static final int MY_PID = Process.myPid();
Dianne Hackborn98305522017-05-05 17:53:53 -0700396 private static final IBinder WHITELIST_TOKEN = new Binder();
Chris Wren51017d02015-12-15 15:34:46 -0500397 private RankingHandler mRankingHandler;
Chris Wrenc8673a82016-05-17 17:11:29 -0400398 private long mLastOverRateLogTime;
Chris Wren763a9bb2016-05-31 17:14:12 -0400399 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
John Spurlocke6a7d932014-03-13 12:29:00 -0400400
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400401 private SnoozeHelper mSnoozeHelper;
Julia Reynolds8f488d32016-10-14 10:59:01 -0400402 private GroupHelper mGroupHelper;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -0500403 private boolean mIsTelevision;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400404
Kenny Guy23991102018-04-05 21:18:38 +0100405 private MetricsLogger mMetricsLogger;
Kristian Monsen30f59b22018-04-09 10:27:16 +0200406 private Predicate<String> mAllowedManagedServicePackages;
Kenny Guy23991102018-04-05 21:18:38 +0100407
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500408 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700409 final int mBufferSize;
410 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500411
Griff Hazen9f637d12014-06-10 11:13:51 -0700412 public Archive(int size) {
413 mBufferSize = size;
414 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500415 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700416
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400417 public String toString() {
418 final StringBuilder sb = new StringBuilder();
419 final int N = mBuffer.size();
420 sb.append("Archive (");
421 sb.append(N);
422 sb.append(" notification");
423 sb.append((N==1)?")":"s)");
424 return sb.toString();
425 }
426
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500427 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700428 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500429 mBuffer.removeFirst();
430 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400431
432 // We don't want to store the heavy bits of the notification in the archive,
433 // but other clients in the system process might be using the object, so we
434 // store a (lightened) copy.
435 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500436 }
437
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500438 public Iterator<StatusBarNotification> descendingIterator() {
439 return mBuffer.descendingIterator();
440 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500441
442 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700443 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500444 final StatusBarNotification[] a
445 = new StatusBarNotification[Math.min(count, mBuffer.size())];
446 Iterator<StatusBarNotification> iter = descendingIterator();
447 int i=0;
448 while (iter.hasNext() && i < count) {
449 a[i++] = iter.next();
450 }
451 return a;
452 }
453
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500454 }
455
Julia Reynolds88a879f2017-07-26 17:06:46 -0400456 protected void readDefaultApprovedServices(int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400457 String defaultListenerAccess = getContext().getResources().getString(
458 com.android.internal.R.string.config_defaultListenerAccessPackages);
459 if (defaultListenerAccess != null) {
460 for (String whitelisted :
461 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
462 // Gather all notification listener components for candidate pkgs.
463 Set<ComponentName> approvedListeners =
464 mListeners.queryPackageForServices(whitelisted,
465 PackageManager.MATCH_DIRECT_BOOT_AWARE
466 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
467 for (ComponentName cn : approvedListeners) {
468 try {
469 getBinderService().setNotificationListenerAccessGrantedForUser(cn,
470 userId, true);
471 } catch (RemoteException e) {
472 e.printStackTrace();
473 }
474 }
475 }
476 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500477
Julia Reynoldsb852e562017-06-06 16:14:18 -0400478 String defaultDndAccess = getContext().getResources().getString(
479 com.android.internal.R.string.config_defaultDndAccessPackages);
480 if (defaultListenerAccess != null) {
481 for (String whitelisted :
482 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
483 try {
484 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
485 } catch (RemoteException e) {
486 e.printStackTrace();
487 }
488 }
489 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500490
491 readDefaultAssistant(userId);
492 }
493
494 protected void readDefaultAssistant(int userId) {
495 String defaultAssistantAccess = getContext().getResources().getString(
496 com.android.internal.R.string.config_defaultAssistantAccessPackage);
497 if (defaultAssistantAccess != null) {
498 // Gather all notification assistant components for candidate pkg. There should
499 // only be one
500 Set<ComponentName> approvedAssistants =
501 mAssistants.queryPackageForServices(defaultAssistantAccess,
502 PackageManager.MATCH_DIRECT_BOOT_AWARE
503 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
504 for (ComponentName cn : approvedAssistants) {
505 try {
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400506 getBinderService().setNotificationAssistantAccessGrantedForUser(
507 cn, userId, true);
Julia Reynolds7380d872018-01-12 10:28:26 -0500508 } catch (RemoteException e) {
509 e.printStackTrace();
510 }
511 }
512 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400513 }
514
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400515 void readPolicyXml(InputStream stream, boolean forRestore)
John Spurlock35ef0a62015-05-28 11:24:10 -0400516 throws XmlPullParserException, NumberFormatException, IOException {
517 final XmlPullParser parser = Xml.newPullParser();
518 parser.setInput(stream, StandardCharsets.UTF_8.name());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400519 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
520 boolean migratedManagedServices = false;
521 int outerDepth = parser.getDepth();
522 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
523 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
524 mZenModeHelper.readXml(parser, forRestore);
525 } else if (RankingHelper.TAG_RANKING.equals(parser.getName())){
526 mRankingHelper.readXml(parser, forRestore);
527 }
Kristian Monsen30f59b22018-04-09 10:27:16 +0200528 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
529 mListeners.readXml(parser, mAllowedManagedServicePackages);
530 migratedManagedServices = true;
531 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
532 mAssistants.readXml(parser, mAllowedManagedServicePackages);
533 migratedManagedServices = true;
534 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
535 mConditionProviders.readXml(parser, mAllowedManagedServicePackages);
536 migratedManagedServices = true;
Julia Reynolds68263d12017-06-21 14:21:19 -0400537 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400538 }
539
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400540 if (!migratedManagedServices) {
541 mListeners.migrateToXml();
542 mAssistants.migrateToXml();
543 mConditionProviders.migrateToXml();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400544 savePolicyFile();
John Spurlock35ef0a62015-05-28 11:24:10 -0400545 }
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400546
547 mAssistants.ensureAssistant();
John Spurlock35ef0a62015-05-28 11:24:10 -0400548 }
549
John Spurlock056c5192014-04-20 21:52:01 -0400550 private void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400551 if (DBG) Slog.d(TAG, "loadPolicyFile");
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500552 synchronized (mPolicyFile) {
Daniel Sandler0da673f2012-04-11 12:33:16 -0400553
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400554 InputStream infile = null;
John Spurlock056c5192014-04-20 21:52:01 -0400555 try {
556 infile = mPolicyFile.openRead();
John Spurlock35ef0a62015-05-28 11:24:10 -0400557 readPolicyXml(infile, false /*forRestore*/);
John Spurlock056c5192014-04-20 21:52:01 -0400558 } catch (FileNotFoundException e) {
559 // No data yet
Julia Reynoldsb852e562017-06-06 16:14:18 -0400560 // Load default managed services approvals
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400561 readDefaultApprovedServices(USER_SYSTEM);
John Spurlock056c5192014-04-20 21:52:01 -0400562 } catch (IOException e) {
563 Log.wtf(TAG, "Unable to read notification policy", e);
564 } catch (NumberFormatException e) {
565 Log.wtf(TAG, "Unable to parse notification policy", e);
566 } catch (XmlPullParserException e) {
567 Log.wtf(TAG, "Unable to parse notification policy", e);
568 } finally {
569 IoUtils.closeQuietly(infile);
570 }
571 }
572 }
573
574 public void savePolicyFile() {
575 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
576 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
577 }
578
579 private void handleSavePolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400580 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400581 synchronized (mPolicyFile) {
582 final FileOutputStream stream;
583 try {
584 stream = mPolicyFile.startWrite();
585 } catch (IOException e) {
586 Slog.w(TAG, "Failed to save policy file", e);
587 return;
588 }
589
590 try {
John Spurlock35ef0a62015-05-28 11:24:10 -0400591 writePolicyXml(stream, false /*forBackup*/);
John Spurlock056c5192014-04-20 21:52:01 -0400592 mPolicyFile.finishWrite(stream);
593 } catch (IOException e) {
594 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
595 mPolicyFile.failWrite(stream);
Daniel Sandler0da673f2012-04-11 12:33:16 -0400596 }
597 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400598 BackupManager.dataChanged(getContext().getPackageName());
599 }
600
601 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
602 final XmlSerializer out = new FastXmlSerializer();
603 out.setOutput(stream, StandardCharsets.UTF_8.name());
604 out.startDocument(null, true);
605 out.startTag(null, TAG_NOTIFICATION_POLICY);
606 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
Beverly4e2f76c2018-03-16 15:43:49 -0400607 mZenModeHelper.writeXml(out, forBackup, null);
John Spurlock35ef0a62015-05-28 11:24:10 -0400608 mRankingHelper.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400609 mListeners.writeXml(out, forBackup);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400610 mAssistants.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400611 mConditionProviders.writeXml(out, forBackup);
John Spurlock35ef0a62015-05-28 11:24:10 -0400612 out.endTag(null, TAG_NOTIFICATION_POLICY);
613 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400614 }
615
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 private static final class ToastRecord
617 {
618 final int pid;
619 final String pkg;
Beverly Tai98efc792018-06-11 14:50:36 +0000620 final ITransientNotification callback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621 int duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700622 Binder token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700624 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
625 Binder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 this.pid = pid;
627 this.pkg = pkg;
628 this.callback = callback;
629 this.duration = duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700630 this.token = token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 }
632
633 void update(int duration) {
634 this.duration = duration;
635 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800636
John Spurlock25e2d242014-06-27 13:58:23 -0400637 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
638 if (filter != null && !filter.matches(pkg)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 pw.println(prefix + this);
640 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 @Override
643 public final String toString()
644 {
645 return "ToastRecord{"
646 + Integer.toHexString(System.identityHashCode(this))
647 + " pkg=" + pkg
648 + " callback=" + callback
649 + " duration=" + duration;
650 }
651 }
652
Beverly40239d92017-07-07 10:20:41 -0400653 @VisibleForTesting
654 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655
Adam Lesinski182f73f2013-12-05 16:48:06 -0800656 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 public void onSetDisabled(int status) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500658 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400659 mDisableNotificationEffects =
660 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
John Spurlock32fe4c62014-10-02 12:16:02 -0400661 if (disableNotificationEffects(null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 // cancel whatever's going on
663 long identity = Binder.clearCallingIdentity();
664 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800665 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700666 if (player != null) {
667 player.stopAsync();
668 }
669 } catch (RemoteException e) {
670 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 Binder.restoreCallingIdentity(identity);
672 }
673
674 identity = Binder.clearCallingIdentity();
675 try {
676 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700677 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 Binder.restoreCallingIdentity(identity);
679 }
680 }
681 }
682 }
683
Adam Lesinski182f73f2013-12-05 16:48:06 -0800684 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400685 public void onClearAll(int callingUid, int callingPid, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500686 synchronized (mNotificationLock) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400687 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
Kenny Guya263e4e2014-03-03 18:24:03 +0000688 /*includeCurrentProfiles*/ true);
Adam Lesinskie8240262014-03-26 16:01:00 -0700689 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 }
691
Adam Lesinski182f73f2013-12-05 16:48:06 -0800692 @Override
Dieter Hsud39f0d52018-04-14 02:08:30 +0800693 public void onNotificationClick(int callingUid, int callingPid, String key, NotificationVisibility nv) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800694 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500695 synchronized (mNotificationLock) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200696 NotificationRecord r = mNotificationsByKey.get(key);
697 if (r == null) {
698 Log.w(TAG, "No notification with key: " + key);
699 return;
700 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400701 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500702 MetricsLogger.action(r.getLogMaker(now)
703 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
Dieter Hsud39f0d52018-04-14 02:08:30 +0800704 .setType(MetricsEvent.TYPE_ACTION)
705 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
706 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400707 EventLogTags.writeNotificationClicked(key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800708 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
709 nv.rank, nv.count);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400710
Christoph Studer03b87a22014-04-30 17:33:27 +0200711 StatusBarNotification sbn = r.sbn;
712 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
713 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400714 FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
Dieter Hsud39f0d52018-04-14 02:08:30 +0800715 REASON_CLICK, nv.rank, nv.count, null);
716 nv.recycle();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800717 reportUserInteraction(r);
Christoph Studer03b87a22014-04-30 17:33:27 +0200718 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 }
720
Adam Lesinski182f73f2013-12-05 16:48:06 -0800721 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200722 public void onNotificationActionClick(int callingUid, int callingPid, String key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800723 int actionIndex, NotificationVisibility nv) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800724 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500725 synchronized (mNotificationLock) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200726 NotificationRecord r = mNotificationsByKey.get(key);
727 if (r == null) {
728 Log.w(TAG, "No notification with key: " + key);
729 return;
730 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400731 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500732 MetricsLogger.action(r.getLogMaker(now)
733 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
734 .setType(MetricsEvent.TYPE_ACTION)
Dieter Hsud39f0d52018-04-14 02:08:30 +0800735 .setSubtype(actionIndex)
736 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
737 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400738 EventLogTags.writeNotificationActionClicked(key, actionIndex,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800739 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
740 nv.rank, nv.count);
741 nv.recycle();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800742 reportUserInteraction(r);
Christoph Studer4da84cd2014-10-21 17:24:20 +0200743 }
744 }
745
746 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400747 public void onNotificationClear(int callingUid, int callingPid,
Julia Reynolds503ed942017-10-04 16:04:56 -0400748 String pkg, String tag, int id, int userId, String key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800749 @NotificationStats.DismissalSurface int dismissalSurface,
750 NotificationVisibility nv) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400751 synchronized (mNotificationLock) {
752 NotificationRecord r = mNotificationsByKey.get(key);
753 if (r != null) {
754 r.recordDismissalSurface(dismissalSurface);
755 }
756 }
John Spurlocke6a7d932014-03-13 12:29:00 -0400757 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400758 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800759 true, userId, REASON_CANCEL, nv.rank, nv.count,null);
760 nv.recycle();
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400761 }
762
Adam Lesinski182f73f2013-12-05 16:48:06 -0800763 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400764 public void onPanelRevealed(boolean clearEffects, int items) {
Chris Wren9eb5e102017-01-26 13:15:06 -0500765 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Chris Wren621933f2017-06-14 15:59:03 -0400766 MetricsLogger.histogram(getContext(), "note_load", items);
Chris Wrenb659c4f2015-06-25 17:12:27 -0400767 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100768 if (clearEffects) {
769 clearEffects();
770 }
771 }
772
773 @Override
774 public void onPanelHidden() {
Chris Wren9eb5e102017-01-26 13:15:06 -0500775 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Christoph Studer1f32c652014-11-26 15:32:20 +0100776 EventLogTags.writeNotificationPanelHidden();
777 }
778
779 @Override
780 public void clearEffects() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500781 synchronized (mNotificationLock) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100782 if (DBG) Slog.d(TAG, "clearEffects");
Chris Wren93bb8b82016-03-29 14:35:05 -0400783 clearSoundLocked();
784 clearVibrateLocked();
785 clearLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 }
787 }
Joe Onorato005847b2010-06-04 16:08:02 -0400788
Adam Lesinski182f73f2013-12-05 16:48:06 -0800789 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400790 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000791 int uid, int initialPid, String message, int userId) {
John Spurlocke6a7d932014-03-13 12:29:00 -0400792 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400793 REASON_ERROR, null);
Joe Onorato005847b2010-06-04 16:08:02 -0400794 }
John Spurlocke677d712014-02-13 12:52:19 -0500795
796 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400797 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
798 NotificationVisibility[] noLongerVisibleKeys) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500799 synchronized (mNotificationLock) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400800 for (NotificationVisibility nv : newlyVisibleKeys) {
801 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200802 if (r == null) continue;
Amith Yamasani803eab692017-11-09 17:47:04 -0800803 if (!r.isSeen()) {
804 // Report to usage stats that notification was made visible
805 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
806 reportSeen(r);
Kenny Guy23991102018-04-05 21:18:38 +0100807
808 // If the newly visible notification has smart replies
809 // then log that the user has seen them.
810 if (r.getNumSmartRepliesAdded() > 0
811 && !r.hasSeenSmartReplies()) {
812 r.setSeenSmartReplies(true);
813 LogMaker logMaker = r.getLogMaker()
814 .setCategory(MetricsEvent.SMART_REPLY_VISIBLE)
815 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT,
816 r.getNumSmartRepliesAdded());
817 mMetricsLogger.write(logMaker);
818 }
Amith Yamasani803eab692017-11-09 17:47:04 -0800819 }
Dieter Hsud39f0d52018-04-14 02:08:30 +0800820 r.setVisibility(true, nv.rank, nv.count);
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400821 maybeRecordInterruptionLocked(r);
Chris Wrend1dbc922015-06-19 17:51:16 -0400822 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200823 }
824 // Note that we might receive this event after notifications
825 // have already left the system, e.g. after dismissing from the
826 // shade. Hence not finding notifications in
827 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400828 for (NotificationVisibility nv : noLongerVisibleKeys) {
829 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200830 if (r == null) continue;
Dieter Hsud39f0d52018-04-14 02:08:30 +0800831 r.setVisibility(false, nv.rank, nv.count);
Chris Wrend1dbc922015-06-19 17:51:16 -0400832 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200833 }
834 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200835 }
Chris Wren78403d72014-07-28 10:23:24 +0100836
837 @Override
838 public void onNotificationExpansionChanged(String key,
839 boolean userAction, boolean expanded) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500840 synchronized (mNotificationLock) {
Chris Wren78403d72014-07-28 10:23:24 +0100841 NotificationRecord r = mNotificationsByKey.get(key);
842 if (r != null) {
843 r.stats.onExpansionChanged(userAction, expanded);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400844 final long now = System.currentTimeMillis();
Chris Wrenf7342712017-09-14 10:55:55 -0400845 if (userAction) {
Chris Wren377ac6d2017-09-12 14:15:23 -0400846 MetricsLogger.action(r.getLogMaker(now)
847 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
Chris Wrenf7342712017-09-14 10:55:55 -0400848 .setType(expanded ? MetricsEvent.TYPE_DETAIL
849 : MetricsEvent.TYPE_COLLAPSE));
Chris Wren377ac6d2017-09-12 14:15:23 -0400850 }
Julia Reynolds84dc96b2017-11-14 09:51:01 -0500851 if (expanded && userAction) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400852 r.recordExpanded();
853 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400854 EventLogTags.writeNotificationExpansion(key,
855 userAction ? 1 : 0, expanded ? 1 : 0,
856 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Chris Wren78403d72014-07-28 10:23:24 +0100857 }
858 }
859 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400860
861 @Override
862 public void onNotificationDirectReplied(String key) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800863 exitIdle();
Julia Reynolds503ed942017-10-04 16:04:56 -0400864 synchronized (mNotificationLock) {
865 NotificationRecord r = mNotificationsByKey.get(key);
866 if (r != null) {
867 r.recordDirectReplied();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800868 reportUserInteraction(r);
Julia Reynolds503ed942017-10-04 16:04:56 -0400869 }
870 }
871 }
872
873 @Override
Kenny Guy23991102018-04-05 21:18:38 +0100874 public void onNotificationSmartRepliesAdded(String key, int replyCount) {
875 synchronized (mNotificationLock) {
876 NotificationRecord r = mNotificationsByKey.get(key);
877 if (r != null) {
878 r.setNumSmartRepliesAdded(replyCount);
879 }
880 }
881 }
882
883 @Override
884 public void onNotificationSmartReplySent(String key, int replyIndex) {
885 synchronized (mNotificationLock) {
886 NotificationRecord r = mNotificationsByKey.get(key);
887 if (r != null) {
888 LogMaker logMaker = r.getLogMaker()
889 .setCategory(MetricsEvent.SMART_REPLY_ACTION)
890 .setSubtype(replyIndex);
891 mMetricsLogger.write(logMaker);
892 // Treat clicking on a smart reply as a user interaction.
893 reportUserInteraction(r);
894 }
895 }
896 }
897
898 @Override
Julia Reynolds503ed942017-10-04 16:04:56 -0400899 public void onNotificationSettingsViewed(String key) {
900 synchronized (mNotificationLock) {
901 NotificationRecord r = mNotificationsByKey.get(key);
902 if (r != null) {
903 r.recordViewedSettings();
904 }
905 }
906 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907 };
908
Julia Reynolds88860ce2017-06-01 16:55:49 -0400909 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400910 private void clearSoundLocked() {
911 mSoundNotificationKey = null;
912 long identity = Binder.clearCallingIdentity();
913 try {
914 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
915 if (player != null) {
916 player.stopAsync();
917 }
918 } catch (RemoteException e) {
919 } finally {
920 Binder.restoreCallingIdentity(identity);
921 }
922 }
923
Julia Reynolds88860ce2017-06-01 16:55:49 -0400924 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400925 private void clearVibrateLocked() {
926 mVibrateNotificationKey = null;
927 long identity = Binder.clearCallingIdentity();
928 try {
929 mVibrator.cancel();
930 } finally {
931 Binder.restoreCallingIdentity(identity);
932 }
933 }
934
Julia Reynolds88860ce2017-06-01 16:55:49 -0400935 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400936 private void clearLightsLocked() {
937 // light
938 mLights.clear();
939 updateLightsLocked();
940 }
941
Beverlyd4f96492017-08-02 13:36:11 -0400942 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
943 @Override
944 public void onReceive(Context context, Intent intent) {
945 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
Beverly70dcd002018-03-29 17:09:16 -0400946 // update system notification channels
947 SystemNotificationChannels.createAll(context);
Beverlyd4f96492017-08-02 13:36:11 -0400948 mZenModeHelper.updateDefaultZenRules();
Julia Reynolds816797a2017-08-11 15:47:09 -0400949 mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
Beverlyd4f96492017-08-02 13:36:11 -0400950 }
951 }
952 };
953
Julia Reynoldsb852e562017-06-06 16:14:18 -0400954 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
955 @Override
956 public void onReceive(Context context, Intent intent) {
957 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
958 try {
959 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
960 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
Michal Karpinski6135a262017-08-11 10:45:58 +0100961 int restoredFromSdkInt = intent.getIntExtra(
962 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400963 mListeners.onSettingRestored(
964 element, newValue, restoredFromSdkInt, getSendingUserId());
965 mConditionProviders.onSettingRestored(
966 element, newValue, restoredFromSdkInt, getSendingUserId());
Julia Reynoldsb852e562017-06-06 16:14:18 -0400967 } catch (Exception e) {
968 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
969 }
970 }
971 }
972 };
973
Julia Reynolds2a128742016-11-28 14:29:25 -0500974 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
975 @Override
976 public void onReceive(Context context, Intent intent) {
977 String action = intent.getAction();
978 if (action == null) {
979 return;
980 }
981 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
982 final NotificationRecord record;
983 synchronized (mNotificationLock) {
984 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
985 }
986 if (record != null) {
987 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
988 record.sbn.getPackageName(), record.sbn.getTag(),
989 record.sbn.getId(), 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400990 FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
Julia Reynolds2a128742016-11-28 14:29:25 -0500991 REASON_TIMEOUT, null);
992 }
993 }
994 }
995 };
996
Kenny Guy70058402014-10-28 20:45:06 +0000997 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 @Override
999 public void onReceive(Context context, Intent intent) {
1000 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -08001001 if (action == null) {
1002 return;
1003 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001005 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -04001006 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -04001007 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -04001008 boolean cancelNotifications = true;
Beverly5a20a5e2018-03-06 15:02:44 -05001009 boolean hideNotifications = false;
1010 boolean unhideNotifications = false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001011 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -04001012
Chris Wren3da73022013-05-10 14:41:21 -04001013 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -04001014 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001015 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -04001016 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001017 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001018 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
Beverly5a20a5e2018-03-06 15:02:44 -05001019 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
1020 || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
Kenny Guy70058402014-10-28 20:45:06 +00001021 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1022 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001023 String pkgList[] = null;
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001024 int uidList[] = null;
Julia Reynolds6434eb22016-08-08 17:19:26 -04001025 boolean removingPackage = queryRemove &&
1026 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
1027 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001028 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001029 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001030 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001031 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
1032 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Beverly5a20a5e2018-03-06 15:02:44 -05001033 cancelNotifications = false;
1034 hideNotifications = true;
1035 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
1036 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1037 cancelNotifications = false;
1038 unhideNotifications = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001039 } else if (queryRestart) {
1040 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001041 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001042 } else {
1043 Uri uri = intent.getData();
1044 if (uri == null) {
1045 return;
1046 }
1047 String pkgName = uri.getSchemeSpecificPart();
1048 if (pkgName == null) {
1049 return;
1050 }
Daniel Sandler26ece572012-06-01 15:38:46 -04001051 if (packageChanged) {
1052 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -07001053 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001054 final int enabled = mPackageManager.getApplicationEnabledSetting(
1055 pkgName,
Kenny Guy70058402014-10-28 20:45:06 +00001056 changeUserId != UserHandle.USER_ALL ? changeUserId :
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001057 USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -07001058 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1059 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
1060 cancelNotifications = false;
1061 }
1062 } catch (IllegalArgumentException e) {
1063 // Package doesn't exist; probably racing with uninstall.
1064 // cancelNotifications is already true, so nothing to do here.
1065 if (DBG) {
1066 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
1067 }
Kenny Guy70058402014-10-28 20:45:06 +00001068 } catch (RemoteException e) {
1069 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -04001070 }
1071 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001072 pkgList = new String[]{pkgName};
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001073 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001075 if (pkgList != null && (pkgList.length > 0)) {
1076 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -04001077 if (cancelNotifications) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001078 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
1079 !queryRestart, changeUserId, reason, null);
Beverly5a20a5e2018-03-06 15:02:44 -05001080 } else if (hideNotifications) {
1081 hideNotificationsForPackages(pkgList);
1082 } else if (unhideNotifications) {
1083 unhideNotificationsForPackages(pkgList);
John Spurlock79f78922013-05-16 09:10:05 -04001084 }
Beverly5a20a5e2018-03-06 15:02:44 -05001085
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001086 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 }
Beverly5a20a5e2018-03-06 15:02:44 -05001088
Julia Reynoldsb852e562017-06-06 16:14:18 -04001089 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001090 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsb852e562017-06-06 16:14:18 -04001091 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001092 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
1093 savePolicyFile();
Kenny Guy70058402014-10-28 20:45:06 +00001094 }
1095 }
1096 };
1097
1098 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1099 @Override
1100 public void onReceive(Context context, Intent intent) {
1101 String action = intent.getAction();
1102
1103 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001104 // Keep track of screen on/off state, but do not turn off the notification light
1105 // until user passes through the lock screen or views the notification.
1106 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +01001107 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001108 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1109 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +01001110 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001111 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -05001112 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
1113 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001114 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001115 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
1116 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1117 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001118 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001119 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001120 }
Rubin Xue95057a2016-04-01 16:49:25 +01001121 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001122 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +01001123 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001124 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001125 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001126 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001127 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1128 // turn off LED when user passes through lock screen
1129 mNotificationLight.turnOff();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001130 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001131 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001132 // reload per-user settings
1133 mSettingsObserver.update(null);
John Spurlockb408e8e2014-04-23 21:12:45 -04001134 mUserProfiles.updateCache(context);
Christoph Studerb53dfd42014-09-12 14:45:59 +02001135 // Refresh managed services
John Spurlock1b8b22b2015-05-20 09:47:13 -04001136 mConditionProviders.onUserSwitched(user);
1137 mListeners.onUserSwitched(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001138 mAssistants.onUserSwitched(user);
John Spurlock21258a32015-05-27 18:22:55 -04001139 mZenModeHelper.onUserSwitched(user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001140 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001141 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1142 if (userId != USER_NULL) {
1143 mUserProfiles.updateCache(context);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001144 if (!mUserProfiles.isManagedProfile(userId)) {
1145 readDefaultApprovedServices(userId);
1146 }
Julia Reynolds88a879f2017-07-26 17:06:46 -04001147 }
John Spurlock21258a32015-05-27 18:22:55 -04001148 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001149 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001150 mUserProfiles.updateCache(context);
John Spurlock21258a32015-05-27 18:22:55 -04001151 mZenModeHelper.onUserRemoved(user);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -04001152 mRankingHelper.onUserRemoved(user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001153 mListeners.onUserRemoved(user);
1154 mConditionProviders.onUserRemoved(user);
1155 mAssistants.onUserRemoved(user);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -04001156 savePolicyFile();
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001157 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001158 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001159 mConditionProviders.onUserUnlocked(user);
1160 mListeners.onUserUnlocked(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001161 mAssistants.onUserUnlocked(user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001162 mZenModeHelper.onUserUnlocked(user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 }
1164 }
1165 };
1166
John Spurlock7c74f782015-06-04 13:01:42 -04001167 private final class SettingsObserver extends ContentObserver {
Chris Wren89aa2262017-05-05 18:05:56 -04001168 private final Uri NOTIFICATION_BADGING_URI
1169 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001170 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1171 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wren763a9bb2016-05-31 17:14:12 -04001172 private final Uri NOTIFICATION_RATE_LIMIT_URI
1173 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001174
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001175 SettingsObserver(Handler handler) {
1176 super(handler);
1177 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001178
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001179 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001180 ContentResolver resolver = getContext().getContentResolver();
Chris Wren89aa2262017-05-05 18:05:56 -04001181 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1182 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001183 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -07001184 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -04001185 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1186 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001187 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001188 }
1189
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001190 @Override public void onChange(boolean selfChange, Uri uri) {
1191 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001192 }
1193
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001194 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001195 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001196 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
zhoulei7e376972017-05-17 18:41:25 +08001197 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
1198 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001199 if (mNotificationPulseEnabled != pulseEnabled) {
1200 mNotificationPulseEnabled = pulseEnabled;
1201 updateNotificationPulse();
1202 }
1203 }
Chris Wren763a9bb2016-05-31 17:14:12 -04001204 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1205 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1206 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1207 }
Chris Wren89aa2262017-05-05 18:05:56 -04001208 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
1209 mRankingHelper.updateBadgingEnabled();
1210 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001211 }
1212 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001213
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001214 private SettingsObserver mSettingsObserver;
Beverlyd4f96492017-08-02 13:36:11 -04001215 protected ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001216
Daniel Sandleredbb3802012-11-13 20:49:47 -08001217 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1218 int[] ar = r.getIntArray(resid);
1219 if (ar == null) {
1220 return def;
1221 }
1222 final int len = ar.length > maxlen ? maxlen : ar.length;
1223 long[] out = new long[len];
1224 for (int i=0; i<len; i++) {
1225 out[i] = ar[i];
1226 }
1227 return out;
1228 }
1229
Jeff Brownb880d882014-02-10 19:47:07 -08001230 public NotificationManagerService(Context context) {
1231 super(context);
Dianne Hackborn98305522017-05-05 17:53:53 -07001232 Notification.processWhitelistToken = WHITELIST_TOKEN;
Jeff Brownb880d882014-02-10 19:47:07 -08001233 }
1234
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001235 // TODO - replace these methods with a single VisibleForTesting constructor
Chris Wren93bb8b82016-03-29 14:35:05 -04001236 @VisibleForTesting
1237 void setAudioManager(AudioManager audioMananger) {
1238 mAudioManager = audioMananger;
1239 }
1240
1241 @VisibleForTesting
1242 void setVibrator(Vibrator vibrator) {
1243 mVibrator = vibrator;
1244 }
1245
1246 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001247 void setLights(Light light) {
1248 mNotificationLight = light;
1249 mAttentionLight = light;
Julia Reynolds033a4122017-01-31 16:50:38 -05001250 mNotificationPulseEnabled = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001251 }
1252
1253 @VisibleForTesting
1254 void setScreenOn(boolean on) {
1255 mScreenOn = on;
1256 }
1257
1258 @VisibleForTesting
Julia Reynolds080361e2017-07-13 11:23:12 -04001259 int getNotificationRecordCount() {
1260 synchronized (mNotificationLock) {
1261 int count = mNotificationList.size() + mNotificationsByKey.size()
1262 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1263 // subtract duplicates
1264 for (NotificationRecord posted : mNotificationList) {
1265 if (mNotificationsByKey.containsKey(posted.getKey())) {
1266 count--;
1267 }
1268 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001269 count--;
Julia Reynolds080361e2017-07-13 11:23:12 -04001270 }
1271 }
1272
1273 return count;
1274 }
1275 }
1276
Julia Reynolds7380d872018-01-12 10:28:26 -05001277 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001278 void clearNotifications() {
1279 mEnqueuedNotifications.clear();
1280 mNotificationList.clear();
1281 mNotificationsByKey.clear();
1282 mSummaryByGroupKey.clear();
1283 }
1284
Julia Reynolds080361e2017-07-13 11:23:12 -04001285 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001286 void addNotification(NotificationRecord r) {
1287 mNotificationList.add(r);
1288 mNotificationsByKey.put(r.sbn.getKey(), r);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001289 if (r.sbn.isGroup()) {
1290 mSummaryByGroupKey.put(r.getGroupKey(), r);
1291 }
1292 }
1293
1294 @VisibleForTesting
1295 void addEnqueuedNotification(NotificationRecord r) {
1296 mEnqueuedNotifications.add(r);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001297 }
1298
1299 @VisibleForTesting
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001300 NotificationRecord getNotificationRecord(String key) {
1301 return mNotificationsByKey.get(key);
1302 }
1303
1304
1305 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001306 void setSystemReady(boolean systemReady) {
1307 mSystemReady = systemReady;
1308 }
1309
1310 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001311 void setHandler(WorkerHandler handler) {
Chris Wren93bb8b82016-03-29 14:35:05 -04001312 mHandler = handler;
1313 }
1314
Chris Wrend4054312016-06-24 17:07:40 -04001315 @VisibleForTesting
Julia Reynolds0c299d42016-11-15 14:37:04 -05001316 void setFallbackVibrationPattern(long[] vibrationPattern) {
1317 mFallbackVibrationPattern = vibrationPattern;
Chris Wrend4054312016-06-24 17:07:40 -04001318 }
1319
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001320 @VisibleForTesting
1321 void setPackageManager(IPackageManager packageManager) {
1322 mPackageManager = packageManager;
1323 }
1324
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001325 @VisibleForTesting
1326 void setRankingHelper(RankingHelper rankingHelper) {
1327 mRankingHelper = rankingHelper;
1328 }
1329
1330 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001331 void setRankingHandler(RankingHandler rankingHandler) {
1332 mRankingHandler = rankingHandler;
1333 }
1334
1335 @VisibleForTesting
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001336 void setIsTelevision(boolean isTelevision) {
1337 mIsTelevision = isTelevision;
1338 }
1339
Julia Reynolds76c096d2017-06-19 08:16:04 -04001340 @VisibleForTesting
1341 void setUsageStats(NotificationUsageStats us) {
1342 mUsageStats = us;
1343 }
1344
Julia Reynolds94187562017-10-10 13:58:49 -04001345 @VisibleForTesting
1346 void setAccessibilityManager(AccessibilityManager am) {
1347 mAccessibilityManager = am;
1348 }
1349
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001350 // TODO: All tests should use this init instead of the one-off setters above.
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001351 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001352 void init(Looper looper, IPackageManager packageManager,
1353 PackageManager packageManagerClient,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001354 LightsManager lightsManager, NotificationListeners notificationListeners,
Julia Reynoldsb852e562017-06-06 16:14:18 -04001355 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001356 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
Julia Reynolds68263d12017-06-21 14:21:19 -04001357 NotificationUsageStats usageStats, AtomicFile policyFile,
Julia Reynolds7217dc92018-03-07 12:12:09 -05001358 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
Jason Parks50322ff2018-03-27 10:23:33 -05001359 UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm) {
Chris Wren54bbef42014-07-09 18:37:56 -04001360 Resources resources = getContext().getResources();
Chris Wren763a9bb2016-05-31 17:14:12 -04001361 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1362 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1363 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1364
Julia Reynolds94187562017-10-10 13:58:49 -04001365 mAccessibilityManager =
1366 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001367 mAm = am;
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001368 mPackageManager = packageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001369 mPackageManagerClient = packageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001370 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1371 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Julia Reynolds7217dc92018-03-07 12:12:09 -05001372 mAppUsageStats = appUsageStats;
Julia Reynolds2a128742016-11-28 14:29:25 -05001373 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001374 mCompanionManager = companionManager;
Julia Reynolds68263d12017-06-21 14:21:19 -04001375 mActivityManager = activityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -08001376 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1377 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
Jason Parks50322ff2018-03-27 10:23:33 -05001378 mDpm = dpm;
1379
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001380 mHandler = new WorkerHandler(looper);
Chris Wrenf9536642014-04-17 10:01:54 -04001381 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -04001382 String[] extractorNames;
1383 try {
1384 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1385 } catch (Resources.NotFoundException e) {
1386 extractorNames = new String[0];
1387 }
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001388 mUsageStats = usageStats;
Kenny Guy23991102018-04-05 21:18:38 +01001389 mMetricsLogger = new MetricsLogger();
Chris Wren51017d02015-12-15 15:34:46 -05001390 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Julia Reynoldsb852e562017-06-06 16:14:18 -04001391 mConditionProviders = conditionProviders;
John Spurlockb2278d62015-04-07 12:47:12 -04001392 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -04001393 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -04001394 @Override
1395 public void onConfigChanged() {
1396 savePolicyFile();
1397 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001398
1399 @Override
1400 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001401 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -05001402 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -05001403 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1404 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -05001405 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001406 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02001407 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001408 }
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001409 mRankingHandler.requestSort();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001410 }
John Spurlock1fc476d2015-04-14 16:05:20 -04001411
1412 @Override
1413 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001414 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001415 mRankingHandler.requestSort();
John Spurlock80774932015-05-07 17:38:50 -04001416 }
John Spurlock056c5192014-04-20 21:52:01 -04001417 });
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001418 mRankingHelper = new RankingHelper(getContext(),
1419 mPackageManagerClient,
1420 mRankingHandler,
1421 mZenModeHelper,
1422 mUsageStats,
1423 extractorNames);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001424 mSnoozeHelper = snoozeHelper;
Julia Reynolds8aebf352017-06-26 11:35:33 -04001425 mGroupHelper = groupHelper;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04001426
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001427 // This is a ManagedServices object that keeps track of the listeners.
1428 mListeners = notificationListeners;
Chris Wren0efdb882016-03-01 17:17:47 -05001429
Julia Reynolds77b2cc92016-11-08 14:41:09 -05001430 // This is a MangedServices object that keeps track of the assistant.
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001431 mAssistants = notificationAssistants;
Julia Reynoldsb852e562017-06-06 16:14:18 -04001432
Kristian Monsen30f59b22018-04-09 10:27:16 +02001433 // Needs to be set before loadPolicyFile
1434 mAllowedManagedServicePackages = this::canUseManagedServices;
1435
Julia Reynoldsb852e562017-06-06 16:14:18 -04001436 mPolicyFile = policyFile;
1437 loadPolicyFile();
Chris Wren0efdb882016-03-01 17:17:47 -05001438
Adam Lesinski182f73f2013-12-05 16:48:06 -08001439 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -08001440 if (mStatusBar != null) {
1441 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1442 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001444 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1445 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001446
Daniel Sandleredbb3802012-11-13 20:49:47 -08001447 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001448 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001449 VIBRATE_PATTERN_MAXLEN,
1450 DEFAULT_VIBRATE_PATTERN);
Beverly5d463b62017-07-26 14:13:40 -04001451 mInCallNotificationUri = Uri.parse("file://" +
1452 resources.getString(R.string.config_inCallNotificationSound));
1453 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1454 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1455 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
Beverly5d463b62017-07-26 14:13:40 -04001456 .build();
1457 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1458
Chris Wren5116a822014-06-04 15:59:50 -04001459 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1460
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001461 // Don't start allowing notifications until the setup wizard has run once.
1462 // After that, including subsequent boots, init with notifications turned on.
1463 // This works on the first boot because the setup wizard will toggle this
1464 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001465 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001466 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001467 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001468 }
John Spurlockb2278d62015-04-07 12:47:12 -04001469 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001470 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001471
John Spurlockb408e8e2014-04-23 21:12:45 -04001472 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001473 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001474
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001475 mSettingsObserver = new SettingsObserver(mHandler);
1476
1477 mArchive = new Archive(resources.getInteger(
1478 R.integer.config_notificationServiceArchiveSize));
1479
1480 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1481 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1482 }
1483
1484 @Override
1485 public void onStart() {
1486 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1487 @Override
1488 public void repost(int userId, NotificationRecord r) {
1489 try {
1490 if (DBG) {
1491 Slog.d(TAG, "Reposting " + r.getKey());
1492 }
1493 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1494 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1495 r.sbn.getNotification(), userId);
1496 } catch (Exception e) {
1497 Slog.e(TAG, "Cannot un-snooze notification", e);
1498 }
1499 }
1500 }, mUserProfiles);
1501
1502 final File systemDir = new File(Environment.getDataDirectory(), "system");
1503
1504 init(Looper.myLooper(),
1505 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1506 getLocalService(LightsManager.class),
1507 new NotificationListeners(AppGlobals.getPackageManager()),
Julia Reynolds7380d872018-01-12 10:28:26 -05001508 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
1509 AppGlobals.getPackageManager()),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001510 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1511 null, snoozeHelper, new NotificationUsageStats(getContext()),
Dianne Hackborne17b4452018-01-10 13:15:40 -08001512 new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001513 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
Julia Reynolds7217dc92018-03-07 12:12:09 -05001514 getGroupHelper(), ActivityManager.getService(),
Jason Parks50322ff2018-03-27 10:23:33 -05001515 LocalServices.getService(UsageStatsManagerInternal.class),
1516 LocalServices.getService(DevicePolicyManagerInternal.class));
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001517
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001518 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001520 filter.addAction(Intent.ACTION_SCREEN_ON);
1521 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001522 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001523 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001524 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001525 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001526 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001527 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001528 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001529 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001530 getContext().registerReceiver(mIntentReceiver, filter);
Kenny Guy70058402014-10-28 20:45:06 +00001531
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001532 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001533 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001534 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001535 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001536 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1537 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1538 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001539 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1540 null);
1541
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001542 IntentFilter suspendedPkgFilter = new IntentFilter();
1543 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
Beverly5a20a5e2018-03-06 15:02:44 -05001544 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001545 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1546 suspendedPkgFilter, null, null);
1547
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001548 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001549 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1550 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001551
Julia Reynolds2a128742016-11-28 14:29:25 -05001552 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1553 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1554 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1555
Julia Reynoldsb852e562017-06-06 16:14:18 -04001556 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1557 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1558
Beverlyd4f96492017-08-02 13:36:11 -04001559 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1560 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1561
Vishnu Naire3e4d252018-03-01 11:26:57 -08001562 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
1563 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001564 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 }
1566
Julia Reynolds8aebf352017-06-26 11:35:33 -04001567 private GroupHelper getGroupHelper() {
1568 return new GroupHelper(new GroupHelper.Callback() {
1569 @Override
1570 public void addAutoGroup(String key) {
1571 synchronized (mNotificationLock) {
1572 addAutogroupKeyLocked(key);
1573 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001574 }
1575
1576 @Override
1577 public void removeAutoGroup(String key) {
1578 synchronized (mNotificationLock) {
1579 removeAutogroupKeyLocked(key);
1580 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001581 }
1582
1583 @Override
1584 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1585 createAutoGroupSummary(userId, pkg, triggeringKey);
1586 }
1587
1588 @Override
1589 public void removeAutoGroupSummary(int userId, String pkg) {
1590 synchronized (mNotificationLock) {
1591 clearAutogroupSummaryLocked(userId, pkg);
1592 }
1593 }
1594 });
1595 }
1596
John Spurlocke7a835b2015-05-13 10:47:05 -04001597 private void sendRegisteredOnlyBroadcast(String action) {
1598 getContext().sendBroadcastAsUser(new Intent(action)
1599 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1600 }
1601
Adam Lesinski182f73f2013-12-05 16:48:06 -08001602 @Override
1603 public void onBootPhase(int phase) {
1604 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1605 // no beeping until we're basically done booting
1606 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001607
Adam Lesinski182f73f2013-12-05 16:48:06 -08001608 // Grab our optional AudioService
1609 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001610 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001611 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001612 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001613 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1614 // This observer will force an update when observe is called, causing us to
1615 // bind to listener services.
1616 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001617 mListeners.onBootPhaseAppsCanStart();
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001618 mAssistants.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001619 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001620 }
1621 }
1622
Julia Reynolds88860ce2017-06-01 16:55:49 -04001623 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04001624 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001625 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001626 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001627 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001628 mListenerHints = hints;
1629 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001630 }
1631
Julia Reynolds88860ce2017-06-01 16:55:49 -04001632 @GuardedBy("mNotificationLock")
John Spurlockb4782522014-08-22 14:54:46 -04001633 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001634 final long updatedSuppressedEffects = calculateSuppressedEffects();
1635 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1636 final List<ComponentName> suppressors = getSuppressors();
1637 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1638 mEffectsSuppressors = suppressors;
1639 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001640 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001641 }
1642
Amith Yamasani396a10c2018-01-19 10:58:07 -08001643 private void exitIdle() {
1644 try {
1645 if (mDeviceIdleController != null) {
1646 mDeviceIdleController.exitIdle("notification interaction");
1647 }
1648 } catch (RemoteException e) {
1649 }
1650 }
1651
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001652 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1653 boolean fromListener) {
Julia Reynolds924eed12017-01-19 09:52:07 -05001654 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1655 // cancel
1656 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001657 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
Julia Reynolds924eed12017-01-19 09:52:07 -05001658 null);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001659 if (isUidSystemOrPhone(uid)) {
1660 int[] profileIds = mUserProfiles.getCurrentProfileIds();
1661 int N = profileIds.length;
1662 for (int i = 0; i < N; i++) {
1663 int profileId = profileIds[i];
1664 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1665 profileId, REASON_CHANNEL_BANNED,
1666 null);
1667 }
1668 }
Julia Reynolds924eed12017-01-19 09:52:07 -05001669 }
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001670 final NotificationChannel preUpdate =
1671 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
1672
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001673 mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001674 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
Julia Reynolds924eed12017-01-19 09:52:07 -05001675
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001676 if (!fromListener) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001677 final NotificationChannel modifiedChannel =
1678 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001679 mListeners.notifyNotificationChannelChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001680 pkg, UserHandle.getUserHandleForUid(uid),
1681 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001682 }
1683
Julia Reynolds924eed12017-01-19 09:52:07 -05001684 savePolicyFile();
1685 }
1686
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001687 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1688 NotificationChannel update) {
1689 try {
1690 if ((preUpdate.getImportance() == IMPORTANCE_NONE
1691 && update.getImportance() != IMPORTANCE_NONE)
1692 || (preUpdate.getImportance() != IMPORTANCE_NONE
1693 && update.getImportance() == IMPORTANCE_NONE)) {
1694 getContext().sendBroadcastAsUser(
1695 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001696 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001697 update.getId())
1698 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1699 update.getImportance() == IMPORTANCE_NONE)
1700 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1701 .setPackage(pkg),
1702 UserHandle.of(UserHandle.getUserId(uid)), null);
1703 }
1704 } catch (SecurityException e) {
1705 Slog.w(TAG, "Can't notify app about channel change", e);
1706 }
1707 }
1708
Julia Reynolds005c8b92017-08-24 10:35:53 -04001709 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
1710 boolean fromApp, boolean fromListener) {
1711 Preconditions.checkNotNull(group);
1712 Preconditions.checkNotNull(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001713
1714 final NotificationChannelGroup preUpdate =
1715 mRankingHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
Julia Reynolds005c8b92017-08-24 10:35:53 -04001716 mRankingHelper.createNotificationChannelGroup(pkg, uid, group,
1717 fromApp);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001718 if (!fromApp) {
1719 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
1720 }
Julia Reynolds005c8b92017-08-24 10:35:53 -04001721 if (!fromListener) {
1722 mListeners.notifyNotificationChannelGroupChanged(pkg,
1723 UserHandle.of(UserHandle.getCallingUserId()), group,
1724 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1725 }
1726 }
1727
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001728 private void maybeNotifyChannelGroupOwner(String pkg, int uid,
1729 NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
1730 try {
1731 if (preUpdate.isBlocked() != update.isBlocked()) {
1732 getContext().sendBroadcastAsUser(
1733 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001734 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001735 update.getId())
1736 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1737 update.isBlocked())
1738 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1739 .setPackage(pkg),
1740 UserHandle.of(UserHandle.getUserId(uid)), null);
1741 }
1742 } catch (SecurityException e) {
1743 Slog.w(TAG, "Can't notify app about group change", e);
1744 }
1745 }
1746
Bryce Lee7219ada2016-04-08 10:54:23 -07001747 private ArrayList<ComponentName> getSuppressors() {
1748 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1749 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1750 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1751
1752 for (ManagedServiceInfo info : serviceInfoList) {
1753 names.add(info.component);
1754 }
1755 }
1756
1757 return names;
1758 }
1759
1760 private boolean removeDisabledHints(ManagedServiceInfo info) {
1761 return removeDisabledHints(info, 0);
1762 }
1763
1764 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1765 boolean removed = false;
1766
1767 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1768 final int hint = mListenersDisablingEffects.keyAt(i);
1769 final ArraySet<ManagedServiceInfo> listeners =
1770 mListenersDisablingEffects.valueAt(i);
1771
1772 if (hints == 0 || (hint & hints) == hint) {
1773 removed = removed || listeners.remove(info);
1774 }
1775 }
1776
1777 return removed;
1778 }
1779
1780 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1781 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1782 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1783 }
1784
1785 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1786 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1787 }
1788
1789 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1790 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1791 }
1792 }
1793
1794 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1795 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1796 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1797 }
1798
1799 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1800 hintListeners.add(info);
1801 }
1802
1803 private int calculateHints() {
1804 int hints = 0;
1805 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1806 int hint = mListenersDisablingEffects.keyAt(i);
1807 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1808
1809 if (!serviceInfoList.isEmpty()) {
1810 hints |= hint;
1811 }
1812 }
1813
1814 return hints;
1815 }
1816
1817 private long calculateSuppressedEffects() {
1818 int hints = calculateHints();
1819 long suppressedEffects = 0;
1820
1821 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1822 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1823 }
1824
1825 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1826 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1827 }
1828
1829 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1830 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1831 }
1832
1833 return suppressedEffects;
1834 }
1835
Julia Reynolds88860ce2017-06-01 16:55:49 -04001836 @GuardedBy("mNotificationLock")
Christoph Studer85a384b2014-08-27 20:16:15 +02001837 private void updateInterruptionFilterLocked() {
1838 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1839 if (interruptionFilter == mInterruptionFilter) return;
1840 mInterruptionFilter = interruptionFilter;
1841 scheduleInterruptionFilterChanged(interruptionFilter);
1842 }
1843
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001844 @VisibleForTesting
1845 INotificationManager getBinderService() {
1846 return INotificationManager.Stub.asInterface(mService);
1847 }
1848
Amith Yamasani7ec89412018-02-07 08:48:49 -08001849 /**
1850 * Report to usage stats that the notification was seen.
1851 * @param r notification record
1852 */
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001853 @GuardedBy("mNotificationLock")
Amith Yamasani803eab692017-11-09 17:47:04 -08001854 protected void reportSeen(NotificationRecord r) {
Amith Yamasani803eab692017-11-09 17:47:04 -08001855 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001856 getRealUserId(r.sbn.getUserId()),
Amith Yamasani803eab692017-11-09 17:47:04 -08001857 UsageEvents.Event.NOTIFICATION_SEEN);
1858 }
1859
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001860 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
1861 int targetSdkVersion) {
1862 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
1863 return incomingPolicy.suppressedVisualEffects;
1864 }
1865 final int[] effectsIntroducedInP = {
1866 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
1867 SUPPRESSED_EFFECT_LIGHTS,
1868 SUPPRESSED_EFFECT_PEEK,
1869 SUPPRESSED_EFFECT_STATUS_BAR,
1870 SUPPRESSED_EFFECT_BADGE,
1871 SUPPRESSED_EFFECT_AMBIENT,
1872 SUPPRESSED_EFFECT_NOTIFICATION_LIST
1873 };
1874
1875 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06001876 if (targetSdkVersion < Build.VERSION_CODES.P) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001877 // unset higher order bits introduced in P, maintain the user's higher order bits
1878 for (int i = 0; i < effectsIntroducedInP.length ; i++) {
1879 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
1880 newSuppressedVisualEffects |=
1881 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
1882 }
1883 // set higher order bits according to lower order bits
1884 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1885 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1886 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001887 }
1888 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1889 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1890 }
1891 } else {
1892 boolean hasNewEffects = (newSuppressedVisualEffects
1893 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
1894 // if any of the new effects introduced in P are set
1895 if (hasNewEffects) {
1896 // clear out the deprecated effects
1897 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
1898 | SUPPRESSED_EFFECT_SCREEN_OFF);
1899
1900 // set the deprecated effects according to the new more specific effects
1901 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
1902 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
1903 }
1904 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
1905 && (newSuppressedVisualEffects
1906 & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
1907 && (newSuppressedVisualEffects
1908 & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
1909 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
1910 }
1911 } else {
1912 // set higher order bits according to lower order bits
1913 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1914 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1915 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
1916 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
1917 }
1918 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1919 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1920 }
1921 }
1922 }
1923
1924 return newSuppressedVisualEffects;
1925 }
1926
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001927 @GuardedBy("mNotificationLock")
1928 protected void maybeRecordInterruptionLocked(NotificationRecord r) {
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04001929 if (r.isInterruptive() && !r.hasRecordedInterruption()) {
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001930 mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
1931 r.getChannel().getId(),
1932 getRealUserId(r.sbn.getUserId()));
Julia Reynoldsad7d7132018-03-21 16:05:00 -04001933 logRecentLocked(r);
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04001934 r.setRecordedInterruption(true);
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001935 }
1936 }
1937
Amith Yamasani7ec89412018-02-07 08:48:49 -08001938 /**
1939 * Report to usage stats that the notification was clicked.
1940 * @param r notification record
1941 */
1942 protected void reportUserInteraction(NotificationRecord r) {
Amith Yamasani7ec89412018-02-07 08:48:49 -08001943 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001944 getRealUserId(r.sbn.getUserId()),
Amith Yamasani7ec89412018-02-07 08:48:49 -08001945 UsageEvents.Event.USER_INTERACTION);
1946 }
1947
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001948 private int getRealUserId(int userId) {
1949 return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
1950 }
1951
Geoffrey Pitsch415e4542017-04-10 13:12:58 -04001952 @VisibleForTesting
1953 NotificationManagerInternal getInternalService() {
1954 return mInternalService;
1955 }
1956
Adam Lesinski182f73f2013-12-05 16:48:06 -08001957 private final IBinder mService = new INotificationManager.Stub() {
1958 // Toasts
1959 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001960
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001961 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001962 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001963 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001964 if (DBG) {
1965 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1966 + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001968
1969 if (pkg == null || callback == null) {
1970 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1971 return ;
1972 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001973 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001974 final boolean isPackageSuspended =
1975 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
Adam Lesinski182f73f2013-12-05 16:48:06 -08001976
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001977 if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001978 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1979 || isPackageSuspended)) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001980 Slog.e(TAG, "Suppressing toast from package " + pkg
1981 + (isPackageSuspended
1982 ? " due to package suspended by administrator."
1983 : " by user request."));
1984 return;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001985 }
1986
1987 synchronized (mToastQueue) {
1988 int callingPid = Binder.getCallingPid();
1989 long callingId = Binder.clearCallingIdentity();
1990 try {
1991 ToastRecord record;
Beverly Tai98efc792018-06-11 14:50:36 +00001992 int index = indexOfToastLocked(pkg, callback);
1993 // If it's already in the queue, we update it in place, we don't
1994 // move it to the end of the queue.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001995 if (index >= 0) {
1996 record = mToastQueue.get(index);
1997 record.update(duration);
1998 } else {
Beverly Tai98efc792018-06-11 14:50:36 +00001999 // Limit the number of toasts that any given package except the android
2000 // package can enqueue. Prevents DOS attacks and deals with leaks.
2001 if (!isSystemToast) {
2002 int count = 0;
2003 final int N = mToastQueue.size();
2004 for (int i=0; i<N; i++) {
2005 final ToastRecord r = mToastQueue.get(i);
2006 if (r.pkg.equals(pkg)) {
2007 count++;
2008 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2009 Slog.e(TAG, "Package has already posted " + count
2010 + " toasts. Not showing more. Package=" + pkg);
2011 return;
2012 }
2013 }
2014 }
2015 }
2016
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002017 Binder token = new Binder();
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002018 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002019 record = new ToastRecord(callingPid, pkg, callback, duration, token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002020 mToastQueue.add(record);
2021 index = mToastQueue.size() - 1;
Beverly Tai98efc792018-06-11 14:50:36 +00002022 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002023 }
2024 // If it's at index 0, it's the current toast. It doesn't matter if it's
2025 // new or just been updated. Call back and tell it to show itself.
2026 // If the callback fails, this will remove it from the list, so don't
2027 // assume that it's valid after this.
2028 if (index == 0) {
2029 showNextToastLocked();
2030 }
2031 } finally {
2032 Binder.restoreCallingIdentity(callingId);
2033 }
2034 }
2035 }
2036
2037 @Override
2038 public void cancelToast(String pkg, ITransientNotification callback) {
2039 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
2040
2041 if (pkg == null || callback == null) {
2042 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
2043 return ;
2044 }
2045
2046 synchronized (mToastQueue) {
2047 long callingId = Binder.clearCallingIdentity();
2048 try {
2049 int index = indexOfToastLocked(pkg, callback);
2050 if (index >= 0) {
2051 cancelToastLocked(index);
2052 } else {
2053 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
2054 + " callback=" + callback);
2055 }
2056 } finally {
2057 Binder.restoreCallingIdentity(callingId);
2058 }
2059 }
2060 }
2061
2062 @Override
Robert Carr997427342018-02-28 18:06:10 -08002063 public void finishToken(String pkg, ITransientNotification callback) {
2064 synchronized (mToastQueue) {
2065 long callingId = Binder.clearCallingIdentity();
2066 try {
2067 int index = indexOfToastLocked(pkg, callback);
2068 if (index >= 0) {
2069 ToastRecord record = mToastQueue.get(index);
2070 finishTokenLocked(record.token);
2071 } else {
2072 Slog.w(TAG, "Toast already killed. pkg=" + pkg
2073 + " callback=" + callback);
2074 }
2075 } finally {
2076 Binder.restoreCallingIdentity(callingId);
2077 }
2078 }
2079 }
2080
2081 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002082 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002083 Notification notification, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002084 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002085 Binder.getCallingPid(), tag, id, notification, userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002086 }
2087
2088 @Override
2089 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002090 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002091 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2092 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002093 // Don't allow client applications to cancel foreground service notis or autobundled
2094 // summaries.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002095 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
Julia Reynoldse5c60452018-04-30 14:41:36 -04002096 (FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
John Spurlocke6a7d932014-03-13 12:29:00 -04002097 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002098 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002099 }
2100
2101 @Override
2102 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002103 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002104
2105 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2106 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
2107
2108 // Calling from user space, don't allow the canceling of actively
2109 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04002110 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
Julia Reynoldse5c60452018-04-30 14:41:36 -04002111 pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05002112 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002113 }
2114
2115 @Override
2116 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
Rohan Shahca0447e2018-03-30 15:18:27 -07002117 enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002118
Chris Wrenacf424a2016-03-15 12:48:55 -04002119 mRankingHelper.setEnabled(pkg, uid, enabled);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002120 // Now, cancel any outstanding notifications that are part of a just-disabled app
Julia Reynolds4da79702017-06-01 11:06:10 -04002121 if (!enabled) {
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002122 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
2123 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
2124 }
Julia Reynoldsfc9767b2018-01-22 17:45:16 -05002125
2126 try {
2127 getContext().sendBroadcastAsUser(
2128 new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
2129 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
2130 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2131 .setPackage(pkg),
2132 UserHandle.of(UserHandle.getUserId(uid)), null);
2133 } catch (SecurityException e) {
2134 Slog.w(TAG, "Can't notify app about app block change", e);
2135 }
2136
Chris Wrenacf424a2016-03-15 12:48:55 -04002137 savePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002138 }
2139
2140 /**
Rohan Shah590e1b22018-04-10 23:48:47 -04002141 * Updates the enabled state for notifications for the given package (and uid).
2142 * Additionally, this method marks the app importance as locked by the user, which means
2143 * that notifications from the app will <b>not</b> be considered for showing a
2144 * blocking helper.
2145 *
2146 * @param pkg package that owns the notifications to update
2147 * @param uid uid of the app providing notifications
2148 * @param enabled whether notifications should be enabled for the app
2149 *
2150 * @see #setNotificationsEnabledForPackage(String, int, boolean)
2151 */
2152 @Override
2153 public void setNotificationsEnabledWithImportanceLockForPackage(
2154 String pkg, int uid, boolean enabled) {
2155 setNotificationsEnabledForPackage(pkg, uid, enabled);
2156
2157 mRankingHelper.setAppImportanceLocked(pkg, uid);
2158 }
2159
2160 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002161 * Use this when you just want to know if notifications are OK for this package.
2162 */
2163 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002164 public boolean areNotificationsEnabled(String pkg) {
2165 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
2166 }
2167
2168 /**
2169 * Use this when you just want to know if notifications are OK for this package.
2170 */
2171 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002172 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002173 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002174
2175 return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002176 }
2177
Chris Wren54bbef42014-07-09 18:37:56 -04002178 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05002179 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002180 checkCallerIsSystemOrSameApp(pkg);
Julia Reynoldsef37f282016-02-12 09:11:27 -05002181 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002182 }
2183
2184 @Override
Julia Reynolds924eed12017-01-19 09:52:07 -05002185 public boolean canShowBadge(String pkg, int uid) {
2186 checkCallerIsSystem();
2187 return mRankingHelper.canShowBadge(pkg, uid);
2188 }
2189
2190 @Override
2191 public void setShowBadge(String pkg, int uid, boolean showBadge) {
2192 checkCallerIsSystem();
2193 mRankingHelper.setShowBadge(pkg, uid, showBadge);
2194 savePolicyFile();
2195 }
2196
2197 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002198 public void updateNotificationChannelGroupForPackage(String pkg, int uid,
2199 NotificationChannelGroup group) throws RemoteException {
2200 enforceSystemOrSystemUI("Caller not system or systemui");
2201 createNotificationChannelGroup(pkg, uid, group, false, false);
2202 savePolicyFile();
2203 }
2204
2205 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002206 public void createNotificationChannelGroups(String pkg,
2207 ParceledListSlice channelGroupList) throws RemoteException {
2208 checkCallerIsSystemOrSameApp(pkg);
2209 List<NotificationChannelGroup> groups = channelGroupList.getList();
2210 final int groupSize = groups.size();
2211 for (int i = 0; i < groupSize; i++) {
2212 final NotificationChannelGroup group = groups.get(i);
Julia Reynolds005c8b92017-08-24 10:35:53 -04002213 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002214 }
2215 savePolicyFile();
2216 }
2217
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002218 private void createNotificationChannelsImpl(String pkg, int uid,
2219 ParceledListSlice channelsList) {
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002220 List<NotificationChannel> channels = channelsList.getList();
2221 final int channelsSize = channels.size();
2222 for (int i = 0; i < channelsSize; i++) {
2223 final NotificationChannel channel = channels.get(i);
2224 Preconditions.checkNotNull(channel, "channel in list is null");
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002225 mRankingHelper.createNotificationChannel(pkg, uid, channel,
Julia Reynolds1fe10942018-03-28 12:46:51 -04002226 true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed(
2227 pkg, UserHandle.getUserId(uid)));
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002228 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002229 UserHandle.getUserHandleForUid(uid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002230 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
2231 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002232 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002233 savePolicyFile();
2234 }
2235
2236 @Override
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002237 public void createNotificationChannels(String pkg,
2238 ParceledListSlice channelsList) throws RemoteException {
2239 checkCallerIsSystemOrSameApp(pkg);
2240 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
2241 }
2242
2243 @Override
2244 public void createNotificationChannelsForPackage(String pkg, int uid,
2245 ParceledListSlice channelsList) throws RemoteException {
2246 checkCallerIsSystem();
2247 createNotificationChannelsImpl(pkg, uid, channelsList);
2248 }
2249
2250 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002251 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002252 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002253 return mRankingHelper.getNotificationChannel(
2254 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002255 }
2256
2257 @Override
2258 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002259 String channelId, boolean includeDeleted) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002260 checkCallerIsSystem();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002261 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002262 }
2263
2264 @Override
2265 public void deleteNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002266 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002267 final int callingUid = Binder.getCallingUid();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002268 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
2269 throw new IllegalArgumentException("Cannot delete default channel");
2270 }
2271 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002272 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
2273 mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
2274 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002275 UserHandle.getUserHandleForUid(callingUid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002276 mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
2277 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002278 savePolicyFile();
2279 }
2280
2281 @Override
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002282 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
2283 checkCallerIsSystemOrSameApp(pkg);
2284 return mRankingHelper.getNotificationChannelGroupWithChannels(
2285 pkg, Binder.getCallingUid(), groupId, false);
2286 }
2287
2288 @Override
Julia Reynolds9bfba592017-03-15 14:03:55 -04002289 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
2290 String pkg) {
2291 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002292 return mRankingHelper.getNotificationChannelGroups(
2293 pkg, Binder.getCallingUid(), false, false);
Julia Reynolds9bfba592017-03-15 14:03:55 -04002294 }
2295
2296 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002297 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04002298 checkCallerIsSystemOrSameApp(pkg);
2299
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002300 final int callingUid = Binder.getCallingUid();
2301 NotificationChannelGroup groupToDelete =
2302 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
2303 if (groupToDelete != null) {
2304 List<NotificationChannel> deletedChannels =
2305 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
2306 for (int i = 0; i < deletedChannels.size(); i++) {
2307 final NotificationChannel deletedChannel = deletedChannels.get(i);
2308 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2309 true,
2310 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2311 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002312 mListeners.notifyNotificationChannelChanged(pkg,
2313 UserHandle.getUserHandleForUid(callingUid),
2314 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002315 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2316 }
2317 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002318 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2319 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002320 savePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002321 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04002322 }
2323
2324 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002325 public void updateNotificationChannelForPackage(String pkg, int uid,
2326 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002327 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05002328 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002329 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002330 }
2331
2332 @Override
2333 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002334 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002335 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002336 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002337 }
2338
2339 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002340 public int getNumNotificationChannelsForPackage(String pkg, int uid,
2341 boolean includeDeleted) {
2342 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
2343 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
2344 .getList().size();
2345 }
2346
2347 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04002348 public boolean onlyHasDefaultChannel(String pkg, int uid) {
2349 enforceSystemOrSystemUI("onlyHasDefaultChannel");
2350 return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
2351 }
2352
2353 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04002354 public int getDeletedChannelCount(String pkg, int uid) {
2355 enforceSystemOrSystemUI("getDeletedChannelCount");
2356 return mRankingHelper.getDeletedChannelCount(pkg, uid);
2357 }
2358
2359 @Override
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002360 public int getBlockedChannelCount(String pkg, int uid) {
2361 enforceSystemOrSystemUI("getBlockedChannelCount");
2362 return mRankingHelper.getBlockedChannelCount(pkg, uid);
2363 }
2364
2365 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002366 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2367 String pkg, int uid, boolean includeDeleted) {
2368 checkCallerIsSystem();
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002369 return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted, true);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002370 }
2371
2372 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002373 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2374 String pkg, int uid, String groupId, boolean includeDeleted) {
2375 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
2376 return mRankingHelper.getNotificationChannelGroupWithChannels(
2377 pkg, uid, groupId, includeDeleted);
2378 }
2379
2380 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002381 public NotificationChannelGroup getNotificationChannelGroupForPackage(
2382 String groupId, String pkg, int uid) {
2383 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
2384 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
2385 }
2386
2387 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002388 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
2389 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002390 return mRankingHelper.getNotificationChannels(
2391 pkg, Binder.getCallingUid(), false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002392 }
2393
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002394 @Override
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05002395 public ParceledListSlice<NotifyingApp> getRecentNotifyingAppsForUser(int userId) {
2396 checkCallerIsSystem();
2397 synchronized (mNotificationLock) {
2398 List<NotifyingApp> apps = new ArrayList<>(
2399 mRecentApps.getOrDefault(userId, new ArrayList<>()));
2400 return new ParceledListSlice<>(apps);
2401 }
2402 }
2403
2404 @Override
Julia Reynoldse273f082018-04-12 13:48:49 -04002405 public int getBlockedAppCount(int userId) {
2406 checkCallerIsSystem();
2407 return mRankingHelper.getBlockedAppCount(userId);
2408 }
2409
2410 @Override
Beverly86d076f2018-04-17 14:44:52 -04002411 public boolean areChannelsBypassingDnd() {
2412 return mRankingHelper.areChannelsBypassingDnd();
2413 }
2414
2415 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05002416 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002417 checkCallerIsSystem();
2418
2419 // Cancel posted notifications
2420 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2421 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2422
Julia Reynoldsb852e562017-06-06 16:14:18 -04002423 final String[] packages = new String[] {packageName};
2424 final int[] uids = new int[] {uid};
2425
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002426 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04002427 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002428 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002429
2430 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04002431 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002432
2433 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05002434 if (!fromApp) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002435 mRankingHelper.onPackagesChanged(
2436 true, UserHandle.getCallingUserId(), packages, uids);
Julia Reynolds5355e852017-02-07 14:54:13 -05002437 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002438
2439 savePolicyFile();
2440 }
2441
2442
Adam Lesinski182f73f2013-12-05 16:48:06 -08002443 /**
2444 * System-only API for getting a list of current (i.e. not cleared) notifications.
2445 *
2446 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04002447 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002448 */
2449 @Override
2450 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2451 // enforce() will ensure the calling uid has the correct permission
2452 getContext().enforceCallingOrSelfPermission(
2453 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2454 "NotificationManagerService.getActiveNotifications");
2455
2456 StatusBarNotification[] tmp = null;
2457 int uid = Binder.getCallingUid();
2458
2459 // noteOp will check to make sure the callingPkg matches the uid
2460 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2461 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002462 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002463 tmp = new StatusBarNotification[mNotificationList.size()];
2464 final int N = mNotificationList.size();
2465 for (int i=0; i<N; i++) {
2466 tmp[i] = mNotificationList.get(i).sbn;
2467 }
2468 }
2469 }
2470 return tmp;
2471 }
2472
2473 /**
Dan Sandler994349c2015-04-15 11:02:54 -04002474 * Public API for getting a list of current notifications for the calling package/uid.
2475 *
Julia Reynolds573c6532017-01-24 17:44:38 -05002476 * Note that since notification posting is done asynchronously, this will not return
2477 * notifications that are in the process of being posted.
2478 *
Dan Sandler994349c2015-04-15 11:02:54 -04002479 * @returns A list of all the package's notifications, in natural order.
2480 */
2481 @Override
2482 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2483 int incomingUserId) {
2484 checkCallerIsSystemOrSameApp(pkg);
2485 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2486 Binder.getCallingUid(), incomingUserId, true, false,
2487 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002488 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002489 final ArrayMap<String, StatusBarNotification> map
2490 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002491 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002492 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002493 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2494 mNotificationList.get(i).sbn);
2495 if (sbn != null) {
2496 map.put(sbn.getKey(), sbn);
2497 }
2498 }
2499 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2500 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2501 if (sbn != null) {
2502 map.put(sbn.getKey(), sbn);
2503 }
2504 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002505 final int M = mEnqueuedNotifications.size();
2506 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002507 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2508 mEnqueuedNotifications.get(i).sbn);
2509 if (sbn != null) {
2510 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04002511 }
2512 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002513 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2514 list.addAll(map.values());
2515 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04002516 }
Dan Sandler994349c2015-04-15 11:02:54 -04002517 }
2518
Chris Wren6676dab2016-12-21 18:26:27 -05002519 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2520 StatusBarNotification sbn) {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04002521 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
Chris Wren6676dab2016-12-21 18:26:27 -05002522 // We could pass back a cloneLight() but clients might get confused and
2523 // try to send this thing back to notify() again, which would not work
2524 // very well.
2525 return new StatusBarNotification(
2526 sbn.getPackageName(),
2527 sbn.getOpPkg(),
Chris Wren6676dab2016-12-21 18:26:27 -05002528 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2529 sbn.getNotification().clone(),
2530 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2531 }
2532 return null;
2533 }
2534
Dan Sandler994349c2015-04-15 11:02:54 -04002535 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002536 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2537 *
2538 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2539 */
2540 @Override
2541 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2542 // enforce() will ensure the calling uid has the correct permission
2543 getContext().enforceCallingOrSelfPermission(
2544 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2545 "NotificationManagerService.getHistoricalNotifications");
2546
2547 StatusBarNotification[] tmp = null;
2548 int uid = Binder.getCallingUid();
2549
2550 // noteOp will check to make sure the callingPkg matches the uid
2551 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2552 == AppOpsManager.MODE_ALLOWED) {
2553 synchronized (mArchive) {
2554 tmp = mArchive.getArray(count);
2555 }
2556 }
2557 return tmp;
2558 }
2559
2560 /**
2561 * Register a listener binder directly with the notification manager.
2562 *
2563 * Only works with system callers. Apps should extend
2564 * {@link android.service.notification.NotificationListenerService}.
2565 */
2566 @Override
2567 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05002568 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02002569 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05002570 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002571 }
2572
2573 /**
2574 * Remove a listener binder directly
2575 */
2576 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002577 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05002578 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002579 }
2580
2581 /**
2582 * Allow an INotificationListener to simulate a "clear all" operation.
2583 *
2584 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2585 *
2586 * @param token The binder for the listener, to check that the caller is allowed
2587 */
2588 @Override
John Spurlocka4294292014-03-24 18:02:32 -04002589 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002590 final int callingUid = Binder.getCallingUid();
2591 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002592 long identity = Binder.clearCallingIdentity();
2593 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002594 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002595 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Beverly5a20a5e2018-03-06 15:02:44 -05002596
John Spurlocka4294292014-03-24 18:02:32 -04002597 if (keys != null) {
2598 final int N = keys.length;
2599 for (int i = 0; i < N; i++) {
2600 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07002601 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00002602 final int userId = r.sbn.getUserId();
2603 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04002604 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00002605 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04002606 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00002607 }
Griff Hazen335e1f02014-09-11 14:49:31 -07002608 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2609 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2610 userId);
John Spurlocka4294292014-03-24 18:02:32 -04002611 }
2612 } else {
2613 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00002614 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04002615 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002616 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002617 } finally {
2618 Binder.restoreCallingIdentity(identity);
2619 }
2620 }
2621
Chris Wrenab41eec2016-01-04 18:01:27 -05002622 /**
2623 * Handle request from an approved listener to re-enable itself.
2624 *
2625 * @param component The componenet to be re-enabled, caller must match package.
2626 */
2627 @Override
2628 public void requestBindListener(ComponentName component) {
2629 checkCallerIsSystemOrSameApp(component.getPackageName());
2630 long identity = Binder.clearCallingIdentity();
2631 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002632 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002633 mAssistants.isComponentEnabledForCurrentProfiles(component)
2634 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05002635 : mListeners;
2636 manager.setComponentState(component, true);
2637 } finally {
2638 Binder.restoreCallingIdentity(identity);
2639 }
2640 }
2641
2642 @Override
2643 public void requestUnbindListener(INotificationListener token) {
2644 long identity = Binder.clearCallingIdentity();
2645 try {
2646 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002647 synchronized (mNotificationLock) {
2648 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2649 info.getOwner().setComponentState(info.component, false);
2650 }
Chris Wrenab41eec2016-01-04 18:01:27 -05002651 } finally {
2652 Binder.restoreCallingIdentity(identity);
2653 }
2654 }
2655
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002656 @Override
2657 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002658 long identity = Binder.clearCallingIdentity();
2659 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002660 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002661 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2662 if (keys != null) {
2663 final int N = keys.length;
2664 for (int i = 0; i < N; i++) {
2665 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2666 if (r == null) continue;
2667 final int userId = r.sbn.getUserId();
2668 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2669 !mUserProfiles.isCurrentProfile(userId)) {
2670 throw new SecurityException("Disallowed call from listener: "
2671 + info.service);
2672 }
2673 if (!r.isSeen()) {
2674 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
Amith Yamasani803eab692017-11-09 17:47:04 -08002675 reportSeen(r);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002676 r.setSeen();
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04002677 maybeRecordInterruptionLocked(r);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002678 }
2679 }
2680 }
2681 }
2682 } finally {
2683 Binder.restoreCallingIdentity(identity);
2684 }
2685 }
2686
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002687 /**
2688 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2689 *
2690 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2691 *
Julia Reynolds79672302017-01-12 08:30:16 -05002692 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002693 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04002694 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04002695 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00002696 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04002697 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -04002698 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
John Spurlocka4294292014-03-24 18:02:32 -04002699 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00002700 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04002701 }
2702
Adam Lesinski182f73f2013-12-05 16:48:06 -08002703 /**
Julia Reynolds79672302017-01-12 08:30:16 -05002704 * Allow an INotificationListener to snooze a single notification until a context.
2705 *
2706 * @param token The binder for the listener, to check that the caller is allowed
2707 */
2708 @Override
2709 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2710 String key, String snoozeCriterionId) {
2711 long identity = Binder.clearCallingIdentity();
2712 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002713 synchronized (mNotificationLock) {
2714 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2715 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2716 }
Julia Reynolds79672302017-01-12 08:30:16 -05002717 } finally {
2718 Binder.restoreCallingIdentity(identity);
2719 }
2720 }
2721
2722 /**
2723 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002724 *
2725 * @param token The binder for the listener, to check that the caller is allowed
2726 */
2727 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002728 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05002729 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002730 long identity = Binder.clearCallingIdentity();
2731 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002732 synchronized (mNotificationLock) {
2733 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2734 snoozeNotificationInt(key, duration, null, info);
2735 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002736 } finally {
2737 Binder.restoreCallingIdentity(identity);
2738 }
2739 }
2740
2741 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002742 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002743 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002744 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002745 */
2746 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002747 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002748 long identity = Binder.clearCallingIdentity();
2749 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002750 synchronized (mNotificationLock) {
2751 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002752 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002753 unsnoozeNotificationInt(key, info);
2754 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002755 } finally {
2756 Binder.restoreCallingIdentity(identity);
2757 }
2758 }
2759
2760 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002761 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2762 *
2763 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2764 *
2765 * @param token The binder for the listener, to check that the caller is allowed
2766 */
2767 @Override
2768 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2769 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002770 final int callingUid = Binder.getCallingUid();
2771 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002772 long identity = Binder.clearCallingIdentity();
2773 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002774 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002775 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00002776 if (info.supportsProfiles()) {
2777 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2778 + "from " + info.component
2779 + " use cancelNotification(key) instead.");
2780 } else {
2781 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2782 pkg, tag, id, info.userid);
2783 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002784 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002785 } finally {
2786 Binder.restoreCallingIdentity(identity);
2787 }
2788 }
2789
2790 /**
2791 * Allow an INotificationListener to request the list of outstanding notifications seen by
2792 * the current user. Useful when starting up, after which point the listener callbacks
2793 * should be used.
2794 *
2795 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002796 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04002797 * @returns The return value will contain the notifications specified in keys, in that
2798 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002799 */
2800 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02002801 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02002802 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002803 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002804 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002805 final boolean getKeys = keys != null;
2806 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02002807 final ArrayList<StatusBarNotification> list
2808 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02002809 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002810 final NotificationRecord r = getKeys
2811 ? mNotificationsByKey.get(keys[i])
2812 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02002813 if (r == null) continue;
2814 StatusBarNotification sbn = r.sbn;
2815 if (!isVisibleToListener(sbn, info)) continue;
2816 StatusBarNotification sbnToSend =
2817 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2818 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002819 }
Christoph Studercee44ba2014-05-20 18:36:43 +02002820 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002821 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002822 }
2823
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002824 /**
2825 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2826 * seen by the current user. Useful when starting up, after which point the listener
2827 * callbacks should be used.
2828 *
2829 * @param token The binder for the listener, to check that the caller is allowed
2830 * @returns The return value will contain the notifications specified in keys, in that
2831 * order, or if keys is null, all the notifications, in natural order.
2832 */
2833 @Override
2834 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2835 INotificationListener token, int trim) {
2836 synchronized (mNotificationLock) {
2837 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2838 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2839 final int N = snoozedRecords.size();
2840 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2841 for (int i=0; i < N; i++) {
2842 final NotificationRecord r = snoozedRecords.get(i);
2843 if (r == null) continue;
2844 StatusBarNotification sbn = r.sbn;
2845 if (!isVisibleToListener(sbn, info)) continue;
2846 StatusBarNotification sbnToSend =
2847 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2848 list.add(sbnToSend);
2849 }
2850 return new ParceledListSlice<>(list);
2851 }
2852 }
2853
Adam Lesinski182f73f2013-12-05 16:48:06 -08002854 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002855 public void requestHintsFromListener(INotificationListener token, int hints) {
2856 final long identity = Binder.clearCallingIdentity();
2857 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002858 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002859 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07002860 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2861 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2862 | HINT_HOST_DISABLE_CALL_EFFECTS;
2863 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04002864 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07002865 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002866 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07002867 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002868 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002869 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04002870 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04002871 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002872 } finally {
2873 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04002874 }
2875 }
2876
2877 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002878 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002879 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002880 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04002881 }
2882 }
2883
2884 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02002885 public void requestInterruptionFilterFromListener(INotificationListener token,
2886 int interruptionFilter) throws RemoteException {
2887 final long identity = Binder.clearCallingIdentity();
2888 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002889 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002890 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2891 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02002892 updateInterruptionFilterLocked();
2893 }
2894 } finally {
2895 Binder.restoreCallingIdentity(identity);
2896 }
2897 }
2898
2899 @Override
2900 public int getInterruptionFilterFromListener(INotificationListener token)
2901 throws RemoteException {
2902 synchronized (mNotificationLight) {
2903 return mInterruptionFilter;
2904 }
2905 }
2906
2907 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02002908 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2909 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002910 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02002911 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2912 if (info == null) return;
2913 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2914 }
2915 }
2916
2917 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002918 public int getZenMode() {
2919 return mZenModeHelper.getZenMode();
2920 }
2921
2922 @Override
John Spurlock056c5192014-04-20 21:52:01 -04002923 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002924 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04002925 return mZenModeHelper.getConfig();
2926 }
2927
2928 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002929 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002930 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05002931 final long identity = Binder.clearCallingIdentity();
2932 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002933 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05002934 } finally {
2935 Binder.restoreCallingIdentity(identity);
2936 }
2937 }
2938
2939 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002940 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002941 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05002942 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002943 }
2944
2945 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002946 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2947 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002948 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002949 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002950 }
2951
2952 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002953 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002954 throws RemoteException {
2955 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2956 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2957 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2958 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002959 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002960
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002961 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2962 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002963 }
2964
2965 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002966 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002967 throws RemoteException {
2968 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2969 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2970 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2971 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2972 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002973
Julia Reynolds361e82d32016-02-26 18:19:49 -05002974 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002975 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002976 }
2977
2978 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002979 public boolean removeAutomaticZenRule(String id) throws RemoteException {
2980 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002981 // Verify that they can modify zen rules.
2982 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2983
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002984 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002985 }
2986
2987 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05002988 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2989 Preconditions.checkNotNull(packageName, "Package name is null");
2990 enforceSystemOrSystemUI("removeAutomaticZenRules");
2991
2992 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2993 }
2994
2995 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05002996 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2997 Preconditions.checkNotNull(owner, "Owner is null");
2998 enforceSystemOrSystemUI("getRuleInstanceCount");
2999
3000 return mZenModeHelper.getCurrentInstanceCount(owner);
3001 }
3002
3003 @Override
John Spurlock80774932015-05-07 17:38:50 -04003004 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
3005 enforcePolicyAccess(pkg, "setInterruptionFilter");
3006 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
3007 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
3008 final long identity = Binder.clearCallingIdentity();
3009 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04003010 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04003011 } finally {
3012 Binder.restoreCallingIdentity(identity);
3013 }
3014 }
3015
3016 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04003017 public void notifyConditions(final String pkg, IConditionProvider provider,
3018 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04003019 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3020 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04003021 mHandler.post(new Runnable() {
3022 @Override
3023 public void run() {
3024 mConditionProviders.notifyConditions(pkg, info, conditions);
3025 }
3026 });
John Spurlocke77bb362014-04-26 10:24:59 -04003027 }
3028
Julia Reynolds38e6ca42016-08-08 08:38:09 -04003029 @Override
3030 public void requestUnbindProvider(IConditionProvider provider) {
3031 long identity = Binder.clearCallingIdentity();
3032 try {
3033 // allow bound services to disable themselves
3034 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3035 info.getOwner().setComponentState(info.component, false);
3036 } finally {
3037 Binder.restoreCallingIdentity(identity);
3038 }
3039 }
3040
3041 @Override
3042 public void requestBindProvider(ComponentName component) {
3043 checkCallerIsSystemOrSameApp(component.getPackageName());
3044 long identity = Binder.clearCallingIdentity();
3045 try {
3046 mConditionProviders.setComponentState(component, true);
3047 } finally {
3048 Binder.restoreCallingIdentity(identity);
3049 }
3050 }
3051
John Spurlocke77bb362014-04-26 10:24:59 -04003052 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003053 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04003054 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
3055 message);
John Spurlock7340fc82014-04-24 18:50:12 -04003056 }
3057
Julia Reynolds48034f82016-03-09 10:15:16 -05003058 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
3059 try {
3060 checkCallerIsSystemOrSameApp(pkg);
3061 } catch (SecurityException e) {
3062 getContext().enforceCallingPermission(
3063 android.Manifest.permission.STATUS_BAR_SERVICE,
3064 message);
3065 }
3066 }
3067
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003068 private void enforcePolicyAccess(int uid, String method) {
3069 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3070 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3071 return;
3072 }
3073 boolean accessAllowed = false;
3074 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
3075 final int packageCount = packages.length;
3076 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003077 if (mConditionProviders.isPackageOrComponentAllowed(
3078 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003079 accessAllowed = true;
3080 }
3081 }
3082 if (!accessAllowed) {
3083 Slog.w(TAG, "Notification policy access denied calling " + method);
3084 throw new SecurityException("Notification policy access denied");
3085 }
3086 }
3087
John Spurlock80774932015-05-07 17:38:50 -04003088 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04003089 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3090 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3091 return;
3092 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04003093 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003094 if (!checkPolicyAccess(pkg)) {
3095 Slog.w(TAG, "Notification policy access denied calling " + method);
3096 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04003097 }
3098 }
3099
John Spurlock80774932015-05-07 17:38:50 -04003100 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003101 return mConditionProviders.isPackageOrComponentAllowed(
3102 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04003103 }
3104
3105 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003106 try {
Jason Parks50322ff2018-03-27 10:23:33 -05003107 int uid = getContext().getPackageManager().getPackageUidAsUser(pkg,
3108 UserHandle.getCallingUserId());
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003109 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
3110 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
3111 -1, true)) {
3112 return true;
3113 }
3114 } catch (NameNotFoundException e) {
3115 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003116 }
Jason Parks50322ff2018-03-27 10:23:33 -05003117 return checkPackagePolicyAccess(pkg)
3118 || mListeners.isComponentEnabledForPackage(pkg)
3119 || (mDpm != null &&
3120 mDpm.isActiveAdminWithPolicy(Binder.getCallingUid(),
3121 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER));
John Spurlock1fc476d2015-04-14 16:05:20 -04003122 }
3123
John Spurlock7340fc82014-04-24 18:50:12 -04003124 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08003125 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003126 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04003127 final DumpFilter filter = DumpFilter.parseFromArguments(args);
Kweku Adams887f09c2017-11-13 17:12:20 -08003128 if (filter.stats) {
Chris Wrene4b38802015-07-07 15:54:19 -04003129 dumpJson(pw, filter);
Kweku Adams887f09c2017-11-13 17:12:20 -08003130 } else if (filter.proto) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003131 dumpProto(fd, filter);
Vishnu Naire3e4d252018-03-01 11:26:57 -08003132 } else if (filter.criticalPriority) {
3133 dumpNotificationRecords(pw, filter);
Chris Wrene4b38802015-07-07 15:54:19 -04003134 } else {
3135 dumpImpl(pw, filter);
3136 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003137 }
John Spurlockb4782522014-08-22 14:54:46 -04003138
3139 @Override
3140 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07003141 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04003142 }
John Spurlock2b122f42014-08-27 16:29:47 -04003143
3144 @Override
3145 public boolean matchesCallFilter(Bundle extras) {
3146 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02003147 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003148 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02003149 extras,
3150 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
3151 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
3152 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04003153 }
John Spurlock530052a2014-11-30 16:26:19 -05003154
3155 @Override
3156 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003157 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04003158 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05003159 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003160
Christopher Tatef9767d62015-04-08 14:35:43 -07003161 // Backup/restore interface
3162 @Override
3163 public byte[] getBackupPayload(int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003164 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003165 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003166 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003167 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003168 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
3169 return null;
3170 }
songjinshi9bf22712017-02-04 10:47:45 +08003171 synchronized(mPolicyFile) {
3172 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
3173 try {
3174 writePolicyXml(baos, true /*forBackup*/);
3175 return baos.toByteArray();
3176 } catch (IOException e) {
3177 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
3178 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003179 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003180 return null;
3181 }
3182
3183 @Override
3184 public void applyRestore(byte[] payload, int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003185 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003186 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
3187 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
3188 if (payload == null) {
3189 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
3190 return;
3191 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003192 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003193 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003194 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
3195 return;
3196 }
songjinshi9bf22712017-02-04 10:47:45 +08003197 synchronized(mPolicyFile) {
3198 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
3199 try {
3200 readPolicyXml(bais, true /*forRestore*/);
3201 savePolicyFile();
3202 } catch (NumberFormatException | XmlPullParserException | IOException e) {
3203 Slog.w(TAG, "applyRestore: error reading payload", e);
3204 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003205 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003206 }
3207
John Spurlock1fc476d2015-04-14 16:05:20 -04003208 @Override
John Spurlock80774932015-05-07 17:38:50 -04003209 public boolean isNotificationPolicyAccessGranted(String pkg) {
3210 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04003211 }
3212
3213 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05003214 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
3215 enforceSystemOrSystemUIOrSamePackage(pkg,
3216 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003217 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003218 }
3219
3220 @Override
John Spurlock80774932015-05-07 17:38:50 -04003221 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
3222 throws RemoteException {
Julia Reynolds92febc32017-10-26 11:30:31 -04003223 setNotificationPolicyAccessGrantedForUser(
3224 pkg, getCallingUserHandle().getIdentifier(), granted);
3225 }
3226
3227 @Override
3228 public void setNotificationPolicyAccessGrantedForUser(
3229 String pkg, int userId, boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003230 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003231 final long identity = Binder.clearCallingIdentity();
3232 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003233 if (mAllowedManagedServicePackages.test(pkg)) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003234 mConditionProviders.setPackageOrComponentEnabled(
Julia Reynolds92febc32017-10-26 11:30:31 -04003235 pkg, userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003236
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003237 getContext().sendBroadcastAsUser(new Intent(
3238 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3239 .setPackage(pkg)
3240 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003241 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003242 savePolicyFile();
3243 }
3244 } finally {
3245 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003246 }
John Spurlock80774932015-05-07 17:38:50 -04003247 }
3248
3249 @Override
3250 public Policy getNotificationPolicy(String pkg) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003251 final long identity = Binder.clearCallingIdentity();
3252 try {
3253 return mZenModeHelper.getNotificationPolicy();
3254 } finally {
3255 Binder.restoreCallingIdentity(identity);
3256 }
3257 }
3258
Beverly6697eff2017-12-14 15:00:27 -05003259 /**
3260 * Sets the notification policy. Apps that target API levels below
Beverly98ef61b2018-02-15 10:36:28 -05003261 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
Beverlyd6964762018-02-16 14:07:03 -05003262 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3263 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3264 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
Beverly6697eff2017-12-14 15:00:27 -05003265 */
John Spurlock1fc476d2015-04-14 16:05:20 -04003266 @Override
John Spurlock80774932015-05-07 17:38:50 -04003267 public void setNotificationPolicy(String pkg, Policy policy) {
3268 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04003269 final long identity = Binder.clearCallingIdentity();
3270 try {
Beverly6697eff2017-12-14 15:00:27 -05003271 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3272 0, UserHandle.getUserId(MY_UID));
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003273 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
Beverly6697eff2017-12-14 15:00:27 -05003274
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06003275 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
Beverly98ef61b2018-02-15 10:36:28 -05003276 int priorityCategories = policy.priorityCategories;
3277 // ignore alarm and media values from new policy
3278 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
Beverlyd6964762018-02-16 14:07:03 -05003279 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3280 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003281 // use user-designated values
Beverlyd6964762018-02-16 14:07:03 -05003282 priorityCategories |= currPolicy.priorityCategories
3283 & Policy.PRIORITY_CATEGORY_ALARMS;
3284 priorityCategories |= currPolicy.priorityCategories
3285 & Policy.PRIORITY_CATEGORY_MEDIA;
3286 priorityCategories |= currPolicy.priorityCategories
3287 & Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003288
Beverly6697eff2017-12-14 15:00:27 -05003289 policy = new Policy(priorityCategories,
3290 policy.priorityCallSenders, policy.priorityMessageSenders,
3291 policy.suppressedVisualEffects);
3292 }
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003293 int newVisualEffects = calculateSuppressedVisualEffects(
3294 policy, currPolicy, applicationInfo.targetSdkVersion);
3295 policy = new Policy(policy.priorityCategories,
3296 policy.priorityCallSenders, policy.priorityMessageSenders,
3297 newVisualEffects);
Beverly5e073222018-03-08 10:36:25 -05003298 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
John Spurlock1fc476d2015-04-14 16:05:20 -04003299 mZenModeHelper.setNotificationPolicy(policy);
Beverly6697eff2017-12-14 15:00:27 -05003300 } catch (RemoteException e) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003301 } finally {
3302 Binder.restoreCallingIdentity(identity);
3303 }
3304 }
Chris Wren51017d02015-12-15 15:34:46 -05003305
3306 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003307 public List<String> getEnabledNotificationListenerPackages() {
3308 checkCallerIsSystem();
3309 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3310 }
3311
3312 @Override
3313 public List<ComponentName> getEnabledNotificationListeners(int userId) {
3314 checkCallerIsSystem();
3315 return mListeners.getAllowedComponents(userId);
3316 }
3317
3318 @Override
3319 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3320 Preconditions.checkNotNull(listener);
3321 checkCallerIsSystemOrSameApp(listener.getPackageName());
3322 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3323 getCallingUserHandle().getIdentifier());
3324 }
3325
3326 @Override
3327 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3328 int userId) {
3329 Preconditions.checkNotNull(listener);
3330 checkCallerIsSystem();
3331 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3332 userId);
3333 }
3334
3335 @Override
3336 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3337 Preconditions.checkNotNull(assistant);
3338 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003339 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04003340 getCallingUserHandle().getIdentifier());
3341 }
3342
3343 @Override
3344 public void setNotificationListenerAccessGranted(ComponentName listener,
3345 boolean granted) throws RemoteException {
3346 setNotificationListenerAccessGrantedForUser(
3347 listener, getCallingUserHandle().getIdentifier(), granted);
3348 }
3349
3350 @Override
3351 public void setNotificationAssistantAccessGranted(ComponentName assistant,
3352 boolean granted) throws RemoteException {
3353 setNotificationAssistantAccessGrantedForUser(
3354 assistant, getCallingUserHandle().getIdentifier(), granted);
3355 }
3356
3357 @Override
3358 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3359 boolean granted) throws RemoteException {
3360 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04003361 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003362 final long identity = Binder.clearCallingIdentity();
3363 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003364 if (mAllowedManagedServicePackages.test(listener.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003365 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3366 userId, false, granted);
3367 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3368 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003369
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003370 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds92febc32017-10-26 11:30:31 -04003371 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003372 .setPackage(listener.getPackageName())
3373 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003374 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003375
3376 savePolicyFile();
3377 }
3378 } finally {
3379 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003380 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003381 }
3382
3383 @Override
3384 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3385 int userId, boolean granted) throws RemoteException {
3386 Preconditions.checkNotNull(assistant);
Julia Reynolds0d217642017-08-11 11:26:04 -04003387 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003388 final long identity = Binder.clearCallingIdentity();
3389 try {
Kristian Monsen30f59b22018-04-09 10:27:16 +02003390 if (mAllowedManagedServicePackages.test(assistant.getPackageName())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003391 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
3392 userId, false, granted);
3393 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
3394 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003395
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003396 getContext().sendBroadcastAsUser(new Intent(
3397 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3398 .setPackage(assistant.getPackageName())
3399 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003400 UserHandle.of(userId), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003401
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003402 savePolicyFile();
3403 }
3404 } finally {
3405 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003406 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003407 }
3408
3409 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003410 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
3411 Adjustment adjustment) throws RemoteException {
3412 final long identity = Binder.clearCallingIdentity();
3413 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003414 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003415 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003416 int N = mEnqueuedNotifications.size();
3417 for (int i = 0; i < N; i++) {
3418 final NotificationRecord n = mEnqueuedNotifications.get(i);
3419 if (Objects.equals(adjustment.getKey(), n.getKey())
3420 && Objects.equals(adjustment.getUser(), n.getUserId())) {
3421 applyAdjustment(n, adjustment);
3422 break;
3423 }
3424 }
3425 }
3426 } finally {
3427 Binder.restoreCallingIdentity(identity);
3428 }
3429 }
3430
3431 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003432 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003433 Adjustment adjustment) throws RemoteException {
Chris Wren51017d02015-12-15 15:34:46 -05003434 final long identity = Binder.clearCallingIdentity();
3435 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003436 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003437 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003438 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3439 applyAdjustment(n, adjustment);
Chris Wren51017d02015-12-15 15:34:46 -05003440 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003441 mRankingHandler.requestSort();
Julia Reynoldse46bb372016-03-17 11:05:58 -04003442 } finally {
3443 Binder.restoreCallingIdentity(identity);
3444 }
3445 }
3446
3447 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003448 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003449 List<Adjustment> adjustments) throws RemoteException {
3450
3451 final long identity = Binder.clearCallingIdentity();
3452 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003453 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003454 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003455 for (Adjustment adjustment : adjustments) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003456 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3457 applyAdjustment(n, adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003458 }
3459 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003460 mRankingHandler.requestSort();
Chris Wren51017d02015-12-15 15:34:46 -05003461 } finally {
3462 Binder.restoreCallingIdentity(identity);
3463 }
3464 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003465
3466 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04003467 public void updateNotificationChannelGroupFromPrivilegedListener(
3468 INotificationListener token, String pkg, UserHandle user,
3469 NotificationChannelGroup group) throws RemoteException {
3470 Preconditions.checkNotNull(user);
3471 verifyPrivilegedListener(token, user);
3472 createNotificationChannelGroup(
3473 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
3474 savePolicyFile();
3475 }
3476
3477 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003478 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003479 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003480 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003481 Preconditions.checkNotNull(pkg);
3482 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003483
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003484 verifyPrivilegedListener(token, user);
3485 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003486 }
3487
3488 @Override
3489 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003490 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3491 Preconditions.checkNotNull(pkg);
3492 Preconditions.checkNotNull(user);
3493 verifyPrivilegedListener(token, user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003494
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003495 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
3496 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003497 }
3498
3499 @Override
3500 public ParceledListSlice<NotificationChannelGroup>
3501 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003502 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3503 Preconditions.checkNotNull(pkg);
3504 Preconditions.checkNotNull(user);
3505 verifyPrivilegedListener(token, user);
3506
3507 List<NotificationChannelGroup> groups = new ArrayList<>();
3508 groups.addAll(mRankingHelper.getNotificationChannelGroups(
3509 pkg, getUidForPackageAndUser(pkg, user)));
3510 return new ParceledListSlice<>(groups);
3511 }
3512
3513 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003514 ManagedServiceInfo info;
3515 synchronized (mNotificationLock) {
3516 info = mListeners.checkServiceTokenLocked(token);
3517 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003518 if (!hasCompanionDevice(info)) {
3519 throw new SecurityException(info + " does not have access");
3520 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003521 if (!info.enabledAndUserMatches(user.getIdentifier())) {
3522 throw new SecurityException(info + " does not have access");
3523 }
3524 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003525
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003526 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3527 int uid = 0;
3528 long identity = Binder.clearCallingIdentity();
3529 try {
3530 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3531 } finally {
3532 Binder.restoreCallingIdentity(identity);
3533 }
3534 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003535 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003536
3537 @Override
3538 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3539 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3540 throws RemoteException {
3541 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3542 }
John Spurlock1fc476d2015-04-14 16:05:20 -04003543 };
John Spurlocka4294292014-03-24 18:02:32 -04003544
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003545 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3546 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003547 return;
3548 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003549 if (adjustment.getSignals() != null) {
3550 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003551 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003552 }
3553 }
3554
Julia Reynolds88860ce2017-06-01 16:55:49 -04003555 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003556 void addAutogroupKeyLocked(String key) {
3557 NotificationRecord r = mNotificationsByKey.get(key);
3558 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003559 return;
3560 }
Julia Reynolds51710712017-07-19 13:48:07 -04003561 if (r.sbn.getOverrideGroupKey() == null) {
3562 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3563 EventLogTags.writeNotificationAutogrouped(key);
3564 mRankingHandler.requestSort();
3565 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003566 }
3567
Julia Reynolds88860ce2017-06-01 16:55:49 -04003568 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003569 void removeAutogroupKeyLocked(String key) {
3570 NotificationRecord r = mNotificationsByKey.get(key);
3571 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003572 return;
3573 }
Julia Reynolds51710712017-07-19 13:48:07 -04003574 if (r.sbn.getOverrideGroupKey() != null) {
3575 addAutoGroupAdjustment(r, null);
3576 EventLogTags.writeNotificationUnautogrouped(key);
3577 mRankingHandler.requestSort();
3578 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003579 }
3580
3581 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3582 Bundle signals = new Bundle();
3583 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3584 Adjustment adjustment =
3585 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3586 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003587 }
3588
3589 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04003590 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04003591 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3592 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3593 if (summaries != null && summaries.containsKey(pkg)) {
3594 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003595 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04003596 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04003597 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003598 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003599 }
3600 }
3601 }
3602
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003603 @GuardedBy("mNotificationLock")
3604 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3605 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3606 return summaries != null && summaries.containsKey(sbn.getPackageName());
3607 }
3608
Julia Reynoldse46bb372016-03-17 11:05:58 -04003609 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04003610 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3611 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003612 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003613 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3614 if (notificationRecord == null) {
3615 // The notification could have been cancelled again already. A successive
3616 // adjustment will post a summary if needed.
3617 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003618 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003619 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3620 userId = adjustedSbn.getUser().getIdentifier();
3621 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3622 if (summaries == null) {
3623 summaries = new ArrayMap<>();
3624 }
3625 mAutobundledSummaries.put(userId, summaries);
3626 if (!summaries.containsKey(pkg)) {
3627 // Add summary
3628 final ApplicationInfo appInfo =
3629 adjustedSbn.getNotification().extras.getParcelable(
3630 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3631 final Bundle extras = new Bundle();
3632 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003633 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04003634 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003635 new Notification.Builder(getContext(), channelId)
3636 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04003637 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04003638 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04003639 .setGroup(GroupHelper.AUTOGROUP_KEY)
3640 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3641 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3642 .setColor(adjustedSbn.getNotification().color)
3643 .setLocalOnly(true)
3644 .build();
3645 summaryNotification.extras.putAll(extras);
3646 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3647 if (appIntent != null) {
3648 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3649 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3650 }
3651 final StatusBarNotification summarySbn =
3652 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003653 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003654 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04003655 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3656 adjustedSbn.getInitialPid(), summaryNotification,
3657 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3658 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05003659 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003660 notificationRecord.getChannel());
Rohan Shah590e1b22018-04-10 23:48:47 -04003661 summaryRecord.setIsAppImportanceLocked(
3662 notificationRecord.getIsAppImportanceLocked());
Julia Reynolds8f488d32016-10-14 10:59:01 -04003663 summaries.put(pkg, summarySbn.getKey());
3664 }
3665 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003666 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04003667 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003668 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04003669 }
3670 }
3671
John Spurlock32fe4c62014-10-02 12:16:02 -04003672 private String disableNotificationEffects(NotificationRecord record) {
3673 if (mDisableNotificationEffects) {
3674 return "booleanState";
3675 }
3676 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3677 return "listenerHints";
3678 }
3679 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3680 return "callState";
3681 }
3682 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04003683 };
3684
Kweku Adams887f09c2017-11-13 17:12:20 -08003685 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
Chris Wrene4b38802015-07-07 15:54:19 -04003686 JSONObject dump = new JSONObject();
3687 try {
3688 dump.put("service", "Notification Manager");
Chris Wrenacf424a2016-03-15 12:48:55 -04003689 dump.put("bans", mRankingHelper.dumpBansJson(filter));
3690 dump.put("ranking", mRankingHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003691 dump.put("stats", mUsageStats.dumpJson(filter));
Julia Reynoldsd373d782017-03-03 13:32:57 -05003692 dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003693 } catch (JSONException e) {
3694 e.printStackTrace();
3695 }
3696 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04003697 }
3698
Kweku Adams887f09c2017-11-13 17:12:20 -08003699 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003700 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3701 synchronized (mNotificationLock) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003702 int N = mNotificationList.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003703 for (int i = 0; i < N; i++) {
3704 final NotificationRecord nr = mNotificationList.get(i);
3705 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3706 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3707 NotificationRecordProto.POSTED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003708 }
3709 N = mEnqueuedNotifications.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003710 for (int i = 0; i < N; i++) {
3711 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3712 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3713 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3714 NotificationRecordProto.ENQUEUED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003715 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003716 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3717 N = snoozed.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003718 for (int i = 0; i < N; i++) {
3719 final NotificationRecord nr = snoozed.get(i);
3720 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3721 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3722 NotificationRecordProto.SNOOZED);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003723 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003724
Kweku Adams93304b62017-09-20 17:03:00 -07003725 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3726 mZenModeHelper.dump(proto);
3727 for (ComponentName suppressor : mEffectsSuppressors) {
Kweku Adams99546332018-01-24 17:03:50 -08003728 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
Kweku Adams93304b62017-09-20 17:03:00 -07003729 }
3730 proto.end(zenLog);
3731
3732 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
3733 mListeners.dump(proto, filter);
3734 proto.end(listenersToken);
3735
3736 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
3737
3738 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
3739 long effectsToken = proto.start(
3740 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
3741
3742 proto.write(
3743 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
3744 final ArraySet<ManagedServiceInfo> listeners =
3745 mListenersDisablingEffects.valueAt(i);
3746 for (int j = 0; j < listeners.size(); j++) {
3747 final ManagedServiceInfo listener = listeners.valueAt(i);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08003748 listener.writeToProto(proto, ListenersDisablingEffectsProto.LISTENERS, null);
Kweku Adams93304b62017-09-20 17:03:00 -07003749 }
3750
3751 proto.end(effectsToken);
3752 }
3753
3754 long assistantsToken = proto.start(
3755 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
3756 mAssistants.dump(proto, filter);
3757 proto.end(assistantsToken);
3758
3759 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
3760 mConditionProviders.dump(proto, filter);
3761 proto.end(conditionsToken);
Kweku Adams62b42242017-09-25 12:54:02 -07003762
3763 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
3764 mRankingHelper.dump(proto, filter);
3765 proto.end(rankingToken);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003766 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003767
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003768 proto.flush();
3769 }
3770
Vishnu Naire3e4d252018-03-01 11:26:57 -08003771 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
3772 synchronized (mNotificationLock) {
3773 int N;
3774 N = mNotificationList.size();
3775 if (N > 0) {
3776 pw.println(" Notification List:");
3777 for (int i = 0; i < N; i++) {
3778 final NotificationRecord nr = mNotificationList.get(i);
3779 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3780 nr.dump(pw, " ", getContext(), filter.redact);
3781 }
3782 pw.println(" ");
3783 }
3784 }
3785 }
3786
Kweku Adams887f09c2017-11-13 17:12:20 -08003787 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
John Spurlock25e2d242014-06-27 13:58:23 -04003788 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04003789 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003790 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04003791 }
3792 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08003793 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003794 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003795
John Spurlock50806fc2014-07-15 10:22:02 -04003796 if (!zenOnly) {
3797 synchronized (mToastQueue) {
3798 N = mToastQueue.size();
3799 if (N > 0) {
3800 pw.println(" Toast Queue:");
3801 for (int i=0; i<N; i++) {
3802 mToastQueue.get(i).dump(pw, " ", filter);
3803 }
3804 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003805 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003806 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003807 }
3808
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003809 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04003810 if (!zenOnly) {
Vishnu Naire3e4d252018-03-01 11:26:57 -08003811 // Priority filters are only set when called via bugreport. If set
3812 // skip sections that are part of the critical section.
3813 if (!filter.normalPriority) {
3814 dumpNotificationRecords(pw, filter);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003815 }
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003816 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003817 N = mLights.size();
3818 if (N > 0) {
3819 pw.println(" Lights List:");
3820 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05003821 if (i == N - 1) {
3822 pw.print(" > ");
3823 } else {
3824 pw.print(" ");
3825 }
3826 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04003827 }
3828 pw.println(" ");
3829 }
John Spurlockcb566aa2014-08-03 22:58:28 -04003830 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
3831 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05003832 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3833 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003834 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04003835 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04003836 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04003837 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04003838 }
3839 pw.println(" mArchive=" + mArchive.toString());
3840 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003841 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04003842 while (iter.hasNext()) {
3843 final StatusBarNotification sbn = iter.next();
3844 if (filter != null && !filter.matches(sbn)) continue;
3845 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003846 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04003847 if (iter.hasNext()) pw.println(" ...");
3848 break;
3849 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003850 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003851
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003852 if (!zenOnly) {
3853 N = mEnqueuedNotifications.size();
3854 if (N > 0) {
3855 pw.println(" Enqueued Notification List:");
3856 for (int i = 0; i < N; i++) {
3857 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3858 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3859 nr.dump(pw, " ", getContext(), filter.redact);
3860 }
3861 pw.println(" ");
3862 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003863
3864 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003865 }
3866 }
3867
John Spurlock50806fc2014-07-15 10:22:02 -04003868 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04003869 pw.println("\n Ranking Config:");
3870 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04003871
John Spurlock50806fc2014-07-15 10:22:02 -04003872 pw.println("\n Notification listeners:");
3873 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003874 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3875 pw.print(" mListenersDisablingEffects: (");
3876 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04003877 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003878 final int hint = mListenersDisablingEffects.keyAt(i);
3879 if (i > 0) pw.print(';');
3880 pw.print("hint[" + hint + "]:");
3881
3882 final ArraySet<ManagedServiceInfo> listeners =
3883 mListenersDisablingEffects.valueAt(i);
3884 final int listenerSize = listeners.size();
3885
3886 for (int j = 0; j < listenerSize; j++) {
3887 if (i > 0) pw.print(',');
3888 final ManagedServiceInfo listener = listeners.valueAt(i);
Julia Reynolds1f580572018-04-27 14:48:36 -04003889 if (listener != null) {
3890 pw.print(listener.component);
3891 }
Bryce Lee7219ada2016-04-08 10:54:23 -07003892 }
John Spurlock1fa865f2014-07-21 14:56:39 -04003893 }
3894 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05003895 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003896 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04003897 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003898
Julia Reynolds520df6e2017-02-13 09:05:10 -05003899 if (!filter.filtered || zenOnly) {
3900 pw.println("\n Zen Mode:");
3901 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3902 mZenModeHelper.dump(pw, " ");
3903
3904 pw.println("\n Zen Log:");
3905 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003906 }
3907
John Spurlocke77bb362014-04-26 10:24:59 -04003908 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04003909 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02003910
3911 pw.println("\n Group summaries:");
3912 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3913 NotificationRecord r = entry.getValue();
3914 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3915 if (mNotificationsByKey.get(r.getKey()) != r) {
3916 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04003917 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02003918 }
3919 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003920
3921 if (!zenOnly) {
3922 pw.println("\n Usage Stats:");
3923 mUsageStats.dump(pw, " ", filter);
3924 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003925 }
3926 }
3927
Adam Lesinski182f73f2013-12-05 16:48:06 -08003928 /**
3929 * The private API only accessible to the system process.
3930 */
3931 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3932 @Override
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04003933 public NotificationChannel getNotificationChannel(String pkg, int uid, String
3934 channelId) {
3935 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
3936 }
3937
3938 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003939 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003940 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003941 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003942 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003943 }
Christoph Studer365e4c32014-09-18 20:35:36 +02003944
3945 @Override
3946 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3947 int userId) {
3948 checkCallerIsSystem();
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003949 mHandler.post(new Runnable() {
3950 @Override
3951 public void run() {
3952 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003953 removeForegroundServiceFlagByListLocked(
3954 mEnqueuedNotifications, pkg, notificationId, userId);
3955 removeForegroundServiceFlagByListLocked(
3956 mNotificationList, pkg, notificationId, userId);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003957 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003958 }
3959 });
3960 }
3961
Julia Reynolds88860ce2017-06-01 16:55:49 -04003962 @GuardedBy("mNotificationLock")
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003963 private void removeForegroundServiceFlagByListLocked(
Julia Reynolds88860ce2017-06-01 16:55:49 -04003964 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3965 int userId) {
3966 NotificationRecord r = findNotificationByListLocked(
3967 notificationList, pkg, null, notificationId, userId);
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003968 if (r == null) {
3969 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02003970 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003971 StatusBarNotification sbn = r.sbn;
3972 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3973 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3974 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3975 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3976 sbn.getNotification().flags =
Julia Reynoldse5c60452018-04-30 14:41:36 -04003977 (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003978 mRankingHelper.sort(mNotificationList);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06003979 mListeners.notifyPostedLocked(r, r);
Christoph Studer365e4c32014-09-18 20:35:36 +02003980 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003981 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003982
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003983 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04003984 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003985 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04003986 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08003987 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3988 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04003989 }
John Spurlock7340fc82014-04-24 18:50:12 -04003990 checkCallerIsSystemOrSameApp(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003991
Scott Greenwald9b05c612013-06-25 23:44:05 -04003992 final int userId = ActivityManager.handleIncomingUser(callingPid,
3993 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
Jeff Sharkey65c4a2b2012-09-25 17:22:27 -07003994 final UserHandle user = new UserHandle(userId);
Dianne Hackborn41203752012-08-31 14:05:51 -07003995
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003996 if (pkg == null || notification == null) {
3997 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3998 + " id=" + id + " notification=" + notification);
3999 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004000
4001 // The system can post notifications for any package, let us resolve that.
4002 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
4003
Julia Reynoldse46bb372016-03-17 11:05:58 -04004004 // Fix the notification as best we can.
4005 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004006 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06004007 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
Julia Reynoldse0d711f2017-09-01 08:50:47 -04004008 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
Julia Reynoldse071abd2017-03-22 10:52:11 -04004009 Notification.addFieldsFromContext(ai, notification);
Julia Reynolds4db59552017-06-30 13:34:01 -04004010
4011 int canColorize = mPackageManagerClient.checkPermission(
4012 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
4013 if (canColorize == PERMISSION_GRANTED) {
4014 notification.flags |= Notification.FLAG_CAN_COLORIZE;
4015 } else {
4016 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
4017 }
4018
Julia Reynoldse46bb372016-03-17 11:05:58 -04004019 } catch (NameNotFoundException e) {
4020 Slog.e(TAG, "Cannot create a context for sending app", e);
4021 return;
4022 }
4023
Chris Wren888b7a82016-06-17 15:47:19 -04004024 mUsageStats.registerEnqueuedByApp(pkg);
4025
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004026 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04004027 String channelId = notification.getChannelId();
4028 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
4029 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05004030 }
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004031 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004032 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004033 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004034 final String noChannelStr = "No Channel found for "
4035 + "pkg=" + pkg
4036 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04004037 + ", id=" + id
4038 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004039 + ", opPkg=" + opPkg
4040 + ", callingUid=" + callingUid
4041 + ", userId=" + userId
4042 + ", incomingUserId=" + incomingUserId
4043 + ", notificationUid=" + notificationUid
4044 + ", notification=" + notification;
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004045 Log.e(TAG, noChannelStr);
Beverly5d4564b2018-04-10 20:09:23 -04004046 boolean appNotificationsOff = mRankingHelper.getImportance(pkg, notificationUid)
4047 == NotificationManager.IMPORTANCE_NONE;
4048
4049 if (!appNotificationsOff) {
4050 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
4051 "Failed to post notification on channel \"" + channelId + "\"\n" +
4052 "See log for more details");
4053 }
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004054 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004055 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004056
Chris Wrena61f1792016-08-04 11:24:42 -04004057 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004058 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004059 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004060 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Rohan Shah590e1b22018-04-10 23:48:47 -04004061 r.setIsAppImportanceLocked(mRankingHelper.getIsAppImportanceLocked(pkg, callingUid));
Chris Wrena61f1792016-08-04 11:24:42 -04004062
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004063 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4064 final boolean fgServiceShown = channel.isFgServiceShown();
4065 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
4066 || !fgServiceShown)
4067 && (r.getImportance() == IMPORTANCE_MIN
4068 || r.getImportance() == IMPORTANCE_NONE)) {
4069 // Increase the importance of foreground service notifications unless the user had
4070 // an opinion otherwise (and the channel hasn't yet shown a fg service).
4071 if (TextUtils.isEmpty(channelId)
4072 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4073 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
4074 } else {
4075 channel.setImportance(IMPORTANCE_LOW);
4076 if (!fgServiceShown) {
4077 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
4078 channel.setFgServiceShown(true);
4079 }
4080 mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
4081 r.updateNotificationChannel(channel);
4082 }
4083 } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
4084 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4085 channel.setFgServiceShown(true);
Julia Reynolds8617e4e2017-09-18 16:52:37 -04004086 r.updateNotificationChannel(channel);
4087 }
4088 }
4089
Julia Reynolds5e702192017-08-18 09:22:40 -04004090 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
4091 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004092 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07004093 }
4094
Felipe Lemedd85da62016-06-28 11:29:54 -07004095 // Whitelist pending intents.
4096 if (notification.allPendingIntents != null) {
4097 final int intentCount = notification.allPendingIntents.size();
4098 if (intentCount > 0) {
4099 final ActivityManagerInternal am = LocalServices
4100 .getService(ActivityManagerInternal.class);
4101 final long duration = LocalServices.getService(
4102 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
4103 for (int i = 0; i < intentCount; i++) {
4104 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4105 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07004106 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4107 WHITELIST_TOKEN, duration);
Felipe Lemedd85da62016-06-28 11:29:54 -07004108 }
4109 }
4110 }
4111 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07004112
Chris Wren47633422016-01-22 09:56:59 -05004113 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004114 }
4115
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04004116 private void doChannelWarningToast(CharSequence toastText) {
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04004117 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04004118 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04004119 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4120 if (warningEnabled) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04004121 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
Geoffrey Pitsch5bdddbd2017-05-26 10:50:05 -04004122 Toast.LENGTH_SHORT);
Geoffrey Pitschd34c1872017-05-04 16:02:15 -04004123 toast.show();
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004124 }
4125 }
4126
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004127 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
4128 // The system can post notifications on behalf of any package it wants
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004129 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004130 try {
4131 return getContext().getPackageManager()
4132 .getPackageUidAsUser(opPackageName, userId);
4133 } catch (NameNotFoundException e) {
4134 /* ignore */
4135 }
4136 }
4137 return callingUid;
4138 }
4139
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004140 /**
4141 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4142 *
4143 * Has side effects.
4144 */
4145 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04004146 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004147 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004148 final boolean isSystemNotification =
4149 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004150 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
4151
4152 // Limit the number of notifications that any given package except the android
4153 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
4154 if (!isSystemNotification && !isNotificationFromListener) {
4155 synchronized (mNotificationLock) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004156 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
4157 // Ephemeral apps have some special constraints for notifications.
4158 // They are not allowed to create new notifications however they are allowed to
4159 // update notifications created by the system (e.g. a foreground service
4160 // notification).
4161 throw new SecurityException("Instant app " + pkg
4162 + " cannot create notifications");
4163 }
4164
4165 // rate limit updates that aren't completed progress notifications
4166 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04004167 && !r.getNotification().hasCompletedProgress()
4168 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004169
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004170 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
4171 if (appEnqueueRate > mMaxPackageEnqueueRate) {
4172 mUsageStats.registerOverRateQuota(pkg);
4173 final long now = SystemClock.elapsedRealtime();
4174 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
4175 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04004176 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004177 mLastOverRateLogTime = now;
4178 }
4179 return false;
4180 }
4181 }
4182
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004183 // limit the number of outstanding notificationrecords an app can have
4184 int count = getNotificationCountLocked(pkg, userId, id, tag);
4185 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
4186 mUsageStats.registerOverCountQuota(pkg);
4187 Slog.e(TAG, "Package has already posted or enqueued " + count
4188 + " notifications. Not showing more. package=" + pkg);
4189 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004190 }
4191 }
4192 }
4193
4194 // snoozed apps
4195 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05004196 MetricsLogger.action(r.getLogMaker()
4197 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
4198 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004199 if (DBG) {
4200 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
4201 }
4202 mSnoozeHelper.update(userId, r);
4203 savePolicyFile();
4204 return false;
4205 }
4206
4207
4208 // blocked apps
4209 if (isBlocked(r, mUsageStats)) {
4210 return false;
4211 }
4212
4213 return true;
4214 }
4215
Andreas Gampea36dc622018-02-05 17:19:22 -08004216 @GuardedBy("mNotificationLock")
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004217 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
4218 String excludedTag) {
4219 int count = 0;
4220 final int N = mNotificationList.size();
4221 for (int i = 0; i < N; i++) {
4222 final NotificationRecord existing = mNotificationList.get(i);
4223 if (existing.sbn.getPackageName().equals(pkg)
4224 && existing.sbn.getUserId() == userId) {
4225 if (existing.sbn.getId() == excludedId
4226 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
4227 continue;
4228 }
4229 count++;
4230 }
4231 }
4232 final int M = mEnqueuedNotifications.size();
4233 for (int i = 0; i < M; i++) {
4234 final NotificationRecord existing = mEnqueuedNotifications.get(i);
4235 if (existing.sbn.getPackageName().equals(pkg)
4236 && existing.sbn.getUserId() == userId) {
4237 count++;
4238 }
4239 }
4240 return count;
4241 }
4242
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004243 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
4244 final String pkg = r.sbn.getPackageName();
4245 final int callingUid = r.sbn.getUid();
4246
4247 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
4248 if (isPackageSuspended) {
4249 Slog.e(TAG, "Suppressing notification from package due to package "
4250 + "suspended by administrator.");
4251 usageStats.registerSuspendedByAdmin(r);
4252 return isPackageSuspended;
4253 }
Julia Reynolds4da79702017-06-01 11:06:10 -04004254 final boolean isBlocked =
Julia Reynolds005c8b92017-08-24 10:35:53 -04004255 mRankingHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
4256 || mRankingHelper.getImportance(pkg, callingUid)
4257 == NotificationManager.IMPORTANCE_NONE
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04004258 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004259 if (isBlocked) {
4260 Slog.e(TAG, "Suppressing notification from package by user request.");
4261 usageStats.registerBlocked(r);
4262 }
4263 return isBlocked;
4264 }
4265
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004266 protected class SnoozeNotificationRunnable implements Runnable {
4267 private final String mKey;
4268 private final long mDuration;
4269 private final String mSnoozeCriterionId;
4270
4271 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
4272 mKey = key;
4273 mDuration = duration;
4274 mSnoozeCriterionId = snoozeCriterionId;
4275 }
4276
4277 @Override
4278 public void run() {
4279 synchronized (mNotificationLock) {
4280 final NotificationRecord r = findNotificationByKeyLocked(mKey);
4281 if (r != null) {
4282 snoozeLocked(r);
4283 }
4284 }
4285 }
4286
Julia Reynolds88860ce2017-06-01 16:55:49 -04004287 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004288 void snoozeLocked(NotificationRecord r) {
4289 if (r.sbn.isGroup()) {
4290 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
4291 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
4292 if (r.getNotification().isGroupSummary()) {
4293 // snooze summary and all children
4294 for (int i = 0; i < groupNotifications.size(); i++) {
4295 snoozeNotificationLocked(groupNotifications.get(i));
4296 }
4297 } else {
4298 // if there is a valid summary for this group, and we are snoozing the only
4299 // child, also snooze the summary
4300 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
4301 if (groupNotifications.size() != 2) {
4302 snoozeNotificationLocked(r);
4303 } else {
4304 // snooze summary and the one child
4305 for (int i = 0; i < groupNotifications.size(); i++) {
4306 snoozeNotificationLocked(groupNotifications.get(i));
4307 }
4308 }
4309 } else {
4310 snoozeNotificationLocked(r);
4311 }
4312 }
4313 } else {
4314 // just snooze the one notification
4315 snoozeNotificationLocked(r);
4316 }
4317 }
4318
Julia Reynolds88860ce2017-06-01 16:55:49 -04004319 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004320 void snoozeNotificationLocked(NotificationRecord r) {
4321 MetricsLogger.action(r.getLogMaker()
4322 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4323 .setType(MetricsEvent.TYPE_CLOSE)
Chris Wren21a2e722017-10-02 17:44:53 -04004324 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
4325 mDuration)
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004326 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4327 mSnoozeCriterionId == null ? 0 : 1));
Julia Reynolds0839c022017-06-15 15:24:01 -04004328 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004329 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004330 updateLightsLocked();
4331 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004332 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004333 mSnoozeHelper.snooze(r);
4334 } else {
4335 mSnoozeHelper.snooze(r, mDuration);
4336 }
Julia Reynolds503ed942017-10-04 16:04:56 -04004337 r.recordSnoozed();
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004338 savePolicyFile();
4339 }
4340 }
4341
Julia Reynoldsbaff4002016-12-15 11:34:26 -05004342 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05004343 private final NotificationRecord r;
4344 private final int userId;
4345
4346 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
4347 this.userId = userId;
4348 this.r = r;
4349 };
4350
4351 @Override
4352 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004353 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05004354 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05004355 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05004356
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004357 final StatusBarNotification n = r.sbn;
4358 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
4359 NotificationRecord old = mNotificationsByKey.get(n.getKey());
4360 if (old != null) {
4361 // Retain ranking information from previous record
4362 r.copyRankingInformation(old);
4363 }
4364
4365 final int callingUid = n.getUid();
4366 final int callingPid = n.getInitialPid();
4367 final Notification notification = n.getNotification();
4368 final String pkg = n.getPackageName();
4369 final int id = n.getId();
4370 final String tag = n.getTag();
4371
4372 // Handle grouped notifications and bail out early if we
4373 // can to avoid extracting signals.
4374 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
4375
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004376 // if this is a group child, unsnooze parent summary
4377 if (n.isGroup() && notification.isGroupChild()) {
4378 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
4379 }
4380
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004381 // This conditional is a dirty hack to limit the logging done on
4382 // behalf of the download manager without affecting other apps.
4383 if (!pkg.equals("com.android.providers.downloads")
4384 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
4385 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05004386 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004387 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05004388 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004389 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
4390 pkg, id, tag, userId, notification.toString(),
4391 enqueueStatus);
4392 }
Chris Wren6676dab2016-12-21 18:26:27 -05004393
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004394 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05004395
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004396 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004397 if (mAssistants.isEnabled()) {
4398 mAssistants.onNotificationEnqueued(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004399 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004400 DELAY_FOR_ASSISTANT_TIME);
4401 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004402 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004403 }
4404 }
4405 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004406 }
4407
Beverly5a20a5e2018-03-06 15:02:44 -05004408 @GuardedBy("mNotificationLock")
4409 private boolean isPackageSuspendedLocked(NotificationRecord r) {
4410 final String pkg = r.sbn.getPackageName();
4411 final int callingUid = r.sbn.getUid();
4412
4413 return isPackageSuspendedForUser(pkg, callingUid);
4414 }
4415
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004416 protected class PostNotificationRunnable implements Runnable {
4417 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004418
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004419 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004420 this.key = key;
4421 }
4422
4423 @Override
4424 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004425 synchronized (mNotificationLock) {
4426 try {
4427 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004428 int N = mEnqueuedNotifications.size();
4429 for (int i = 0; i < N; i++) {
4430 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4431 if (Objects.equals(key, enqueued.getKey())) {
4432 r = enqueued;
4433 break;
Chris Wren6676dab2016-12-21 18:26:27 -05004434 }
Chris Wren6676dab2016-12-21 18:26:27 -05004435 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004436 if (r == null) {
4437 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
4438 return;
4439 }
Beverly5a20a5e2018-03-06 15:02:44 -05004440
4441 r.setHidden(isPackageSuspendedLocked(r));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004442 NotificationRecord old = mNotificationsByKey.get(key);
4443 final StatusBarNotification n = r.sbn;
4444 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05004445 int index = indexOfNotificationLocked(n.getKey());
4446 if (index < 0) {
4447 mNotificationList.add(r);
4448 mUsageStats.registerPostedByApp(r);
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004449 r.setInterruptive(isVisuallyInterruptive(null, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004450 } else {
4451 old = mNotificationList.get(index);
4452 mNotificationList.set(index, r);
4453 mUsageStats.registerUpdatedByApp(r, old);
4454 // Make sure we don't lose the foreground service state.
4455 notification.flags |=
Julia Reynoldse5c60452018-04-30 14:41:36 -04004456 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
Chris Wren6676dab2016-12-21 18:26:27 -05004457 r.isUpdate = true;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04004458 r.setTextChanged(isVisuallyInterruptive(old, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004459 }
4460
4461 mNotificationsByKey.put(n.getKey(), r);
4462
4463 // Ensure if this is a foreground service that the proper additional
4464 // flags are set.
Julia Reynoldse5c60452018-04-30 14:41:36 -04004465 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
Chris Wren6676dab2016-12-21 18:26:27 -05004466 notification.flags |= Notification.FLAG_ONGOING_EVENT
4467 | Notification.FLAG_NO_CLEAR;
4468 }
4469
4470 applyZenModeLocked(r);
4471 mRankingHelper.sort(mNotificationList);
4472
4473 if (notification.getSmallIcon() != null) {
4474 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06004475 mListeners.notifyPostedLocked(r, old);
Julia Reynolds8aebf352017-06-26 11:35:33 -04004476 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
4477 mHandler.post(new Runnable() {
4478 @Override
4479 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04004480 mGroupHelper.onNotificationPosted(
4481 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04004482 }
4483 });
4484 }
Chris Wren6676dab2016-12-21 18:26:27 -05004485 } else {
4486 Slog.e(TAG, "Not posting notification without small icon: " + notification);
4487 if (old != null && !old.isCanceled) {
Beverly5a20a5e2018-03-06 15:02:44 -05004488 mListeners.notifyRemovedLocked(r,
Julia Reynolds503ed942017-10-04 16:04:56 -04004489 NotificationListenerService.REASON_ERROR, null);
Chris Wren6676dab2016-12-21 18:26:27 -05004490 mHandler.post(new Runnable() {
4491 @Override
4492 public void run() {
4493 mGroupHelper.onNotificationRemoved(n);
4494 }
4495 });
4496 }
4497 // ATTENTION: in a future release we will bail out here
4498 // so that we do not play sounds, show lights, etc. for invalid
4499 // notifications
4500 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
4501 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05004502 }
Chris Wren47633422016-01-22 09:56:59 -05004503
Beverly5a20a5e2018-03-06 15:02:44 -05004504 if (!r.isHidden()) {
4505 buzzBeepBlinkLocked(r);
4506 }
Julia Reynolds1fac86e2018-03-07 08:30:37 -05004507 maybeRecordInterruptionLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004508 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004509 int N = mEnqueuedNotifications.size();
4510 for (int i = 0; i < N; i++) {
4511 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4512 if (Objects.equals(key, enqueued.getKey())) {
4513 mEnqueuedNotifications.remove(i);
4514 break;
4515 }
4516 }
Chris Wren6676dab2016-12-21 18:26:27 -05004517 }
Chris Wren47633422016-01-22 09:56:59 -05004518 }
4519 }
4520 }
4521
Christoph Studer265c1052014-07-23 17:14:33 +02004522 /**
Julia Reynolds7217dc92018-03-07 12:12:09 -05004523 * If the notification differs enough visually, consider it a new interruptive notification.
4524 */
4525 @GuardedBy("mNotificationLock")
4526 @VisibleForTesting
4527 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004528 if (old == null) {
4529 if (DEBUG_INTERRUPTIVENESS) {
4530 Log.v(TAG, "INTERRUPTIVENESS: "
4531 + r.getKey() + " is interruptive: new notification");
4532 }
4533 return true;
4534 }
4535
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004536 if (r == null) {
4537 if (DEBUG_INTERRUPTIVENESS) {
4538 Log.v(TAG, "INTERRUPTIVENESS: "
4539 + r.getKey() + " is not interruptive: null");
4540 }
4541 return false;
4542 }
4543
Julia Reynolds7217dc92018-03-07 12:12:09 -05004544 Notification oldN = old.sbn.getNotification();
4545 Notification newN = r.sbn.getNotification();
Dan Sandler7d67bd42018-05-15 14:06:38 -04004546
Julia Reynolds7217dc92018-03-07 12:12:09 -05004547 if (oldN.extras == null || newN.extras == null) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004548 if (DEBUG_INTERRUPTIVENESS) {
4549 Log.v(TAG, "INTERRUPTIVENESS: "
4550 + r.getKey() + " is not interruptive: no extras");
4551 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004552 return false;
4553 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004554
4555 // Ignore visual interruptions from foreground services because users
4556 // consider them one 'session'. Count them for everything else.
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004557 if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004558 if (DEBUG_INTERRUPTIVENESS) {
4559 Log.v(TAG, "INTERRUPTIVENESS: "
4560 + r.getKey() + " is not interruptive: foreground service");
4561 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04004562 return false;
4563 }
4564
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04004565 // Ignore summary updates because we don't display most of the information.
4566 if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
4567 if (DEBUG_INTERRUPTIVENESS) {
4568 Log.v(TAG, "INTERRUPTIVENESS: "
4569 + r.getKey() + " is not interruptive: summary");
4570 }
4571 return false;
4572 }
4573
Dan Sandler7d67bd42018-05-15 14:06:38 -04004574 final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
4575 final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
4576 if (!Objects.equals(oldTitle, newTitle)) {
4577 if (DEBUG_INTERRUPTIVENESS) {
4578 Log.v(TAG, "INTERRUPTIVENESS: "
4579 + r.getKey() + " is interruptive: changed title");
4580 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)",
4581 oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
4582 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)",
4583 newTitle, newTitle.getClass(), newTitle.hashCode()));
4584 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004585 return true;
4586 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004587 // Do not compare Spannables (will always return false); compare unstyled Strings
4588 final String oldText = String.valueOf(oldN.extras.get(Notification.EXTRA_TEXT));
4589 final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT));
4590 if (!Objects.equals(oldText, newText)) {
4591 if (DEBUG_INTERRUPTIVENESS) {
4592 Log.v(TAG, "INTERRUPTIVENESS: "
4593 + r.getKey() + " is interruptive: changed text");
4594 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)",
4595 oldText, oldText.getClass(), oldText.hashCode()));
4596 Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)",
4597 newText, newText.getClass(), newText.hashCode()));
4598 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004599 return true;
4600 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004601 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
4602 if (DEBUG_INTERRUPTIVENESS) {
4603 Log.v(TAG, "INTERRUPTIVENESS: "
4604 + r.getKey() + " is interruptive: completed progress");
4605 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004606 return true;
4607 }
4608 // Actions
4609 if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004610 if (DEBUG_INTERRUPTIVENESS) {
4611 Log.v(TAG, "INTERRUPTIVENESS: "
4612 + r.getKey() + " is interruptive: changed actions");
4613 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004614 return true;
4615 }
4616
4617 try {
4618 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
4619 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
4620
4621 // Style based comparisons
4622 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004623 if (DEBUG_INTERRUPTIVENESS) {
4624 Log.v(TAG, "INTERRUPTIVENESS: "
4625 + r.getKey() + " is interruptive: styles differ");
4626 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004627 return true;
4628 }
4629
4630 // Remote views
4631 if (Notification.areRemoteViewsChanged(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04004632 if (DEBUG_INTERRUPTIVENESS) {
4633 Log.v(TAG, "INTERRUPTIVENESS: "
4634 + r.getKey() + " is interruptive: remoteviews differ");
4635 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05004636 return true;
4637 }
4638 } catch (Exception e) {
4639 Slog.w(TAG, "error recovering builder", e);
4640 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04004641
Julia Reynolds7217dc92018-03-07 12:12:09 -05004642 return false;
4643 }
4644
4645 /**
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05004646 * Keeps the last 5 packages that have notified, by user.
4647 */
4648 @GuardedBy("mNotificationLock")
4649 @VisibleForTesting
4650 protected void logRecentLocked(NotificationRecord r) {
4651 if (r.isUpdate) {
4652 return;
4653 }
4654 ArrayList<NotifyingApp> recentAppsForUser =
4655 mRecentApps.getOrDefault(r.getUser().getIdentifier(), new ArrayList<>(6));
4656 NotifyingApp na = new NotifyingApp()
4657 .setPackage(r.sbn.getPackageName())
4658 .setUid(r.sbn.getUid())
4659 .setLastNotified(r.sbn.getPostTime());
4660 // A new notification gets an app moved to the front of the list
4661 for (int i = recentAppsForUser.size() - 1; i >= 0; i--) {
4662 NotifyingApp naExisting = recentAppsForUser.get(i);
4663 if (na.getPackage().equals(naExisting.getPackage())
4664 && na.getUid() == naExisting.getUid()) {
4665 recentAppsForUser.remove(i);
4666 break;
4667 }
4668 }
4669 // time is always increasing, so always add to the front of the list
4670 recentAppsForUser.add(0, na);
4671 if (recentAppsForUser.size() > 5) {
4672 recentAppsForUser.remove(recentAppsForUser.size() -1);
4673 }
4674 mRecentApps.put(r.getUser().getIdentifier(), recentAppsForUser);
4675 }
4676
4677 /**
Christoph Studer265c1052014-07-23 17:14:33 +02004678 * Ensures that grouped notification receive their special treatment.
4679 *
4680 * <p>Cancels group children if the new notification causes a group to lose
4681 * its summary.</p>
4682 *
4683 * <p>Updates mSummaryByGroupKey.</p>
4684 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004685 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02004686 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
4687 int callingUid, int callingPid) {
4688 StatusBarNotification sbn = r.sbn;
4689 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07004690 if (n.isGroupSummary() && !sbn.isAppGroup()) {
4691 // notifications without a group shouldn't be a summary, otherwise autobundling can
4692 // lead to bugs
4693 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
4694 }
4695
Christoph Studer265c1052014-07-23 17:14:33 +02004696 String group = sbn.getGroupKey();
4697 boolean isSummary = n.isGroupSummary();
4698
4699 Notification oldN = old != null ? old.sbn.getNotification() : null;
4700 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
4701 boolean oldIsSummary = old != null && oldN.isGroupSummary();
4702
4703 if (oldIsSummary) {
4704 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
4705 if (removedSummary != old) {
4706 String removedKey =
4707 removedSummary != null ? removedSummary.getKey() : "<null>";
4708 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
4709 ", removed=" + removedKey);
4710 }
4711 }
4712 if (isSummary) {
4713 mSummaryByGroupKey.put(group, r);
4714 }
4715
4716 // Clear out group children of the old notification if the update
4717 // causes the group summary to go away. This happens when the old
4718 // notification was a summary and the new one isn't, or when the old
4719 // notification was a summary and its group key changed.
4720 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04004721 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
4722 null);
Christoph Studer265c1052014-07-23 17:14:33 +02004723 }
4724 }
4725
Chris Wren93bb8b82016-03-29 14:35:05 -04004726 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004727 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05004728 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04004729 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05004730 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4731 REQUEST_CODE_TIMEOUT,
4732 new Intent(ACTION_NOTIFICATION_TIMEOUT)
4733 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4734 .appendPath(record.getKey()).build())
4735 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4736 .putExtra(EXTRA_KEY, record.getKey()),
4737 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05004738 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04004739 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05004740 }
4741 }
4742
4743 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004744 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04004745 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04004746 boolean buzz = false;
4747 boolean beep = false;
4748 boolean blink = false;
4749
Chris Wrena3446562014-06-03 18:11:47 -04004750 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04004751 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04004752
4753 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04004754 final boolean aboveThreshold =
4755 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04004756
4757 // Remember if this notification already owns the notification channels.
4758 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4759 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04004760 // These are set inside the conditional if the notification is allowed to make noise.
4761 boolean hasValidVibrate = false;
4762 boolean hasValidSound = false;
Julia Reynolds94187562017-10-10 13:58:49 -04004763 boolean sentAccessibilityEvent = false;
4764 // If the notification will appear in the status bar, it should send an accessibility
4765 // event
4766 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4767 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4768 sentAccessibilityEvent = true;
4769 }
Chris Wrena3446562014-06-03 18:11:47 -04004770
Julia Reynolds76c096d2017-06-19 08:16:04 -04004771 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004772
Julia Reynolds76c096d2017-06-19 08:16:04 -04004773 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004774 Uri soundUri = record.getSound();
4775 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4776 long[] vibration = record.getVibration();
4777 // Demote sound to vibration if vibration missing & phone in vibration mode.
4778 if (vibration == null
4779 && hasValidSound
4780 && (mAudioManager.getRingerModeInternal()
Julia Reynolds85896572017-09-20 12:54:52 -04004781 == AudioManager.RINGER_MODE_VIBRATE)
4782 && mAudioManager.getStreamVolume(
4783 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004784 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04004785 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004786 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01004787
Julia Reynolds76c096d2017-06-19 08:16:04 -04004788 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
Julia Reynolds76c096d2017-06-19 08:16:04 -04004789 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004790 if (!sentAccessibilityEvent) {
4791 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4792 sentAccessibilityEvent = true;
4793 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004794 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04004795 if (hasValidSound) {
4796 mSoundNotificationKey = key;
4797 if (mInCall) {
4798 playInCallNotification();
4799 beep = true;
4800 } else {
4801 beep = playSound(record, soundUri);
4802 }
4803 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004804
Julia Reynolds7c96b582017-05-25 12:35:36 -04004805 final boolean ringerModeSilent =
4806 mAudioManager.getRingerModeInternal()
4807 == AudioManager.RINGER_MODE_SILENT;
4808 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
4809 mVibrateNotificationKey = key;
4810
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004811 buzz = playVibration(record, vibration, hasValidSound);
Julia Reynolds7c96b582017-05-25 12:35:36 -04004812 }
Chris Wrena3446562014-06-03 18:11:47 -04004813 }
4814 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004815 }
4816 // If a notification is updated to remove the actively playing sound or vibrate,
4817 // cancel that feedback now
4818 if (wasBeep && !hasValidSound) {
4819 clearSoundLocked();
4820 }
4821 if (wasBuzz && !hasValidVibrate) {
4822 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04004823 }
4824
4825 // light
4826 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04004827 boolean wasShowLights = mLights.remove(key);
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05004828 if (record.getLight() != null && aboveThreshold
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05004829 && ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) == 0)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04004830 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04004831 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04004832 if (mUseAttentionLight) {
4833 mAttentionLight.pulse();
4834 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004835 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04004836 } else if (wasShowLights) {
4837 updateLightsLocked();
4838 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004839 if (buzz || beep || blink) {
Julia Reynolds1fac86e2018-03-07 08:30:37 -05004840 record.setInterruptive(true);
Julia Reynolds445cfa82017-05-08 15:41:45 -04004841 MetricsLogger.action(record.getLogMaker()
4842 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4843 .setType(MetricsEvent.TYPE_OPEN)
4844 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4845 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04004846 }
Chris Wrena3446562014-06-03 18:11:47 -04004847 }
4848
Julia Reynolds88860ce2017-06-01 16:55:49 -04004849 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004850 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04004851 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004852 final Notification notification = record.getNotification();
4853 if(record.isUpdate
4854 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4855 return true;
4856 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004857
Julia Reynolds76c096d2017-06-19 08:16:04 -04004858 // muted by listener
4859 final String disableEffects = disableNotificationEffects(record);
4860 if (disableEffects != null) {
4861 ZenLog.traceDisableEffects(record, disableEffects);
4862 return true;
4863 }
4864
4865 // suppressed due to DND
4866 if (record.isIntercepted()) {
4867 return true;
4868 }
4869
4870 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004871 if (record.sbn.isGroup()) {
Julia Reynolds79dfdd62018-04-17 15:36:33 -04004872 if (notification.suppressAlertingDueToGrouping()) {
4873 return true;
4874 }
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004875 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004876
Julia Reynolds65b85cf2017-07-20 09:19:20 -04004877 // Suppressed for being too recently noisy
4878 final String pkg = record.sbn.getPackageName();
4879 if (mUsageStats.isAlertRateLimited(pkg)) {
4880 Slog.e(TAG, "Muting recently noisy " + record.getKey());
4881 return true;
4882 }
4883
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004884 return false;
4885 }
4886
Julia Reynolds0c299d42016-11-15 14:37:04 -05004887 private boolean playSound(final NotificationRecord record, Uri soundUri) {
4888 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
Jean-Michel Triviec2bb182018-03-23 18:04:00 -07004889 // play notifications if there is no user of exclusive audio focus
4890 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
4891 // VIBRATE ringer mode)
4892 if (!mAudioManager.isAudioFocusExclusive()
4893 && (mAudioManager.getStreamVolume(
4894 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05004895 final long identity = Binder.clearCallingIdentity();
4896 try {
4897 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4898 if (player != null) {
4899 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4900 + " with attributes " + record.getAudioAttributes());
4901 player.playAsync(soundUri, record.sbn.getUser(), looping,
4902 record.getAudioAttributes());
4903 return true;
4904 }
4905 } catch (RemoteException e) {
4906 } finally {
4907 Binder.restoreCallingIdentity(identity);
4908 }
4909 }
4910 return false;
4911 }
4912
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004913 private boolean playVibration(final NotificationRecord record, long[] vibration,
4914 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004915 // Escalate privileges so we can use the vibrator even if the
4916 // notifying app does not have the VIBRATE permission.
4917 long identity = Binder.clearCallingIdentity();
4918 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004919 final VibrationEffect effect;
4920 try {
4921 final boolean insistent =
4922 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4923 effect = VibrationEffect.createWaveform(
4924 vibration, insistent ? 0 : -1 /*repeatIndex*/);
4925 } catch (IllegalArgumentException e) {
4926 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4927 Arrays.toString(vibration));
4928 return false;
4929 }
4930 if (delayVibForSound) {
4931 new Thread(() -> {
4932 // delay the vibration by the same amount as the notification sound
4933 final int waitMs = mAudioManager.getFocusRampTimeMs(
4934 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
4935 record.getAudioAttributes());
4936 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
4937 try {
4938 Thread.sleep(waitMs);
4939 } catch (InterruptedException e) { }
4940 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4941 effect, record.getAudioAttributes());
4942 }).start();
4943 } else {
4944 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4945 effect, record.getAudioAttributes());
4946 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004947 return true;
4948 } finally{
4949 Binder.restoreCallingIdentity(identity);
4950 }
4951 }
4952
Julia Reynolds7c96b582017-05-25 12:35:36 -04004953 private boolean isNotificationForCurrentUser(NotificationRecord record) {
4954 final int currentUser;
4955 final long token = Binder.clearCallingIdentity();
4956 try {
4957 currentUser = ActivityManager.getCurrentUser();
4958 } finally {
4959 Binder.restoreCallingIdentity(token);
4960 }
4961 return (record.getUserId() == UserHandle.USER_ALL ||
4962 record.getUserId() == currentUser ||
4963 mUserProfiles.isCurrentProfile(record.getUserId()));
4964 }
4965
Beverly5d463b62017-07-26 14:13:40 -04004966 protected void playInCallNotification() {
Marta Białka39c992f2011-03-10 10:27:24 +01004967 new Thread() {
4968 @Override
4969 public void run() {
Beverly5d463b62017-07-26 14:13:40 -04004970 final long identity = Binder.clearCallingIdentity();
Marta Białka39c992f2011-03-10 10:27:24 +01004971 try {
Beverly5d463b62017-07-26 14:13:40 -04004972 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4973 if (player != null) {
luochaojiang50e5273c2018-04-16 16:55:03 +08004974 if (mCallNotificationToken != null) {
4975 player.stop(mCallNotificationToken);
4976 }
4977 mCallNotificationToken = new Binder();
4978 player.play(mCallNotificationToken, mInCallNotificationUri,
Beverly5d463b62017-07-26 14:13:40 -04004979 mInCallNotificationAudioAttributes,
4980 mInCallNotificationVolume, false);
Marta Białka39c992f2011-03-10 10:27:24 +01004981 }
Beverly5d463b62017-07-26 14:13:40 -04004982 } catch (RemoteException e) {
4983 } finally {
4984 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01004985 }
4986 }
4987 }.start();
4988 }
4989
Julia Reynolds88860ce2017-06-01 16:55:49 -04004990 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004991 void showNextToastLocked() {
4992 ToastRecord record = mToastQueue.get(0);
4993 while (record != null) {
4994 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
4995 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004996 record.callback.show(record.token);
Robert Carr997427342018-02-28 18:06:10 -08004997 scheduleDurationReachedLocked(record);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004998 return;
4999 } catch (RemoteException e) {
5000 Slog.w(TAG, "Object died trying to show notification " + record.callback
5001 + " in package " + record.pkg);
5002 // remove it from the list and let the process die
5003 int index = mToastQueue.indexOf(record);
5004 if (index >= 0) {
5005 mToastQueue.remove(index);
5006 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005007 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005008 if (mToastQueue.size() > 0) {
5009 record = mToastQueue.get(0);
5010 } else {
5011 record = null;
5012 }
5013 }
5014 }
5015 }
5016
Julia Reynolds88860ce2017-06-01 16:55:49 -04005017 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005018 void cancelToastLocked(int index) {
5019 ToastRecord record = mToastQueue.get(index);
5020 try {
5021 record.callback.hide();
5022 } catch (RemoteException e) {
5023 Slog.w(TAG, "Object died trying to hide notification " + record.callback
5024 + " in package " + record.pkg);
5025 // don't worry about this, we're about to remove it from
5026 // the list anyway
5027 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005028
5029 ToastRecord lastToast = mToastQueue.remove(index);
Robert Carr997427342018-02-28 18:06:10 -08005030
5031 mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
5032 DEFAULT_DISPLAY);
5033 // We passed 'false' for 'removeWindows' so that the client has time to stop
5034 // rendering (as hide above is a one-way message), otherwise we could crash
5035 // a client which was actively using a surface made from the token. However
5036 // we need to schedule a timeout to make sure the token is eventually killed
5037 // one way or another.
5038 scheduleKillTokenTimeout(lastToast.token);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005039
5040 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005041 if (mToastQueue.size() > 0) {
5042 // Show the next one. If the callback fails, this will remove
5043 // it from the list, so don't assume that the list hasn't changed
5044 // after this point.
5045 showNextToastLocked();
5046 }
5047 }
5048
Robert Carr997427342018-02-28 18:06:10 -08005049 void finishTokenLocked(IBinder t) {
5050 mHandler.removeCallbacksAndMessages(t);
5051 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
5052 // remaining surfaces as either the client has called finishToken indicating
5053 // it has successfully removed the views, or the client has timed out
5054 // at which point anything goes.
5055 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */,
5056 DEFAULT_DISPLAY);
5057 }
5058
Julia Reynolds88860ce2017-06-01 16:55:49 -04005059 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08005060 private void scheduleDurationReachedLocked(ToastRecord r)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005061 {
5062 mHandler.removeCallbacksAndMessages(r);
Robert Carr997427342018-02-28 18:06:10 -08005063 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005064 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
5065 mHandler.sendMessageDelayed(m, delay);
5066 }
5067
Robert Carr997427342018-02-28 18:06:10 -08005068 private void handleDurationReached(ToastRecord record)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005069 {
5070 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
5071 synchronized (mToastQueue) {
5072 int index = indexOfToastLocked(record.pkg, record.callback);
5073 if (index >= 0) {
5074 cancelToastLocked(index);
5075 }
5076 }
5077 }
5078
Julia Reynolds88860ce2017-06-01 16:55:49 -04005079 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08005080 private void scheduleKillTokenTimeout(IBinder token)
5081 {
5082 mHandler.removeCallbacksAndMessages(token);
5083 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, token);
Robert Carr3406d462018-03-15 16:19:07 -07005084 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
Robert Carr997427342018-02-28 18:06:10 -08005085 }
5086
5087 private void handleKillTokenTimeout(IBinder token)
5088 {
5089 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + token);
5090 synchronized (mToastQueue) {
5091 finishTokenLocked(token);
5092 }
5093 }
5094
5095 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005096 int indexOfToastLocked(String pkg, ITransientNotification callback)
5097 {
5098 IBinder cbak = callback.asBinder();
5099 ArrayList<ToastRecord> list = mToastQueue;
5100 int len = list.size();
5101 for (int i=0; i<len; i++) {
5102 ToastRecord r = list.get(i);
Beverly Tai98efc792018-06-11 14:50:36 +00005103 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08005104 return i;
5105 }
5106 }
5107 return -1;
5108 }
5109
Julia Reynolds88860ce2017-06-01 16:55:49 -04005110 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005111 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005112 {
5113 int toastCount = 0; // toasts from this pid
5114 ArrayList<ToastRecord> list = mToastQueue;
5115 int N = list.size();
5116 for (int i=0; i<N; i++) {
5117 ToastRecord r = list.get(i);
5118 if (r.pid == pid) {
5119 toastCount++;
5120 }
5121 }
5122 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07005123 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08005124 } catch (RemoteException e) {
5125 // Shouldn't happen.
5126 }
5127 }
5128
Chris Wrenf9536642014-04-17 10:01:54 -04005129 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005130 if (!(message.obj instanceof RankingReconsideration)) return;
5131 RankingReconsideration recon = (RankingReconsideration) message.obj;
5132 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04005133 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005134 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005135 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
5136 if (record == null) {
5137 return;
Chris Wrenf9536642014-04-17 10:01:54 -04005138 }
Chris Wren333a61c2014-05-28 16:40:57 -04005139 int indexBefore = findNotificationRecordIndexLocked(record);
5140 boolean interceptBefore = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005141 float contactAffinityBefore = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005142 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04005143 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04005144 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04005145 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04005146 int indexAfter = findNotificationRecordIndexLocked(record);
5147 boolean interceptAfter = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005148 float contactAffinityAfter = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005149 int visibilityAfter = record.getPackageVisibilityOverride();
5150 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
5151 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005152 if (interceptBefore && !interceptAfter
5153 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
Chris Wrena3446562014-06-03 18:11:47 -04005154 buzzBeepBlinkLocked(record);
5155 }
Chris Wrenf9536642014-04-17 10:01:54 -04005156 }
Chris Wren333a61c2014-05-28 16:40:57 -04005157 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005158 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04005159 }
5160 }
5161
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005162 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04005163 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005164 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04005165 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005166 // Any field that can change via one of the extractors needs to be added here.
5167 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005168 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05005169 boolean[] showBadges = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005170 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
5171 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
5172 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
5173 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Julia Reynolds503ed942017-10-04 16:04:56 -04005174 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005175 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
Chris Wren54bbef42014-07-09 18:37:56 -04005176 for (int i = 0; i < N; i++) {
5177 final NotificationRecord r = mNotificationList.get(i);
5178 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005179 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05005180 showBadges[i] = r.canShowBadge();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005181 channelBefore.add(r.getChannel());
5182 groupKeyBefore.add(r.getGroupKey());
5183 overridePeopleBefore.add(r.getPeopleOverride());
5184 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Julia Reynolds503ed942017-10-04 16:04:56 -04005185 userSentimentBefore.add(r.getUserSentiment());
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005186 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
Chris Wren54bbef42014-07-09 18:37:56 -04005187 mRankingHelper.extractSignals(r);
5188 }
Chris Wren19a02b02015-12-22 10:34:22 -05005189 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04005190 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005191 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005192 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05005193 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005194 || showBadges[i] != r.canShowBadge()
5195 || !Objects.equals(channelBefore.get(i), r.getChannel())
5196 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
5197 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
Julia Reynolds503ed942017-10-04 16:04:56 -04005198 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005199 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
5200 || !Objects.equals(suppressVisuallyBefore.get(i),
5201 r.getSuppressedVisualEffects())) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005202 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04005203 return;
5204 }
5205 }
5206 }
5207 }
5208
Julia Reynolds88860ce2017-06-01 16:55:49 -04005209 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005210 private void recordCallerLocked(NotificationRecord record) {
5211 if (mZenModeHelper.isCall(record)) {
5212 mZenModeHelper.recordCaller(record);
5213 }
5214 }
5215
Christoph Studerd5092bc2014-07-03 17:47:58 +02005216 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04005217 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005218 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02005219 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005220 if (record.isIntercepted()) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05005221 record.setSuppressedVisualEffects(
5222 mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
Julia Reynolds445cfa82017-05-08 15:41:45 -04005223 } else {
5224 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005225 }
Chris Wren333a61c2014-05-28 16:40:57 -04005226 }
5227
Julia Reynolds88860ce2017-06-01 16:55:49 -04005228 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04005229 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04005230 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04005231 }
5232
Chris Wrenf9536642014-04-17 10:01:54 -04005233 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005234 synchronized (mNotificationLock) {
Beverly5a20a5e2018-03-06 15:02:44 -05005235 mListeners.notifyRankingUpdateLocked(null);
Chris Wrenf9536642014-04-17 10:01:54 -04005236 }
5237 }
5238
John Spurlockd8afe3c2014-08-01 14:04:07 -04005239 private void scheduleListenerHintsChanged(int state) {
5240 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
5241 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04005242 }
5243
Christoph Studer85a384b2014-08-27 20:16:15 +02005244 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
5245 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
5246 mHandler.obtainMessage(
5247 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
5248 listenerInterruptionFilter,
5249 0).sendToTarget();
5250 }
5251
John Spurlockd8afe3c2014-08-01 14:04:07 -04005252 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005253 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005254 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005255 }
5256 }
5257
Christoph Studer85a384b2014-08-27 20:16:15 +02005258 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005259 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02005260 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
5261 }
5262 }
5263
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005264 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08005265 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005266 public WorkerHandler(Looper looper) {
5267 super(looper);
5268 }
5269
Adam Lesinski182f73f2013-12-05 16:48:06 -08005270 @Override
5271 public void handleMessage(Message msg)
5272 {
5273 switch (msg.what)
5274 {
Robert Carr997427342018-02-28 18:06:10 -08005275 case MESSAGE_DURATION_REACHED:
5276 handleDurationReached((ToastRecord)msg.obj);
5277 break;
5278 case MESSAGE_FINISH_TOKEN_TIMEOUT:
5279 handleKillTokenTimeout((IBinder)msg.obj);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005280 break;
John Spurlock056c5192014-04-20 21:52:01 -04005281 case MESSAGE_SAVE_POLICY_FILE:
5282 handleSavePolicyFile();
5283 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005284 case MESSAGE_SEND_RANKING_UPDATE:
5285 handleSendRankingUpdate();
5286 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04005287 case MESSAGE_LISTENER_HINTS_CHANGED:
5288 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04005289 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02005290 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
5291 handleListenerInterruptionFilterChanged(msg.arg1);
5292 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005293 }
5294 }
5295
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005296 protected void scheduleSendRankingUpdate() {
5297 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
5298 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
5299 sendMessage(m);
5300 }
5301 }
5302
Chris Wrenf9536642014-04-17 10:01:54 -04005303 }
5304
Chris Wren51017d02015-12-15 15:34:46 -05005305 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04005306 {
Chris Wren51017d02015-12-15 15:34:46 -05005307 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04005308 super(looper);
5309 }
5310
5311 @Override
5312 public void handleMessage(Message msg) {
5313 switch (msg.what) {
5314 case MESSAGE_RECONSIDER_RANKING:
5315 handleRankingReconsideration(msg);
5316 break;
Chris Wren51017d02015-12-15 15:34:46 -05005317 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005318 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04005319 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08005320 }
5321 }
Chris Wren51017d02015-12-15 15:34:46 -05005322
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005323 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05005324 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05005325 Message msg = Message.obtain();
5326 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05005327 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05005328 }
5329
5330 public void requestReconsideration(RankingReconsideration recon) {
5331 Message m = Message.obtain(this,
5332 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
5333 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
5334 sendMessageDelayed(m, delay);
5335 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08005336 }
5337
Adam Lesinski182f73f2013-12-05 16:48:06 -08005338 // Notifications
5339 // ============================================================================
5340 static int clamp(int x, int low, int high) {
5341 return (x < low) ? low : ((x > high) ? high : x);
5342 }
5343
5344 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
Eugene Suslad4128ec2017-12-04 19:48:41 +00005345 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07005346 return;
5347 }
5348
5349 AccessibilityEvent event =
5350 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
5351 event.setPackageName(packageName);
5352 event.setClassName(Notification.class.getName());
5353 event.setParcelableData(notification);
5354 CharSequence tickerText = notification.tickerText;
5355 if (!TextUtils.isEmpty(tickerText)) {
5356 event.getText().add(tickerText);
5357 }
5358
Julia Reynolds94187562017-10-10 13:58:49 -04005359 mAccessibilityManager.sendAccessibilityEvent(event);
svetoslavganov75986cf2009-05-14 22:28:01 -07005360 }
5361
Julia Reynolds0839c022017-06-15 15:24:01 -04005362 /**
5363 * Removes all NotificationsRecords with the same key as the given notification record
5364 * from both lists. Do not call this method while iterating over either list.
5365 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005366 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04005367 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
5368 // Remove from both lists, either list could have a separate Record for what is
5369 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005370 boolean wasPosted = false;
5371 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04005372 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
5373 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005374 mNotificationList.remove(recordInList);
5375 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005376 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005377 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005378 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005379 != null) {
5380 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005381 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005382 return wasPosted;
5383 }
5384
5385 @GuardedBy("mNotificationLock")
5386 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04005387 boolean wasPosted, String listenerName) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005388 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName);
5389 }
5390
5391 @GuardedBy("mNotificationLock")
5392 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
5393 int rank, int count, boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04005394 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005395
5396 // Record caller.
5397 recordCallerLocked(r);
5398
Julia Reynolds503ed942017-10-04 16:04:56 -04005399 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
5400 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
5401 }
5402
Joe Onorato46439ce2010-11-19 13:56:21 -08005403 // tell the app
5404 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005405 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08005406 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005407 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08005408 } catch (PendingIntent.CanceledException ex) {
5409 // do nothing - there's no relevant way to recover, and
5410 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04005411 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08005412 }
5413 }
5414 }
5415
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005416 // Only cancel these if this notification actually got to be posted.
5417 if (wasPosted) {
5418 // status bar
5419 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005420 if (reason != REASON_SNOOZED) {
5421 r.isCanceled = true;
5422 }
Beverly5a20a5e2018-03-06 15:02:44 -05005423 mListeners.notifyRemovedLocked(r, reason, r.getStats());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005424 mHandler.post(new Runnable() {
5425 @Override
5426 public void run() {
5427 mGroupHelper.onNotificationRemoved(r.sbn);
5428 }
5429 });
5430 }
5431
5432 // sound
5433 if (canceledKey.equals(mSoundNotificationKey)) {
5434 mSoundNotificationKey = null;
5435 final long identity = Binder.clearCallingIdentity();
5436 try {
5437 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5438 if (player != null) {
5439 player.stopAsync();
5440 }
5441 } catch (RemoteException e) {
5442 } finally {
5443 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04005444 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005445 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005446
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005447 // vibrate
5448 if (canceledKey.equals(mVibrateNotificationKey)) {
5449 mVibrateNotificationKey = null;
5450 long identity = Binder.clearCallingIdentity();
5451 try {
5452 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005453 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005454 finally {
5455 Binder.restoreCallingIdentity(identity);
5456 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005457 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005458
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005459 // light
5460 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005461 }
5462
Christoph Studer546bec82014-03-14 12:17:12 +01005463 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04005464 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01005465 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005466 case REASON_CANCEL:
5467 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005468 case REASON_LISTENER_CANCEL:
5469 case REASON_LISTENER_CANCEL_ALL:
5470 mUsageStats.registerDismissedByUser(r);
5471 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05005472 case REASON_APP_CANCEL:
5473 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005474 mUsageStats.registerRemovedByApp(r);
5475 break;
Christoph Studer546bec82014-03-14 12:17:12 +01005476 }
5477
Christoph Studer265c1052014-07-23 17:14:33 +02005478 String groupKey = r.getGroupKey();
5479 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005480 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02005481 mSummaryByGroupKey.remove(groupKey);
5482 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04005483 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
5484 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
5485 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04005486 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005487
Daniel Sandler23d7c702013-03-07 16:32:06 -05005488 // Save it for users of getHistoricalNotifications()
5489 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02005490
Chris Wren6650e572015-05-15 17:19:25 -04005491 final long now = System.currentTimeMillis();
Dieter Hsud39f0d52018-04-14 02:08:30 +08005492 final LogMaker logMaker = r.getLogMaker(now)
Chris Wren9eb5e102017-01-26 13:15:06 -05005493 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
5494 .setType(MetricsEvent.TYPE_DISMISS)
Dieter Hsud39f0d52018-04-14 02:08:30 +08005495 .setSubtype(reason);
5496 if (rank != -1 && count != -1) {
5497 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
5498 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
5499 }
5500 MetricsLogger.action(logMaker);
Chris Wrene6ddb8a2015-05-27 15:21:00 -04005501 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Dieter Hsud39f0d52018-04-14 02:08:30 +08005502 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
5503 rank, count, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005504 }
5505
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005506 @VisibleForTesting
5507 void updateUriPermissions(@Nullable NotificationRecord newRecord,
5508 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) {
5509 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey();
5510 if (DBG) Slog.d(TAG, key + ": updating permissions");
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005511
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005512 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null;
5513 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null;
5514
5515 // Shortcut when no Uris involved
5516 if (newUris == null && oldUris == null) {
5517 return;
5518 }
5519
5520 // Inherit any existing owner
5521 IBinder permissionOwner = null;
5522 if (newRecord != null && permissionOwner == null) {
5523 permissionOwner = newRecord.permissionOwner;
5524 }
5525 if (oldRecord != null && permissionOwner == null) {
5526 permissionOwner = oldRecord.permissionOwner;
5527 }
5528
5529 // If we have Uris to grant, but no owner yet, go create one
5530 if (newUris != null && permissionOwner == null) {
5531 try {
5532 if (DBG) Slog.d(TAG, key + ": creating owner");
5533 permissionOwner = mAm.newUriPermissionOwner("NOTIF:" + key);
5534 } catch (RemoteException ignored) {
5535 // Ignored because we're in same process
5536 }
5537 }
5538
5539 // If we have no Uris to grant, but an existing owner, go destroy it
5540 if (newUris == null && permissionOwner != null) {
5541 final long ident = Binder.clearCallingIdentity();
5542 try {
5543 if (DBG) Slog.d(TAG, key + ": destroying owner");
5544 mAm.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
5545 UserHandle.getUserId(oldRecord.getUid()));
5546 permissionOwner = null;
5547 } catch (RemoteException ignored) {
5548 // Ignored because we're in same process
5549 } finally {
5550 Binder.restoreCallingIdentity(ident);
5551 }
5552 }
5553
5554 // Grant access to new Uris
5555 if (newUris != null && permissionOwner != null) {
5556 for (int i = 0; i < newUris.size(); i++) {
5557 final Uri uri = newUris.valueAt(i);
5558 if (oldUris == null || !oldUris.contains(uri)) {
5559 if (DBG) Slog.d(TAG, key + ": granting " + uri);
5560 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
5561 targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005562 }
5563 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005564 }
5565
5566 // Revoke access to old Uris
5567 if (oldUris != null && permissionOwner != null) {
5568 for (int i = 0; i < oldUris.size(); i++) {
5569 final Uri uri = oldUris.valueAt(i);
5570 if (newUris == null || !newUris.contains(uri)) {
5571 if (DBG) Slog.d(TAG, key + ": revoking " + uri);
5572 revokeUriPermission(permissionOwner, uri, oldRecord.getUid());
5573 }
5574 }
5575 }
5576
5577 if (newRecord != null) {
5578 newRecord.permissionOwner = permissionOwner;
5579 }
5580 }
5581
5582 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg,
5583 int targetUserId) {
5584 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5585
5586 final long ident = Binder.clearCallingIdentity();
5587 try {
5588 mAm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
5589 ContentProvider.getUriWithoutUserId(uri),
5590 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5591 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
5592 targetUserId);
5593 } catch (RemoteException ignored) {
5594 // Ignored because we're in same process
5595 } finally {
5596 Binder.restoreCallingIdentity(ident);
5597 }
5598 }
5599
5600 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUid) {
5601 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
5602
5603 final long ident = Binder.clearCallingIdentity();
5604 try {
5605 mAm.revokeUriPermissionFromOwner(owner,
5606 ContentProvider.getUriWithoutUserId(uri),
5607 Intent.FLAG_GRANT_READ_URI_PERMISSION,
5608 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
5609 } catch (RemoteException ignored) {
5610 // Ignored because we're in same process
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005611 } finally {
5612 Binder.restoreCallingIdentity(ident);
5613 }
5614 }
5615
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005616 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07005617 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005618 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005619 */
John Spurlocke6a7d932014-03-13 12:29:00 -04005620 void cancelNotification(final int callingUid, final int callingPid,
5621 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005622 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04005623 final int userId, final int reason, final ManagedServiceInfo listener) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08005624 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
5625 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
5626 }
5627
5628 /**
5629 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
5630 * and none of the {@code mustNotHaveFlags}.
5631 */
5632 void cancelNotification(final int callingUid, final int callingPid,
5633 final String pkg, final String tag, final int id,
5634 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
5635 final int userId, final int reason, int rank, int count, final ManagedServiceInfo listener) {
Beverly5a20a5e2018-03-06 15:02:44 -05005636
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005637 // In enqueueNotificationInternal notifications are added by scheduling the
5638 // work on the worker handler. Hence, we also schedule the cancel on this
5639 // handler to avoid a scenario where an add notification call followed by a
5640 // remove notification call ends up in not removing the notification.
5641 mHandler.post(new Runnable() {
5642 @Override
5643 public void run() {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005644 String listenerName = listener == null ? null : listener.component.toShortString();
Chris Wrenbddb5bc2015-03-04 08:47:46 -08005645 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
5646 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005647
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005648 synchronized (mNotificationLock) {
5649 // Look for the notification, searching both the posted and enqueued lists.
5650 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
5651 if (r != null) {
5652 // The notification was found, check if it should be removed.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005653
Christoph Studer546bec82014-03-14 12:17:12 +01005654 // Ideally we'd do this in the caller of this method. However, that would
5655 // require the caller to also find the notification.
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005656 if (reason == REASON_CLICK) {
Christoph Studer546bec82014-03-14 12:17:12 +01005657 mUsageStats.registerClickedByUser(r);
5658 }
5659
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005660 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
5661 return;
5662 }
5663 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
5664 return;
5665 }
5666
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005667 // Cancel the notification.
Julia Reynolds0839c022017-06-15 15:24:01 -04005668 boolean wasPosted = removeFromNotificationListsLocked(r);
Dieter Hsud39f0d52018-04-14 02:08:30 +08005669 cancelNotificationLocked(r, sendDelete, reason, rank, count, wasPosted, listenerName);
Christoph Studer265c1052014-07-23 17:14:33 +02005670 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005671 sendDelete, null);
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005672 updateLightsLocked();
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005673 } else {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005674 // No notification was found, assume that it is snoozed and cancel it.
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005675 if (reason != REASON_SNOOZED) {
5676 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
5677 if (wasSnoozed) {
5678 savePolicyFile();
5679 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005680 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005681 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005683 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005684 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005685 }
5686
5687 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07005688 * Determine whether the userId applies to the notification in question, either because
5689 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
5690 */
5691 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
5692 return
5693 // looking for USER_ALL notifications? match everything
5694 userId == UserHandle.USER_ALL
5695 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005696 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07005697 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005698 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07005699 }
5700
5701 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005702 * Determine whether the userId applies to the notification in question, either because
5703 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01005704 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005705 */
Kenny Guy2a764942014-04-02 13:29:20 +01005706 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00005707 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04005708 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005709 }
5710
5711 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05005712 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005713 * {@code mustHaveFlags}.
5714 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005715 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005716 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005717 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005718 mHandler.post(new Runnable() {
5719 @Override
5720 public void run() {
5721 String listenerName = listener == null ? null : listener.component.toShortString();
5722 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5723 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
5724 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005725
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005726 // Why does this parameter exist? Do we actually want to execute the above if doit
5727 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005728 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005729 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005730 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005731
5732 synchronized (mNotificationLock) {
5733 FlagChecker flagChecker = (int flags) -> {
5734 if ((flags & mustHaveFlags) != mustHaveFlags) {
5735 return false;
5736 }
5737 if ((flags & mustNotHaveFlags) != 0) {
5738 return false;
5739 }
5740 return true;
5741 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005742 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5743 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
5744 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005745 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005746 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5747 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
5748 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005749 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005750 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005751 }
5752 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005753 });
5754 }
5755
5756 private interface FlagChecker {
5757 // Returns false if these flags do not pass the defined flag test.
5758 public boolean apply(int flags);
5759 }
5760
Julia Reynolds88860ce2017-06-01 16:55:49 -04005761 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005762 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
5763 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
5764 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005765 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005766 ArrayList<NotificationRecord> canceledNotifications = null;
5767 for (int i = notificationList.size() - 1; i >= 0; --i) {
5768 NotificationRecord r = notificationList.get(i);
5769 if (includeCurrentProfiles) {
5770 if (!notificationMatchesCurrentProfiles(r, userId)) {
5771 continue;
5772 }
5773 } else if (!notificationMatchesUserId(r, userId)) {
5774 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005775 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005776 // Don't remove notifications to all, if there's no package name specified
5777 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
5778 continue;
5779 }
5780 if (!flagChecker.apply(r.getFlags())) {
5781 continue;
5782 }
5783 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
5784 continue;
5785 }
5786 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
5787 continue;
5788 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005789 if (canceledNotifications == null) {
5790 canceledNotifications = new ArrayList<>();
5791 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005792 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005793 mNotificationsByKey.remove(r.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005794 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04005795 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005796 }
5797 if (canceledNotifications != null) {
5798 final int M = canceledNotifications.size();
5799 for (int i = 0; i < M; i++) {
5800 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005801 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005802 }
5803 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005804 }
5805 }
5806
Julia Reynolds50989772017-02-23 14:32:16 -05005807 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005808 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05005809 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005810 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05005811 return;
5812 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05005813
Julia Reynolds79672302017-01-12 08:30:16 -05005814 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05005815 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
5816 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05005817 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005818 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005819 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005820 }
5821
5822 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
5823 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005824 if (DBG) {
5825 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
5826 }
Julia Reynolds79672302017-01-12 08:30:16 -05005827 mSnoozeHelper.repost(key);
5828 savePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005829 }
5830
Julia Reynolds88860ce2017-06-01 16:55:49 -04005831 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07005832 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005833 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005834 mHandler.post(new Runnable() {
5835 @Override
5836 public void run() {
5837 synchronized (mNotificationLock) {
5838 String listenerName =
5839 listener == null ? null : listener.component.toShortString();
5840 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5841 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01005842
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005843 FlagChecker flagChecker = (int flags) -> {
5844 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
5845 != 0) {
5846 return false;
5847 }
5848 return true;
5849 };
5850
5851 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5852 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
5853 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005854 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005855 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5856 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
5857 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04005858 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005859 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00005860 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005861 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005862 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005863 }
5864
Christoph Studere4ef156b2014-07-04 18:41:57 +02005865 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04005866 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02005867 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005868 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005869 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02005870 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005871 return;
5872 }
5873
5874 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02005875
5876 if (pkg == null) {
5877 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
5878 return;
5879 }
5880
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005881 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005882 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005883 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005884 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005885 }
5886
Julia Reynolds88860ce2017-06-01 16:55:49 -04005887 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005888 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
5889 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005890 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005891 final String pkg = parentNotification.sbn.getPackageName();
5892 final int userId = parentNotification.getUserId();
5893 final int reason = REASON_GROUP_SUMMARY_CANCELED;
5894 for (int i = notificationList.size() - 1; i >= 0; i--) {
5895 final NotificationRecord childR = notificationList.get(i);
5896 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04005897 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005898 childR.getGroupKey().equals(parentNotification.getGroupKey())
Julia Reynoldse5c60452018-04-30 14:41:36 -04005899 && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
Beverly40239d92017-07-07 10:20:41 -04005900 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02005901 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
5902 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04005903 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005904 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04005905 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005906 }
5907 }
5908 }
5909
Julia Reynolds88860ce2017-06-01 16:55:49 -04005910 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005911 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005912 {
The Android Open Source Project10592532009-03-18 17:39:46 -07005913 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05005914 NotificationRecord ledNotification = null;
5915 while (ledNotification == null && !mLights.isEmpty()) {
5916 final String owner = mLights.get(mLights.size() - 1);
5917 ledNotification = mNotificationsByKey.get(owner);
5918 if (ledNotification == null) {
5919 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
5920 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005921 }
5922 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005923
Mike Lockwood63b5ad92011-08-30 09:55:30 -04005924 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05005925 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05005926 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07005927 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05005928 NotificationRecord.Light light = ledNotification.getLight();
5929 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05005930 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05005931 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
5932 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05005933 }
The Android Open Source Project10592532009-03-18 17:39:46 -07005934 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005935 }
5936
Julia Reynolds88860ce2017-06-01 16:55:49 -04005937 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005938 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
5939 String groupKey, int userId) {
5940 List<NotificationRecord> records = new ArrayList<>();
5941 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
5942 records.addAll(
5943 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
5944 return records;
5945 }
5946
5947
Julia Reynolds88860ce2017-06-01 16:55:49 -04005948 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005949 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
5950 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
5951 List<NotificationRecord> records = new ArrayList<>();
5952 final int len = list.size();
5953 for (int i = 0; i < len; i++) {
5954 NotificationRecord r = list.get(i);
5955 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
5956 && r.sbn.getPackageName().equals(pkg)) {
5957 records.add(r);
5958 }
5959 }
5960 return records;
5961 }
5962
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005963 // Searches both enqueued and posted notifications by key.
5964 // TODO: need to combine a bunch of these getters with slightly different behavior.
5965 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04005966 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005967 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005968 NotificationRecord r;
5969 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
5970 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005971 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005972 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
5973 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005974 }
5975 return null;
5976 }
5977
Julia Reynolds88860ce2017-06-01 16:55:49 -04005978 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005979 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005980 NotificationRecord r;
5981 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
5982 return r;
5983 }
5984 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
5985 != null) {
5986 return r;
5987 }
5988 return null;
5989 }
5990
Julia Reynolds88860ce2017-06-01 16:55:49 -04005991 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005992 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005993 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005994 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005995 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005996 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01005997 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
5998 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005999 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006000 }
6001 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006002 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006003 }
6004
Julia Reynolds88860ce2017-06-01 16:55:49 -04006005 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006006 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04006007 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006008 final int N = list.size();
6009 for (int i = 0; i < N; i++) {
6010 if (key.equals(list.get(i).getKey())) {
6011 return list.get(i);
6012 }
6013 }
6014 return null;
6015 }
6016
Julia Reynolds88860ce2017-06-01 16:55:49 -04006017 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02006018 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02006019 final int N = mNotificationList.size();
6020 for (int i = 0; i < N; i++) {
6021 if (key.equals(mNotificationList.get(i).getKey())) {
6022 return i;
6023 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02006024 }
Christoph Studerc5115552014-06-12 20:22:31 +02006025 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02006026 }
6027
Beverly5a20a5e2018-03-06 15:02:44 -05006028 @VisibleForTesting
6029 protected void hideNotificationsForPackages(String[] pkgs) {
6030 synchronized (mNotificationLock) {
6031 List<String> pkgList = Arrays.asList(pkgs);
6032 List<NotificationRecord> changedNotifications = new ArrayList<>();
6033 int numNotifications = mNotificationList.size();
6034 for (int i = 0; i < numNotifications; i++) {
6035 NotificationRecord rec = mNotificationList.get(i);
6036 if (pkgList.contains(rec.sbn.getPackageName())) {
6037 rec.setHidden(true);
6038 changedNotifications.add(rec);
6039 }
6040 }
6041
6042 mListeners.notifyHiddenLocked(changedNotifications);
6043 }
6044 }
6045
6046 @VisibleForTesting
6047 protected void unhideNotificationsForPackages(String[] pkgs) {
6048 synchronized (mNotificationLock) {
6049 List<String> pkgList = Arrays.asList(pkgs);
6050 List<NotificationRecord> changedNotifications = new ArrayList<>();
6051 int numNotifications = mNotificationList.size();
6052 for (int i = 0; i < numNotifications; i++) {
6053 NotificationRecord rec = mNotificationList.get(i);
6054 if (pkgList.contains(rec.sbn.getPackageName())) {
6055 rec.setHidden(false);
6056 changedNotifications.add(rec);
6057 }
6058 }
6059
6060 mListeners.notifyUnhiddenLocked(changedNotifications);
6061 }
6062 }
6063
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006064 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006065 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006066 updateLightsLocked();
6067 }
6068 }
John Spurlocke677d712014-02-13 12:52:19 -05006069
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006070 protected boolean isCallingUidSystem() {
6071 final int uid = Binder.getCallingUid();
6072 return uid == Process.SYSTEM_UID;
6073 }
6074
6075 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04006076 final int appid = UserHandle.getAppId(uid);
6077 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
6078 }
John Spurlockb408e8e2014-04-23 21:12:45 -04006079
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006080 // TODO: Most calls should probably move to isCallerSystem.
6081 protected boolean isCallerSystemOrPhone() {
6082 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04006083 }
6084
Julia Reynoldsb852e562017-06-06 16:14:18 -04006085 private void checkCallerIsSystemOrShell() {
6086 if (Binder.getCallingUid() == Process.SHELL_UID) {
6087 return;
6088 }
6089 checkCallerIsSystem();
6090 }
6091
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006092 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006093 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006094 return;
6095 }
6096 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
6097 }
6098
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006099 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006100 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04006101 return;
6102 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04006103 checkCallerIsSameApp(pkg);
6104 }
6105
Chad Brubaker6b68f102017-01-27 13:39:00 -08006106 private boolean isCallerInstantApp(String pkg) {
6107 // System is always allowed to act for ephemeral apps.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006108 if (isCallerSystemOrPhone()) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08006109 return false;
6110 }
6111
6112 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
6113
6114 try {
6115 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
6116 UserHandle.getCallingUserId());
6117 if (ai == null) {
6118 throw new SecurityException("Unknown package " + pkg);
6119 }
6120 return ai.isInstantApp();
6121 } catch (RemoteException re) {
6122 throw new SecurityException("Unknown package " + pkg, re);
6123 }
6124
6125 }
6126
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006127 private void checkCallerIsSameApp(String pkg) {
John Spurlock7340fc82014-04-24 18:50:12 -04006128 final int uid = Binder.getCallingUid();
6129 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006130 ApplicationInfo ai = mPackageManager.getApplicationInfo(
John Spurlock7340fc82014-04-24 18:50:12 -04006131 pkg, 0, UserHandle.getCallingUserId());
Dan Sandler09afc2e2014-07-18 14:29:20 -04006132 if (ai == null) {
6133 throw new SecurityException("Unknown package " + pkg);
6134 }
John Spurlock7340fc82014-04-24 18:50:12 -04006135 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006136 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04006137 + pkg + " which is owned by uid " + ai.uid);
6138 }
6139 } catch (RemoteException re) {
6140 throw new SecurityException("Unknown package " + pkg + "\n" + re);
6141 }
6142 }
6143
John Spurlock32fe4c62014-10-02 12:16:02 -04006144 private static String callStateToString(int state) {
6145 switch (state) {
6146 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
6147 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
6148 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
6149 default: return "CALL_STATE_UNKNOWN_" + state;
6150 }
6151 }
6152
6153 private void listenForCallState() {
6154 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
6155 @Override
6156 public void onCallStateChanged(int state, String incomingNumber) {
6157 if (mCallState == state) return;
6158 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
6159 mCallState = state;
6160 }
6161 }, PhoneStateListener.LISTEN_CALL_STATE);
6162 }
6163
Christoph Studer05ad4822014-05-16 14:16:03 +02006164 /**
6165 * Generates a NotificationRankingUpdate from 'sbns', considering only
6166 * notifications visible to the given listener.
6167 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006168 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04006169 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04006170 final int N = mNotificationList.size();
6171 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02006172 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05006173 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04006174 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006175 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006176 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05006177 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006178 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05006179 Bundle overridePeople = new Bundle();
6180 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05006181 Bundle showBadge = new Bundle();
Julia Reynolds503ed942017-10-04 16:04:56 -04006182 Bundle userSentiment = new Bundle();
Beverly5a20a5e2018-03-06 15:02:44 -05006183 Bundle hidden = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04006184 for (int i = 0; i < N; i++) {
6185 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02006186 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006187 continue;
6188 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006189 final String key = record.sbn.getKey();
6190 keys.add(key);
6191 importance.add(record.getImportance());
6192 if (record.getImportanceExplanation() != null) {
6193 explanation.putCharSequence(key, record.getImportanceExplanation());
6194 }
Chris Wren333a61c2014-05-28 16:40:57 -04006195 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006196 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006197
Christoph Studer05ad4822014-05-16 14:16:03 +02006198 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006199 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006200 if (record.getPackageVisibilityOverride()
6201 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05006202 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006203 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04006204 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05006205 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05006206 overridePeople.putStringArrayList(key, record.getPeopleOverride());
6207 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05006208 showBadge.putBoolean(key, record.canShowBadge());
Julia Reynolds503ed942017-10-04 16:04:56 -04006209 userSentiment.putInt(key, record.getUserSentiment());
Beverly5a20a5e2018-03-06 15:02:44 -05006210 hidden.putBoolean(key, record.isHidden());
Christoph Studer05ad4822014-05-16 14:16:03 +02006211 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006212 final int M = keys.size();
6213 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02006214 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05006215 int[] importanceAr = new int[M];
6216 for (int i = 0; i < M; i++) {
6217 importanceAr[i] = importance.get(i);
6218 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006219 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05006220 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Beverly5a20a5e2018-03-06 15:02:44 -05006221 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden);
Christoph Studer05ad4822014-05-16 14:16:03 +02006222 }
6223
Julia Reynoldsda781472017-04-12 09:41:16 -04006224 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006225 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04006226 mCompanionManager = getCompanionManager();
6227 }
6228 // Companion mgr doesn't exist on all device types
6229 if (mCompanionManager == null) {
6230 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006231 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006232 long identity = Binder.clearCallingIdentity();
6233 try {
6234 List<String> associations = mCompanionManager.getAssociations(
6235 info.component.getPackageName(), info.userid);
6236 if (!ArrayUtils.isEmpty(associations)) {
6237 return true;
6238 }
6239 } catch (SecurityException se) {
6240 // Not a privileged listener
6241 } catch (RemoteException re) {
6242 Slog.e(TAG, "Cannot reach companion device service", re);
6243 } catch (Exception e) {
6244 Slog.e(TAG, "Cannot verify listener " + info, e);
6245 } finally {
6246 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006247 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006248 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006249 }
6250
Julia Reynolds727a7282017-04-13 10:54:01 -04006251 protected ICompanionDeviceManager getCompanionManager() {
6252 return ICompanionDeviceManager.Stub.asInterface(
6253 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
6254 }
6255
Christoph Studercef37cf2014-07-25 14:18:17 +02006256 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
6257 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
6258 return false;
6259 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07006260 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02006261 return true;
6262 }
6263
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00006264 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Beverly2be7a052018-03-27 11:37:58 -04006265 final long identity = Binder.clearCallingIdentity();
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006266 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006267 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006268 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006269 } catch (RemoteException re) {
6270 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00006271 } catch (IllegalArgumentException ex) {
6272 // Package not found.
6273 return false;
Beverly2be7a052018-03-27 11:37:58 -04006274 } finally {
6275 Binder.restoreCallingIdentity(identity);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006276 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006277 }
6278
Kristian Monsen30f59b22018-04-09 10:27:16 +02006279 @VisibleForTesting
6280 boolean canUseManagedServices(String pkg) {
6281 boolean canUseManagedServices = !mActivityManager.isLowRamDevice()
Julia Reynoldse1816412017-10-24 10:39:11 -04006282 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
Kristian Monsen30f59b22018-04-09 10:27:16 +02006283
6284 for (String whitelisted : getContext().getResources().getStringArray(
6285 R.array.config_allowedManagedServicesOnLowRamDevices)) {
6286 if (whitelisted.equals(pkg)) {
6287 canUseManagedServices = true;
6288 }
6289 }
6290
6291 return canUseManagedServices;
Julia Reynoldse1816412017-10-24 10:39:11 -04006292 }
6293
Chris Wren47633422016-01-22 09:56:59 -05006294 private class TrimCache {
6295 StatusBarNotification heavy;
6296 StatusBarNotification sbnClone;
6297 StatusBarNotification sbnCloneLight;
6298
6299 TrimCache(StatusBarNotification sbn) {
6300 heavy = sbn;
6301 }
6302
6303 StatusBarNotification ForListener(ManagedServiceInfo info) {
6304 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
6305 if (sbnCloneLight == null) {
6306 sbnCloneLight = heavy.cloneLight();
6307 }
6308 return sbnCloneLight;
6309 } else {
6310 if (sbnClone == null) {
6311 sbnClone = heavy.clone();
6312 }
6313 return sbnClone;
6314 }
6315 }
6316 }
6317
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006318 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006319 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05006320
Julia Reynolds7380d872018-01-12 10:28:26 -05006321 public NotificationAssistants(Context context, Object lock, UserProfiles up,
6322 IPackageManager pm) {
6323 super(context, lock, up, pm);
Chris Wren51017d02015-12-15 15:34:46 -05006324 }
6325
6326 @Override
6327 protected Config getConfig() {
6328 Config c = new Config();
Julia Reynolds503ed942017-10-04 16:04:56 -04006329 c.caption = "notification assistant";
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006330 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006331 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006332 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
6333 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05006334 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006335 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05006336 return c;
6337 }
6338
6339 @Override
6340 protected IInterface asInterface(IBinder binder) {
6341 return INotificationListener.Stub.asInterface(binder);
6342 }
6343
6344 @Override
6345 protected boolean checkType(IInterface service) {
6346 return service instanceof INotificationListener;
6347 }
6348
6349 @Override
6350 protected void onServiceAdded(ManagedServiceInfo info) {
6351 mListeners.registerGuestService(info);
6352 }
6353
6354 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006355 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05006356 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
6357 mListeners.unregisterService(removed.service, removed.userid);
6358 }
Chris Wren47633422016-01-22 09:56:59 -05006359
Julia Reynoldsef934fd2018-02-01 14:39:17 -05006360 @Override
6361 public void onUserUnlocked(int user) {
6362 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
6363 rebindServices(true);
6364 }
6365
Chris Wren47633422016-01-22 09:56:59 -05006366 public void onNotificationEnqueued(final NotificationRecord r) {
6367 final StatusBarNotification sbn = r.sbn;
6368 TrimCache trimCache = new TrimCache(sbn);
6369
Chris Wren47633422016-01-22 09:56:59 -05006370 // There should be only one, but it's a list, so while we enforce
6371 // singularity elsewhere, we keep it general here, to avoid surprises.
Julia Reynolds00314d92017-04-14 10:01:24 -04006372 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
Chris Wren47633422016-01-22 09:56:59 -05006373 boolean sbnVisible = isVisibleToListener(sbn, info);
6374 if (!sbnVisible) {
6375 continue;
6376 }
6377
Chris Wren47633422016-01-22 09:56:59 -05006378 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006379 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05006380 @Override
6381 public void run() {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006382 notifyEnqueued(info, sbnToPost);
Chris Wren47633422016-01-22 09:56:59 -05006383 }
6384 });
6385 }
6386 }
6387
6388 private void notifyEnqueued(final ManagedServiceInfo info,
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006389 final StatusBarNotification sbn) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006390 final INotificationListener assistant = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05006391 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6392 try {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006393 assistant.onNotificationEnqueued(sbnHolder);
Chris Wren47633422016-01-22 09:56:59 -05006394 } catch (RemoteException ex) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006395 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Chris Wren47633422016-01-22 09:56:59 -05006396 }
6397 }
6398
Julia Reynolds79672302017-01-12 08:30:16 -05006399 /**
6400 * asynchronously notify the assistant that a notification has been snoozed until a
6401 * context
6402 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006403 @GuardedBy("mNotificationLock")
Julia Reynolds79672302017-01-12 08:30:16 -05006404 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
6405 final String snoozeCriterionId) {
6406 TrimCache trimCache = new TrimCache(sbn);
Julia Reynolds00314d92017-04-14 10:01:24 -04006407 for (final ManagedServiceInfo info : getServices()) {
Julia Reynolds503ed942017-10-04 16:04:56 -04006408 boolean sbnVisible = isVisibleToListener(sbn, info);
6409 if (!sbnVisible) {
6410 continue;
6411 }
Julia Reynolds79672302017-01-12 08:30:16 -05006412 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
6413 mHandler.post(new Runnable() {
6414 @Override
6415 public void run() {
6416 final INotificationListener assistant =
6417 (INotificationListener) info.service;
6418 StatusBarNotificationHolder sbnHolder
6419 = new StatusBarNotificationHolder(sbnToPost);
6420 try {
6421 assistant.onNotificationSnoozedUntilContext(
6422 sbnHolder, snoozeCriterionId);
6423 } catch (RemoteException ex) {
6424 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
6425 }
6426 }
6427 });
6428 }
6429 }
6430
Chris Wren47633422016-01-22 09:56:59 -05006431 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04006432 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05006433 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006434
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04006435 protected void ensureAssistant() {
6436 final List<UserInfo> activeUsers = mUm.getUsers(true);
6437 for (UserInfo userInfo : activeUsers) {
6438 int userId = userInfo.getUserHandle().getIdentifier();
6439 if (getAllowedPackages(userId).isEmpty()) {
6440 Slog.d(TAG, "Approving default notification assistant for user " + userId);
6441 readDefaultAssistant(userId);
6442 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006443 }
6444 }
Chris Wren51017d02015-12-15 15:34:46 -05006445 }
6446
John Spurlock7340fc82014-04-24 18:50:12 -04006447 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006448 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04006449
Christoph Studerb82bc782014-08-20 14:29:43 +02006450 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
6451
Julia Reynoldsb852e562017-06-06 16:14:18 -04006452 public NotificationListeners(IPackageManager pm) {
6453 super(getContext(), mNotificationLock, mUserProfiles, pm);
6454
John Spurlock7340fc82014-04-24 18:50:12 -04006455 }
6456
6457 @Override
6458 protected Config getConfig() {
6459 Config c = new Config();
6460 c.caption = "notification listener";
6461 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006462 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04006463 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
6464 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
6465 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
6466 c.clientLabel = R.string.notification_listener_binding_label;
6467 return c;
6468 }
6469
6470 @Override
6471 protected IInterface asInterface(IBinder binder) {
6472 return INotificationListener.Stub.asInterface(binder);
6473 }
6474
6475 @Override
Chris Wren51017d02015-12-15 15:34:46 -05006476 protected boolean checkType(IInterface service) {
6477 return service instanceof INotificationListener;
6478 }
6479
6480 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04006481 public void onServiceAdded(ManagedServiceInfo info) {
6482 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04006483 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006484 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04006485 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006486 }
John Spurlock7340fc82014-04-24 18:50:12 -04006487 try {
Chris Wren333a61c2014-05-28 16:40:57 -04006488 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04006489 } catch (RemoteException e) {
6490 // we tried
6491 }
6492 }
6493
John Spurlock1fa865f2014-07-21 14:56:39 -04006494 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006495 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04006496 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07006497 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006498 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01006499 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04006500 }
Christoph Studerb82bc782014-08-20 14:29:43 +02006501 mLightTrimListeners.remove(removed);
6502 }
6503
Julia Reynolds88860ce2017-06-01 16:55:49 -04006504 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02006505 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
6506 if (trim == TRIM_LIGHT) {
6507 mLightTrimListeners.add(info);
6508 } else {
6509 mLightTrimListeners.remove(info);
6510 }
6511 }
6512
6513 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
6514 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04006515 }
6516
John Spurlock7340fc82014-04-24 18:50:12 -04006517 /**
6518 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02006519 *
6520 * <p>
6521 * Also takes care of removing a notification that has been visible to a listener before,
6522 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04006523 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006524 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006525 public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
6526 notifyPostedLocked(r, old, true);
Beverly5a20a5e2018-03-06 15:02:44 -05006527 }
6528
6529 /**
6530 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
6531 * targetting <= O_MR1
6532 */
6533 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006534 private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
Beverly5a20a5e2018-03-06 15:02:44 -05006535 boolean notifyAllListeners) {
Christoph Studerb82bc782014-08-20 14:29:43 +02006536 // Lazily initialized snapshots of the notification.
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006537 StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006538 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Chris Wren47633422016-01-22 09:56:59 -05006539 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02006540
Julia Reynolds00314d92017-04-14 10:01:24 -04006541 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02006542 boolean sbnVisible = isVisibleToListener(sbn, info);
6543 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
6544 // This notification hasn't been and still isn't visible -> ignore.
6545 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006546 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04006547 }
Beverly5a20a5e2018-03-06 15:02:44 -05006548
6549 // If the notification is hidden, don't notifyPosted listeners targeting < P.
6550 // Instead, those listeners will receive notifyPosted when the notification is
6551 // unhidden.
6552 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
6553 continue;
6554 }
6555
6556 // If we shouldn't notify all listeners, this means the hidden state of
6557 // a notification was changed. Don't notifyPosted listeners targeting >= P.
6558 // Instead, those listeners will receive notifyRankingUpdate.
6559 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6560 continue;
6561 }
6562
Chris Wren333a61c2014-05-28 16:40:57 -04006563 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02006564
6565 // This notification became invisible -> remove the old one.
6566 if (oldSbnVisible && !sbnVisible) {
6567 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
6568 mHandler.post(new Runnable() {
6569 @Override
6570 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04006571 notifyRemoved(
6572 info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02006573 }
6574 });
Christoph Studer05ad4822014-05-16 14:16:03 +02006575 continue;
6576 }
Christoph Studercef37cf2014-07-25 14:18:17 +02006577
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006578 // Grant access before listener is notified
6579 final int targetUserId = (info.userid == UserHandle.USER_ALL)
6580 ? UserHandle.USER_SYSTEM : info.userid;
6581 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006582
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006583 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006584 mHandler.post(new Runnable() {
6585 @Override
6586 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02006587 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02006588 }
6589 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006590 }
6591 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006592
John Spurlock7340fc82014-04-24 18:50:12 -04006593 /**
6594 * asynchronously notify all listeners about a removed notification
6595 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006596 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05006597 public void notifyRemovedLocked(NotificationRecord r, int reason,
Julia Reynolds503ed942017-10-04 16:04:56 -04006598 NotificationStats notificationStats) {
Beverly5a20a5e2018-03-06 15:02:44 -05006599 final StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006600
John Spurlock7340fc82014-04-24 18:50:12 -04006601 // make a copy in case changes are made to the underlying Notification object
6602 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
6603 // notification
6604 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04006605 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02006606 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006607 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04006608 }
Beverly5a20a5e2018-03-06 15:02:44 -05006609
6610 // don't notifyRemoved for listeners targeting < P
6611 // if not for reason package suspended
6612 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
6613 && info.targetSdkVersion < Build.VERSION_CODES.P) {
6614 continue;
6615 }
6616
6617 // don't notifyRemoved for listeners targeting >= P
6618 // if the reason is package suspended
6619 if (reason == REASON_PACKAGE_SUSPENDED
6620 && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6621 continue;
6622 }
6623
Julia Reynolds503ed942017-10-04 16:04:56 -04006624 // Only assistants can get stats
6625 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
6626 ? notificationStats : null;
Chris Wren333a61c2014-05-28 16:40:57 -04006627 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006628 mHandler.post(new Runnable() {
6629 @Override
6630 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04006631 notifyRemoved(info, sbnLight, update, stats, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02006632 }
6633 });
Chris Wrenf9536642014-04-17 10:01:54 -04006634 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006635
6636 // Revoke access after all listeners have been updated
6637 mHandler.post(() -> {
6638 updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM);
6639 });
Chris Wrenf9536642014-04-17 10:01:54 -04006640 }
6641
6642 /**
Beverly5a20a5e2018-03-06 15:02:44 -05006643 * Asynchronously notify all listeners about a reordering of notifications
6644 * unless changedHiddenNotifications is populated.
6645 * If changedHiddenNotifications is populated, there was a change in the hidden state
6646 * of the notifications. In this case, we only send updates to listeners that
6647 * target >= P.
Chris Wrenf9536642014-04-17 10:01:54 -04006648 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006649 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05006650 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
6651 boolean isHiddenRankingUpdate = changedHiddenNotifications != null
6652 && changedHiddenNotifications.size() > 0;
6653
Julia Reynolds00314d92017-04-14 10:01:24 -04006654 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006655 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6656 continue;
6657 }
Beverly5a20a5e2018-03-06 15:02:44 -05006658
6659 boolean notifyThisListener = false;
6660 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
6661 Build.VERSION_CODES.P) {
6662 for (NotificationRecord rec : changedHiddenNotifications) {
6663 if (isVisibleToListener(rec.sbn, serviceInfo)) {
6664 notifyThisListener = true;
6665 break;
6666 }
John Spurlock7340fc82014-04-24 18:50:12 -04006667 }
Beverly5a20a5e2018-03-06 15:02:44 -05006668 }
6669
6670 if (notifyThisListener || !isHiddenRankingUpdate) {
6671 final NotificationRankingUpdate update = makeRankingUpdateLocked(
6672 serviceInfo);
6673
6674 mHandler.post(new Runnable() {
6675 @Override
6676 public void run() {
6677 notifyRankingUpdate(serviceInfo, update);
6678 }
6679 });
6680 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006681 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006682 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006683
Julia Reynolds88860ce2017-06-01 16:55:49 -04006684 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04006685 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006686 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04006687 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6688 continue;
6689 }
6690 mHandler.post(new Runnable() {
6691 @Override
6692 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006693 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006694 }
6695 });
6696 }
6697 }
6698
Beverly5a20a5e2018-03-06 15:02:44 -05006699 /**
6700 * asynchronously notify relevant listeners their notification is hidden
6701 * NotificationListenerServices that target P+:
6702 * NotificationListenerService#notifyRankingUpdateLocked()
6703 * NotificationListenerServices that target <= P:
6704 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
6705 */
6706 @GuardedBy("mNotificationLock")
6707 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
6708 if (changedNotifications == null || changedNotifications.size() == 0) {
6709 return;
6710 }
6711
6712 notifyRankingUpdateLocked(changedNotifications);
6713
6714 // for listeners that target < P, notifyRemoveLocked
6715 int numChangedNotifications = changedNotifications.size();
6716 for (int i = 0; i < numChangedNotifications; i++) {
6717 NotificationRecord rec = changedNotifications.get(i);
6718 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
6719 }
6720 }
6721
6722 /**
6723 * asynchronously notify relevant listeners their notification is unhidden
6724 * NotificationListenerServices that target P+:
6725 * NotificationListenerService#notifyRankingUpdateLocked()
6726 * NotificationListenerServices that target <= P:
6727 * NotificationListeners#notifyPostedLocked()
6728 */
6729 @GuardedBy("mNotificationLock")
6730 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
6731 if (changedNotifications == null || changedNotifications.size() == 0) {
6732 return;
6733 }
6734
6735 notifyRankingUpdateLocked(changedNotifications);
6736
6737 // for listeners that target < P, notifyPostedLocked
6738 int numChangedNotifications = changedNotifications.size();
6739 for (int i = 0; i < numChangedNotifications; i++) {
6740 NotificationRecord rec = changedNotifications.get(i);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006741 mListeners.notifyPostedLocked(rec, rec, false);
Beverly5a20a5e2018-03-06 15:02:44 -05006742 }
6743 }
6744
Christoph Studer85a384b2014-08-27 20:16:15 +02006745 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006746 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02006747 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6748 continue;
6749 }
6750 mHandler.post(new Runnable() {
6751 @Override
6752 public void run() {
6753 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
6754 }
6755 });
6756 }
6757 }
6758
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006759 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006760 final NotificationChannel channel, final int modificationType) {
6761 if (channel == null) {
6762 return;
6763 }
6764 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04006765 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006766 continue;
6767 }
Julia Reynolds018aa622017-04-20 11:31:30 -04006768
Eugene Suslaa25d17f2017-08-24 11:28:08 -07006769 BackgroundThread.getHandler().post(() -> {
6770 if (hasCompanionDevice(serviceInfo)) {
6771 notifyNotificationChannelChanged(
6772 serviceInfo, pkg, user, channel, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04006773 }
6774 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006775 }
6776 }
6777
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006778 protected void notifyNotificationChannelGroupChanged(
6779 final String pkg, final UserHandle user, final NotificationChannelGroup group,
6780 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006781 if (group == null) {
6782 return;
6783 }
6784 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04006785 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006786 continue;
6787 }
Julia Reynolds018aa622017-04-20 11:31:30 -04006788
Eugene Suslaa25d17f2017-08-24 11:28:08 -07006789 BackgroundThread.getHandler().post(() -> {
6790 if (hasCompanionDevice(serviceInfo)) {
6791 notifyNotificationChannelGroupChanged(
6792 serviceInfo, pkg, user, group, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04006793 }
6794 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006795 }
6796 }
6797
Christoph Studercef37cf2014-07-25 14:18:17 +02006798 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02006799 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04006800 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006801 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04006802 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07006803 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04006804 } catch (RemoteException ex) {
6805 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
6806 }
6807 }
6808
Christoph Studercef37cf2014-07-25 14:18:17 +02006809 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds503ed942017-10-04 16:04:56 -04006810 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04006811 if (!info.enabledAndUserMatches(sbn.getUserId())) {
6812 return;
6813 }
Christoph Studer05ad4822014-05-16 14:16:03 +02006814 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006815 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04006816 try {
Julia Reynolds503ed942017-10-04 16:04:56 -04006817 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04006818 } catch (RemoteException ex) {
6819 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04006820 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006821 }
Chris Wrenf9536642014-04-17 10:01:54 -04006822
Christoph Studer05ad4822014-05-16 14:16:03 +02006823 private void notifyRankingUpdate(ManagedServiceInfo info,
6824 NotificationRankingUpdate rankingUpdate) {
6825 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04006826 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02006827 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04006828 } catch (RemoteException ex) {
6829 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
6830 }
6831 }
John Spurlock1fa865f2014-07-21 14:56:39 -04006832
John Spurlockd8afe3c2014-08-01 14:04:07 -04006833 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04006834 final INotificationListener listener = (INotificationListener) info.service;
6835 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006836 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006837 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006838 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04006839 }
6840 }
Justin Koh38156c52014-06-04 13:57:49 -07006841
Christoph Studer85a384b2014-08-27 20:16:15 +02006842 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
6843 int interruptionFilter) {
6844 final INotificationListener listener = (INotificationListener) info.service;
6845 try {
6846 listener.onInterruptionFilterChanged(interruptionFilter);
6847 } catch (RemoteException ex) {
6848 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
6849 }
6850 }
6851
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006852 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006853 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006854 final int modificationType) {
6855 final INotificationListener listener = (INotificationListener) info.service;
6856 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006857 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006858 } catch (RemoteException ex) {
6859 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
6860 }
6861 }
6862
6863 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006864 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006865 final int modificationType) {
6866 final INotificationListener listener = (INotificationListener) info.service;
6867 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006868 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006869 } catch (RemoteException ex) {
6870 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
6871 }
6872 }
6873
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006874 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07006875 if (packageName == null) {
6876 return false;
6877 }
6878 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006879 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006880 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07006881 if (packageName.equals(serviceInfo.component.getPackageName())) {
6882 return true;
6883 }
6884 }
6885 }
6886 return false;
6887 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006888 }
John Spurlock25e2d242014-06-27 13:58:23 -04006889
6890 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04006891 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04006892 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04006893 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04006894 public long since;
6895 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04006896 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05006897 public boolean proto = false;
Vishnu Naire3e4d252018-03-01 11:26:57 -08006898 public boolean criticalPriority = false;
6899 public boolean normalPriority = false;
John Spurlock25e2d242014-06-27 13:58:23 -04006900
Kweku Adams887f09c2017-11-13 17:12:20 -08006901 @NonNull
John Spurlock25e2d242014-06-27 13:58:23 -04006902 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04006903 final DumpFilter filter = new DumpFilter();
6904 for (int ai = 0; ai < args.length; ai++) {
6905 final String a = args[ai];
Kweku Adams62b42242017-09-25 12:54:02 -07006906 if ("--proto".equals(a)) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05006907 filter.proto = true;
Kweku Adams62b42242017-09-25 12:54:02 -07006908 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
Dan Sandlera1770312015-07-10 13:59:29 -04006909 filter.redact = false;
6910 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
6911 if (ai < args.length-1) {
6912 ai++;
6913 filter.pkgFilter = args[ai].trim().toLowerCase();
6914 if (filter.pkgFilter.isEmpty()) {
6915 filter.pkgFilter = null;
6916 } else {
6917 filter.filtered = true;
6918 }
6919 }
6920 } else if ("--zen".equals(a) || "zen".equals(a)) {
6921 filter.filtered = true;
6922 filter.zen = true;
6923 } else if ("--stats".equals(a)) {
6924 filter.stats = true;
6925 if (ai < args.length-1) {
6926 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01006927 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04006928 } else {
6929 filter.since = 0;
6930 }
Vishnu Naire3e4d252018-03-01 11:26:57 -08006931 } else if (PRIORITY_ARG.equals(a)) {
6932 // Bugreport will call the service twice with priority arguments, first to dump
6933 // critical sections and then non critical ones. Set approriate filters
6934 // to generate the desired data.
6935 if (ai < args.length - 1) {
6936 ai++;
6937 switch (args[ai]) {
6938 case PRIORITY_ARG_CRITICAL:
6939 filter.criticalPriority = true;
6940 break;
6941 case PRIORITY_ARG_NORMAL:
6942 filter.normalPriority = true;
6943 break;
6944 }
6945 }
Dan Sandlera1770312015-07-10 13:59:29 -04006946 }
John Spurlock25e2d242014-06-27 13:58:23 -04006947 }
Dan Sandlera1770312015-07-10 13:59:29 -04006948 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04006949 }
6950
6951 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04006952 if (!filtered) return true;
6953 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04006954 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04006955 }
6956
6957 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04006958 if (!filtered) return true;
6959 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04006960 }
6961
6962 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04006963 if (!filtered) return true;
6964 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04006965 }
6966
6967 @Override
6968 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04006969 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04006970 }
6971 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07006972
Beverly5a20a5e2018-03-06 15:02:44 -05006973 @VisibleForTesting
6974 protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
6975 // only use for testing: mimic receive broadcast that package is (un)suspended
6976 // but does not actually (un)suspend the package
6977 final Bundle extras = new Bundle();
6978 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
6979 new String[]{pkg});
6980
6981 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
6982 : Intent.ACTION_PACKAGES_UNSUSPENDED;
6983 final Intent intent = new Intent(action);
6984 intent.putExtras(extras);
6985
6986 mPackageIntentReceiver.onReceive(getContext(), intent);
6987 }
6988
Griff Hazen84a00ea2014-09-02 17:10:47 -07006989 /**
6990 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
6991 * binder without sending large amounts of data over a oneway transaction.
6992 */
6993 private static final class StatusBarNotificationHolder
6994 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07006995 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006996
6997 public StatusBarNotificationHolder(StatusBarNotification value) {
6998 mValue = value;
6999 }
7000
Griff Hazene9aac5f2014-09-05 20:04:09 -07007001 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07007002 @Override
7003 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07007004 StatusBarNotification value = mValue;
7005 mValue = null;
7006 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07007007 }
7008 }
John Spurlock7c74f782015-06-04 13:01:42 -04007009
Julia Reynoldsb852e562017-06-06 16:14:18 -04007010 private class ShellCmd extends ShellCommand {
7011 public static final String USAGE = "help\n"
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007012 + "allow_listener COMPONENT [user_id]\n"
7013 + "disallow_listener COMPONENT [user_id]\n"
Julia Reynolds7380d872018-01-12 10:28:26 -05007014 + "allow_assistant COMPONENT\n"
Julia Reynoldseb3dca72017-07-11 10:39:58 -04007015 + "remove_assistant COMPONENT\n"
Julia Reynoldsb852e562017-06-06 16:14:18 -04007016 + "allow_dnd PACKAGE\n"
Beverly5a20a5e2018-03-06 15:02:44 -05007017 + "disallow_dnd PACKAGE\n"
7018 + "suspend_package PACKAGE\n"
7019 + "unsuspend_package PACKAGE";
John Spurlock7c74f782015-06-04 13:01:42 -04007020
Julia Reynoldsb852e562017-06-06 16:14:18 -04007021 @Override
7022 public int onCommand(String cmd) {
Felipe Leme68d80412017-07-14 11:18:08 -07007023 if (cmd == null) {
7024 return handleDefaultCommands(cmd);
7025 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007026 final PrintWriter pw = getOutPrintWriter();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04007027 try {
Julia Reynoldsb852e562017-06-06 16:14:18 -04007028 switch (cmd) {
7029 case "allow_dnd": {
7030 getBinderService().setNotificationPolicyAccessGranted(
7031 getNextArgRequired(), true);
John Spurlock7c74f782015-06-04 13:01:42 -04007032 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04007033 break;
7034
7035 case "disallow_dnd": {
7036 getBinderService().setNotificationPolicyAccessGranted(
7037 getNextArgRequired(), false);
7038 }
7039 break;
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007040 case "allow_listener": {
7041 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7042 if (cn == null) {
7043 pw.println("Invalid listener - must be a ComponentName");
7044 return -1;
7045 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007046 String userId = getNextArg();
7047 if (userId == null) {
7048 getBinderService().setNotificationListenerAccessGranted(cn, true);
7049 } else {
7050 getBinderService().setNotificationListenerAccessGrantedForUser(
7051 cn, Integer.parseInt(userId), true);
7052 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007053 }
7054 break;
7055 case "disallow_listener": {
7056 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7057 if (cn == null) {
7058 pw.println("Invalid listener - must be a ComponentName");
7059 return -1;
7060 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09007061 String userId = getNextArg();
7062 if (userId == null) {
7063 getBinderService().setNotificationListenerAccessGranted(cn, false);
7064 } else {
7065 getBinderService().setNotificationListenerAccessGrantedForUser(
7066 cn, Integer.parseInt(userId), false);
7067 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007068 }
7069 break;
Julia Reynoldseb3dca72017-07-11 10:39:58 -04007070 case "allow_assistant": {
7071 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7072 if (cn == null) {
7073 pw.println("Invalid assistant - must be a ComponentName");
7074 return -1;
7075 }
7076 getBinderService().setNotificationAssistantAccessGranted(cn, true);
7077 }
7078 break;
7079 case "disallow_assistant": {
7080 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
7081 if (cn == null) {
7082 pw.println("Invalid assistant - must be a ComponentName");
7083 return -1;
7084 }
7085 getBinderService().setNotificationAssistantAccessGranted(cn, false);
7086 }
7087 break;
Beverly5a20a5e2018-03-06 15:02:44 -05007088 case "suspend_package": {
7089 // only use for testing
7090 simulatePackageSuspendBroadcast(true, getNextArgRequired());
7091 }
7092 break;
7093 case "unsuspend_package": {
7094 // only use for testing
7095 simulatePackageSuspendBroadcast(false, getNextArgRequired());
7096 }
7097 break;
Julia Reynoldsb852e562017-06-06 16:14:18 -04007098 default:
7099 return handleDefaultCommands(cmd);
John Spurlock7c74f782015-06-04 13:01:42 -04007100 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04007101 } catch (Exception e) {
7102 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
Julia Reynoldsb852e562017-06-06 16:14:18 -04007103 Slog.e(TAG, "Error running shell command", e);
John Spurlock7c74f782015-06-04 13:01:42 -04007104 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04007105 return 0;
John Spurlock7c74f782015-06-04 13:01:42 -04007106 }
7107
Julia Reynoldsb852e562017-06-06 16:14:18 -04007108 @Override
7109 public void onHelp() {
7110 getOutPrintWriter().println(USAGE);
John Spurlock7c74f782015-06-04 13:01:42 -04007111 }
7112 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007113}