blob: c6886da55dfc438d62b42beba0215a23dfe03ffa [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 Reynoldsfc9767b2018-01-22 17:45:16 -050019import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050020import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
21import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
Julia Reynolds8617e4e2017-09-18 16:52:37 -040022import static android.app.NotificationManager.IMPORTANCE_LOW;
Julia Reynolds7c96b582017-05-25 12:35:36 -040023import static android.app.NotificationManager.IMPORTANCE_MIN;
Julia Reynolds85769912016-10-25 09:08:57 -040024import static android.app.NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -050025import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
26import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
27import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
28import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
29import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
30import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
31import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
32import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
33import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
34import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -050035import static android.content.pm.PackageManager.FEATURE_LEANBACK;
36import static android.content.pm.PackageManager.FEATURE_TELEVISION;
Julia Reynolds4db59552017-06-30 13:34:01 -040037import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Vishnu Naire3e4d252018-03-01 11:26:57 -080038import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
39import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040040import static android.os.UserHandle.USER_ALL;
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;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500101import android.app.backup.BackupManager;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700102import android.app.usage.UsageEvents;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700103import android.app.usage.UsageStatsManagerInternal;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400104import android.companion.ICompanionDeviceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105import android.content.BroadcastReceiver;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700106import android.content.ComponentName;
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400107import android.content.ContentProvider;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700108import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import android.content.Context;
110import android.content.Intent;
111import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -0400112import android.content.pm.ApplicationInfo;
Kenny Guy70058402014-10-28 20:45:06 +0000113import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114import android.content.pm.PackageManager;
115import android.content.pm.PackageManager.NameNotFoundException;
Christoph Studercee44ba2014-05-20 18:36:43 +0200116import android.content.pm.ParceledListSlice;
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400117import android.content.pm.UserInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700119import android.database.ContentObserver;
Beverly5d463b62017-07-26 14:13:40 -0400120import android.media.AudioAttributes;
svetoslavganov75986cf2009-05-14 22:28:01 -0700121import android.media.AudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500122import android.media.AudioManagerInternal;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700123import android.media.IRingtonePlayer;
Kenny Guy23991102018-04-05 21:18:38 +0100124import android.metrics.LogMaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126import android.os.Binder;
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -0400127import android.os.Build;
John Spurlock2b122f42014-08-27 16:29:47 -0400128import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -0400129import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130import android.os.Handler;
Chris Wrenf9536642014-04-17 10:01:54 -0400131import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132import android.os.IBinder;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800133import android.os.IDeviceIdleController;
John Spurlock7340fc82014-04-24 18:50:12 -0400134import android.os.IInterface;
Chris Wrenf9536642014-04-17 10:01:54 -0400135import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700137import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -0700138import android.os.RemoteException;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400139import android.os.ResultReceiver;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400140import android.os.ServiceManager;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400141import android.os.ShellCallback;
142import android.os.ShellCommand;
Chris Wrenc8673a82016-05-17 17:11:29 -0400143import android.os.SystemClock;
Selim Cinekb5605e52015-02-20 18:21:41 +0100144import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700145import android.os.UserHandle;
Michael Wright71216972017-01-31 18:33:54 +0000146import android.os.VibrationEffect;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500147import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148import android.provider.Settings;
Julia Reynoldse46bb372016-03-17 11:05:58 -0400149import android.service.notification.Adjustment;
Chris Wren333a61c2014-05-28 16:40:57 -0400150import android.service.notification.Condition;
John Spurlock7340fc82014-04-24 18:50:12 -0400151import android.service.notification.IConditionProvider;
Chris Wren333a61c2014-05-28 16:40:57 -0400152import android.service.notification.INotificationListener;
Griff Hazen84a00ea2014-09-02 17:10:47 -0700153import android.service.notification.IStatusBarNotificationHolder;
Kweku Adams93304b62017-09-20 17:03:00 -0700154import android.service.notification.ListenersDisablingEffectsProto;
Julia Reynolds77b2cc92016-11-08 14:41:09 -0500155import android.service.notification.NotificationAssistantService;
John Spurlock7340fc82014-04-24 18:50:12 -0400156import android.service.notification.NotificationListenerService;
Christoph Studer05ad4822014-05-16 14:16:03 +0200157import android.service.notification.NotificationRankingUpdate;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500158import android.service.notification.NotificationRecordProto;
159import android.service.notification.NotificationServiceDumpProto;
Julia Reynolds503ed942017-10-04 16:04:56 -0400160import android.service.notification.NotificationStats;
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500161import android.service.notification.NotifyingApp;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500162import android.service.notification.SnoozeCriterion;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700163import android.service.notification.StatusBarNotification;
John Spurlock056c5192014-04-20 21:52:01 -0400164import android.service.notification.ZenModeConfig;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500165import android.service.notification.ZenModeProto;
John Spurlock32fe4c62014-10-02 12:16:02 -0400166import android.telephony.PhoneStateListener;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500167import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -0700168import android.text.TextUtils;
John Spurlocka4294292014-03-24 18:02:32 -0400169import android.util.ArrayMap;
John Spurlock1fa865f2014-07-21 14:56:39 -0400170import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700171import android.util.AtomicFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -0800173import android.util.Slog;
Bryce Lee7219ada2016-04-08 10:54:23 -0700174import android.util.SparseArray;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400175import android.util.Xml;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500176import android.util.proto.ProtoOutputStream;
svetoslavganov75986cf2009-05-14 22:28:01 -0700177import android.view.accessibility.AccessibilityEvent;
178import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179import android.widget.Toast;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000180
Scott Greenwald9a05b312013-06-28 00:37:54 -0400181import com.android.internal.R;
Julia Reynolds88860ce2017-06-01 16:55:49 -0400182import com.android.internal.annotations.GuardedBy;
Chris Wren93bb8b82016-03-29 14:35:05 -0400183import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -0500184import com.android.internal.logging.MetricsLogger;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500185import com.android.internal.logging.nano.MetricsProto;
Chris Wren9eb5e102017-01-26 13:15:06 -0500186import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Beverly70dcd002018-03-29 17:09:16 -0400187import com.android.internal.notification.SystemNotificationChannels;
Eugene Suslaa25d17f2017-08-24 11:28:08 -0700188import com.android.internal.os.BackgroundThread;
Chris Wrend1dbc922015-06-19 17:51:16 -0400189import com.android.internal.statusbar.NotificationVisibility;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400190import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600191import com.android.internal.util.DumpUtils;
John Spurlock056c5192014-04-20 21:52:01 -0400192import com.android.internal.util.FastXmlSerializer;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400193import com.android.internal.util.Preconditions;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400194import com.android.internal.util.XmlUtils;
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700195import com.android.server.DeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800196import com.android.server.EventLogTags;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700197import com.android.server.LocalServices;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800198import com.android.server.SystemService;
199import com.android.server.lights.Light;
200import com.android.server.lights.LightsManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400201import com.android.server.notification.ManagedServices.ManagedServiceInfo;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500202import com.android.server.notification.ManagedServices.UserProfiles;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700203import com.android.server.policy.PhoneWindowManager;
John Spurlockb408e8e2014-04-23 21:12:45 -0400204import com.android.server.statusbar.StatusBarManagerInternal;
Adrian Roose99bc052017-11-20 17:55:31 +0100205import com.android.server.wm.WindowManagerInternal;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800206
John Spurlockb408e8e2014-04-23 21:12:45 -0400207import libcore.io.IoUtils;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000208
Chris Wrene4b38802015-07-07 15:54:19 -0400209import org.json.JSONException;
210import org.json.JSONObject;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700211import org.xmlpull.v1.XmlPullParser;
212import org.xmlpull.v1.XmlPullParserException;
John Spurlock056c5192014-04-20 21:52:01 -0400213import org.xmlpull.v1.XmlSerializer;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700214
John Spurlock35ef0a62015-05-28 11:24:10 -0400215import java.io.ByteArrayInputStream;
216import java.io.ByteArrayOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400217import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400219import java.io.FileNotFoundException;
John Spurlock056c5192014-04-20 21:52:01 -0400220import java.io.FileOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400221import java.io.IOException;
John Spurlock35ef0a62015-05-28 11:24:10 -0400222import java.io.InputStream;
223import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100225import java.nio.charset.StandardCharsets;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500226import java.util.ArrayDeque;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227import java.util.ArrayList;
Michael Wrightbc4d0d92017-03-23 18:57:57 +0000228import java.util.Arrays;
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400229import java.util.HashSet;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500230import java.util.Iterator;
John Spurlock7c74f782015-06-04 13:01:42 -0400231import java.util.List;
Christoph Studer265c1052014-07-23 17:14:33 +0200232import java.util.Map.Entry;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500233import java.util.Objects;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400234import java.util.Set;
Chris Wren51017d02015-12-15 15:34:46 -0500235import java.util.concurrent.TimeUnit;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400236
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400237/** {@hide} */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800238public class NotificationManagerService extends SystemService {
239 static final String TAG = "NotificationService";
Christoph Studer1f32c652014-11-26 15:32:20 +0100240 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Selim Cinek40412492015-12-08 18:03:22 -0800241 public static final boolean ENABLE_CHILD_NOTIFICATIONS
242 = SystemProperties.getBoolean("debug.child_notifs", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243
Adam Lesinski182f73f2013-12-05 16:48:06 -0800244 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
Julia Reynolds6ad0aec2017-07-05 08:47:03 -0400245 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
Joe Onoratobd73d012010-06-04 11:44:54 -0700246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 // message codes
Robert Carr997427342018-02-28 18:06:10 -0800248 static final int MESSAGE_DURATION_REACHED = 2;
John Spurlock056c5192014-04-20 21:52:01 -0400249 static final int MESSAGE_SAVE_POLICY_FILE = 3;
Chris Wren51017d02015-12-15 15:34:46 -0500250 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
251 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
252 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
Robert Carr997427342018-02-28 18:06:10 -0800253 static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
Chris Wren51017d02015-12-15 15:34:46 -0500254
255 // ranking thread messages
256 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
257 private static final int MESSAGE_RANKING_SORT = 1001;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700259 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800260 static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800261
Robert Carr3406d462018-03-15 16:19:07 -0700262 // 1 second past the ANR timeout.
263 static final int FINISH_TOKEN_TIMEOUT = 11 * 1000;
264
Adam Lesinski182f73f2013-12-05 16:48:06 -0800265 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
Christoph Studer265c1052014-07-23 17:14:33 +0200266
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500267 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
268
Adam Lesinski182f73f2013-12-05 16:48:06 -0800269 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270
Adam Lesinski182f73f2013-12-05 16:48:06 -0800271 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler526fa0e2012-12-04 14:51:50 -0500272
Adam Lesinski182f73f2013-12-05 16:48:06 -0800273 static final boolean ENABLE_BLOCKED_TOASTS = true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400274
Christoph Studer12aeda82014-09-23 19:08:56 +0200275 // When #matchesCallFilter is called from the ringer, wait at most
276 // 3s to resolve the contacts. This timeout is required since
277 // ContactsProvider might take a long time to start up.
278 //
279 // Return STARRED_CONTACT when the timeout is hit in order to avoid
280 // missed calls in ZEN mode "Important".
281 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
282 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
283 ValidateNotificationPeople.STARRED_CONTACT;
284
Christoph Studer265c1052014-07-23 17:14:33 +0200285 /** notification_enqueue status value for a newly enqueued notification. */
286 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
287
288 /** notification_enqueue status value for an existing notification. */
289 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
290
291 /** notification_enqueue status value for an ignored notification. */
292 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
Chris Wrenc8673a82016-05-17 17:11:29 -0400293 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
Christoph Studer265c1052014-07-23 17:14:33 +0200294
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500295 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
296
Julia Reynolds2a128742016-11-28 14:29:25 -0500297 private static final String ACTION_NOTIFICATION_TIMEOUT =
298 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
299 private static final int REQUEST_CODE_TIMEOUT = 1;
300 private static final String SCHEME_TIMEOUT = "timeout";
301 private static final String EXTRA_KEY = "key";
302
Adam Lesinski182f73f2013-12-05 16:48:06 -0800303 private IActivityManager mAm;
Julia Reynolds68263d12017-06-21 14:21:19 -0400304 private ActivityManager mActivityManager;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500305 private IPackageManager mPackageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500306 private PackageManager mPackageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800307 AudioManager mAudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500308 AudioManagerInternal mAudioManagerInternal;
Wei Liu97e56662016-03-04 10:52:33 -0800309 @Nullable StatusBarManagerInternal mStatusBar;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800310 Vibrator mVibrator;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700311 private WindowManagerInternal mWindowManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -0500312 private AlarmManager mAlarmManager;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400313 private ICompanionDeviceManager mCompanionManager;
Julia Reynolds94187562017-10-10 13:58:49 -0400314 private AccessibilityManager mAccessibilityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800315 private IDeviceIdleController mDeviceIdleController;
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400316 private IBinder mPermissionOwner;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 final IBinder mForegroundToken = new Binder();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400319 private WorkerHandler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400320 private final HandlerThread mRankingThread = new HandlerThread("ranker",
321 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322
Adam Lesinski182f73f2013-12-05 16:48:06 -0800323 private Light mNotificationLight;
324 Light mAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800325
Daniel Sandleredbb3802012-11-13 20:49:47 -0800326 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400327 private boolean mUseAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800328 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800329
John Spurlockd8afe3c2014-08-01 14:04:07 -0400330 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400331 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500332 private String mSoundNotificationKey;
333 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334
Bryce Lee7219ada2016-04-08 10:54:23 -0700335 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400336 new SparseArray<>();
337 private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400338 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500339 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400340
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500341 // for enabling and disabling notification pulse behavior
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400342 private boolean mScreenOn = true;
Beverly5d463b62017-07-26 14:13:40 -0400343 protected boolean mInCall = false;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500344 private boolean mNotificationPulseEnabled;
345
Beverly5d463b62017-07-26 14:13:40 -0400346 private Uri mInCallNotificationUri;
347 private AudioAttributes mInCallNotificationAudioAttributes;
348 private float mInCallNotificationVolume;
Marta Białka39c992f2011-03-10 10:27:24 +0100349
Daniel Sandler09a247e2013-02-14 10:24:17 -0500350 // used as a mutex for access to all active notifications & listeners
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500351 final Object mNotificationLock = new Object();
Julia Reynolds0839c022017-06-15 15:24:01 -0400352 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400353 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400354 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400355 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400356 @GuardedBy("mNotificationLock")
Chris Wren6676dab2016-12-21 18:26:27 -0500357 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400358 @GuardedBy("mNotificationLock")
Julia Reynoldseae43fb2016-05-09 12:42:58 -0400359 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400360 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
Christoph Studer265c1052014-07-23 17:14:33 +0200361 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500362 final ArrayMap<Integer, ArrayList<NotifyingApp>> mRecentApps = new ArrayMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363
Chris Wren6054e612014-11-25 17:16:46 -0500364 // The last key in this list owns the hardware.
365 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700366
Adam Lesinski182f73f2013-12-05 16:48:06 -0800367 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700368 private UsageStatsManagerInternal mAppUsageStats;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500369
Griff Hazen9f637d12014-06-10 11:13:51 -0700370 private Archive mArchive;
371
John Spurlock21258a32015-05-27 18:22:55 -0400372 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400373 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400374
Daniel Sandler0da673f2012-04-11 12:33:16 -0400375 private static final int DB_VERSION = 1;
376
John Spurlock21258a32015-05-27 18:22:55 -0400377 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400378 private static final String ATTR_VERSION = "version";
379
Chris Wren54bbef42014-07-09 18:37:56 -0400380 private RankingHelper mRankingHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400381
John Spurlockb408e8e2014-04-23 21:12:45 -0400382 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400383 private NotificationListeners mListeners;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400384 private NotificationAssistants mAssistants;
John Spurlock7340fc82014-04-24 18:50:12 -0400385 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200386 private NotificationUsageStats mUsageStats;
Christoph Studer546bec82014-03-14 12:17:12 +0100387
John Spurlocke6a7d932014-03-13 12:29:00 -0400388 private static final int MY_UID = Process.myUid();
389 private static final int MY_PID = Process.myPid();
Dianne Hackborn98305522017-05-05 17:53:53 -0700390 private static final IBinder WHITELIST_TOKEN = new Binder();
Chris Wren51017d02015-12-15 15:34:46 -0500391 private RankingHandler mRankingHandler;
Chris Wrenc8673a82016-05-17 17:11:29 -0400392 private long mLastOverRateLogTime;
Chris Wren763a9bb2016-05-31 17:14:12 -0400393 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
John Spurlocke6a7d932014-03-13 12:29:00 -0400394
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400395 private SnoozeHelper mSnoozeHelper;
Julia Reynolds8f488d32016-10-14 10:59:01 -0400396 private GroupHelper mGroupHelper;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -0500397 private boolean mIsTelevision;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400398
Kenny Guy23991102018-04-05 21:18:38 +0100399 private MetricsLogger mMetricsLogger;
400
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500401 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700402 final int mBufferSize;
403 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500404
Griff Hazen9f637d12014-06-10 11:13:51 -0700405 public Archive(int size) {
406 mBufferSize = size;
407 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500408 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700409
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400410 public String toString() {
411 final StringBuilder sb = new StringBuilder();
412 final int N = mBuffer.size();
413 sb.append("Archive (");
414 sb.append(N);
415 sb.append(" notification");
416 sb.append((N==1)?")":"s)");
417 return sb.toString();
418 }
419
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500420 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700421 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500422 mBuffer.removeFirst();
423 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400424
425 // We don't want to store the heavy bits of the notification in the archive,
426 // but other clients in the system process might be using the object, so we
427 // store a (lightened) copy.
428 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500429 }
430
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500431 public Iterator<StatusBarNotification> descendingIterator() {
432 return mBuffer.descendingIterator();
433 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500434
435 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700436 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500437 final StatusBarNotification[] a
438 = new StatusBarNotification[Math.min(count, mBuffer.size())];
439 Iterator<StatusBarNotification> iter = descendingIterator();
440 int i=0;
441 while (iter.hasNext() && i < count) {
442 a[i++] = iter.next();
443 }
444 return a;
445 }
446
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500447 }
448
Julia Reynolds88a879f2017-07-26 17:06:46 -0400449 protected void readDefaultApprovedServices(int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400450 String defaultListenerAccess = getContext().getResources().getString(
451 com.android.internal.R.string.config_defaultListenerAccessPackages);
452 if (defaultListenerAccess != null) {
453 for (String whitelisted :
454 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
455 // Gather all notification listener components for candidate pkgs.
456 Set<ComponentName> approvedListeners =
457 mListeners.queryPackageForServices(whitelisted,
458 PackageManager.MATCH_DIRECT_BOOT_AWARE
459 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
460 for (ComponentName cn : approvedListeners) {
461 try {
462 getBinderService().setNotificationListenerAccessGrantedForUser(cn,
463 userId, true);
464 } catch (RemoteException e) {
465 e.printStackTrace();
466 }
467 }
468 }
469 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500470
Julia Reynoldsb852e562017-06-06 16:14:18 -0400471 String defaultDndAccess = getContext().getResources().getString(
472 com.android.internal.R.string.config_defaultDndAccessPackages);
473 if (defaultListenerAccess != null) {
474 for (String whitelisted :
475 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
476 try {
477 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
478 } catch (RemoteException e) {
479 e.printStackTrace();
480 }
481 }
482 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500483
484 readDefaultAssistant(userId);
485 }
486
487 protected void readDefaultAssistant(int userId) {
488 String defaultAssistantAccess = getContext().getResources().getString(
489 com.android.internal.R.string.config_defaultAssistantAccessPackage);
490 if (defaultAssistantAccess != null) {
491 // Gather all notification assistant components for candidate pkg. There should
492 // only be one
493 Set<ComponentName> approvedAssistants =
494 mAssistants.queryPackageForServices(defaultAssistantAccess,
495 PackageManager.MATCH_DIRECT_BOOT_AWARE
496 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
497 for (ComponentName cn : approvedAssistants) {
498 try {
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400499 getBinderService().setNotificationAssistantAccessGrantedForUser(
500 cn, userId, true);
Julia Reynolds7380d872018-01-12 10:28:26 -0500501 } catch (RemoteException e) {
502 e.printStackTrace();
503 }
504 }
505 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400506 }
507
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400508 void readPolicyXml(InputStream stream, boolean forRestore)
John Spurlock35ef0a62015-05-28 11:24:10 -0400509 throws XmlPullParserException, NumberFormatException, IOException {
510 final XmlPullParser parser = Xml.newPullParser();
511 parser.setInput(stream, StandardCharsets.UTF_8.name());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400512 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
513 boolean migratedManagedServices = false;
514 int outerDepth = parser.getDepth();
515 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
516 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
517 mZenModeHelper.readXml(parser, forRestore);
518 } else if (RankingHelper.TAG_RANKING.equals(parser.getName())){
519 mRankingHelper.readXml(parser, forRestore);
520 }
Julia Reynolds68263d12017-06-21 14:21:19 -0400521 // No non-system managed services are allowed on low ram devices
Julia Reynoldse1816412017-10-24 10:39:11 -0400522 if (canUseManagedServices()) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400523 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
524 mListeners.readXml(parser);
525 migratedManagedServices = true;
526 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
527 mAssistants.readXml(parser);
528 migratedManagedServices = true;
529 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
530 mConditionProviders.readXml(parser);
531 migratedManagedServices = true;
532 }
Julia Reynolds68263d12017-06-21 14:21:19 -0400533 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400534 }
535
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400536 if (!migratedManagedServices) {
537 mListeners.migrateToXml();
538 mAssistants.migrateToXml();
539 mConditionProviders.migrateToXml();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400540 savePolicyFile();
John Spurlock35ef0a62015-05-28 11:24:10 -0400541 }
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400542
543 mAssistants.ensureAssistant();
John Spurlock35ef0a62015-05-28 11:24:10 -0400544 }
545
John Spurlock056c5192014-04-20 21:52:01 -0400546 private void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400547 if (DBG) Slog.d(TAG, "loadPolicyFile");
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500548 synchronized (mPolicyFile) {
Daniel Sandler0da673f2012-04-11 12:33:16 -0400549
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400550 InputStream infile = null;
John Spurlock056c5192014-04-20 21:52:01 -0400551 try {
552 infile = mPolicyFile.openRead();
John Spurlock35ef0a62015-05-28 11:24:10 -0400553 readPolicyXml(infile, false /*forRestore*/);
John Spurlock056c5192014-04-20 21:52:01 -0400554 } catch (FileNotFoundException e) {
555 // No data yet
Julia Reynoldsb852e562017-06-06 16:14:18 -0400556 // Load default managed services approvals
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400557 readDefaultApprovedServices(USER_SYSTEM);
John Spurlock056c5192014-04-20 21:52:01 -0400558 } catch (IOException e) {
559 Log.wtf(TAG, "Unable to read notification policy", e);
560 } catch (NumberFormatException e) {
561 Log.wtf(TAG, "Unable to parse notification policy", e);
562 } catch (XmlPullParserException e) {
563 Log.wtf(TAG, "Unable to parse notification policy", e);
564 } finally {
565 IoUtils.closeQuietly(infile);
566 }
567 }
568 }
569
570 public void savePolicyFile() {
571 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
572 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
573 }
574
575 private void handleSavePolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400576 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400577 synchronized (mPolicyFile) {
578 final FileOutputStream stream;
579 try {
580 stream = mPolicyFile.startWrite();
581 } catch (IOException e) {
582 Slog.w(TAG, "Failed to save policy file", e);
583 return;
584 }
585
586 try {
John Spurlock35ef0a62015-05-28 11:24:10 -0400587 writePolicyXml(stream, false /*forBackup*/);
John Spurlock056c5192014-04-20 21:52:01 -0400588 mPolicyFile.finishWrite(stream);
589 } catch (IOException e) {
590 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
591 mPolicyFile.failWrite(stream);
Daniel Sandler0da673f2012-04-11 12:33:16 -0400592 }
593 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400594 BackupManager.dataChanged(getContext().getPackageName());
595 }
596
597 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
598 final XmlSerializer out = new FastXmlSerializer();
599 out.setOutput(stream, StandardCharsets.UTF_8.name());
600 out.startDocument(null, true);
601 out.startTag(null, TAG_NOTIFICATION_POLICY);
602 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
Beverly4e2f76c2018-03-16 15:43:49 -0400603 mZenModeHelper.writeXml(out, forBackup, null);
John Spurlock35ef0a62015-05-28 11:24:10 -0400604 mRankingHelper.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400605 mListeners.writeXml(out, forBackup);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400606 mAssistants.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400607 mConditionProviders.writeXml(out, forBackup);
John Spurlock35ef0a62015-05-28 11:24:10 -0400608 out.endTag(null, TAG_NOTIFICATION_POLICY);
609 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400610 }
611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 private static final class ToastRecord
613 {
614 final int pid;
615 final String pkg;
Beverly4ee785b2017-08-11 12:49:56 -0400616 ITransientNotification callback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800617 int duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700618 Binder token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700620 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
621 Binder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 this.pid = pid;
623 this.pkg = pkg;
624 this.callback = callback;
625 this.duration = duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700626 this.token = token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 }
628
629 void update(int duration) {
630 this.duration = duration;
631 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800632
Beverly4ee785b2017-08-11 12:49:56 -0400633 void update(ITransientNotification callback) {
634 this.callback = callback;
635 }
636
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
Christoph Studer03b87a22014-04-30 17:33:27 +0200693 public void onNotificationClick(int callingUid, int callingPid, String key) {
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)
704 .setType(MetricsEvent.TYPE_ACTION));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400705 EventLogTags.writeNotificationClicked(key,
706 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
707
Christoph Studer03b87a22014-04-30 17:33:27 +0200708 StatusBarNotification sbn = r.sbn;
709 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
710 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
711 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400712 REASON_CLICK, null);
Amith Yamasani7ec89412018-02-07 08:48:49 -0800713 reportUserInteraction(r);
Christoph Studer03b87a22014-04-30 17:33:27 +0200714 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 }
716
Adam Lesinski182f73f2013-12-05 16:48:06 -0800717 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200718 public void onNotificationActionClick(int callingUid, int callingPid, String key,
719 int actionIndex) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800720 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500721 synchronized (mNotificationLock) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200722 NotificationRecord r = mNotificationsByKey.get(key);
723 if (r == null) {
724 Log.w(TAG, "No notification with key: " + key);
725 return;
726 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400727 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500728 MetricsLogger.action(r.getLogMaker(now)
729 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
730 .setType(MetricsEvent.TYPE_ACTION)
731 .setSubtype(actionIndex));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400732 EventLogTags.writeNotificationActionClicked(key, actionIndex,
733 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Amith Yamasani7ec89412018-02-07 08:48:49 -0800734 reportUserInteraction(r);
Christoph Studer4da84cd2014-10-21 17:24:20 +0200735 }
736 }
737
738 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400739 public void onNotificationClear(int callingUid, int callingPid,
Julia Reynolds503ed942017-10-04 16:04:56 -0400740 String pkg, String tag, int id, int userId, String key,
741 @NotificationStats.DismissalSurface int dismissalSurface) {
742 synchronized (mNotificationLock) {
743 NotificationRecord r = mNotificationsByKey.get(key);
744 if (r != null) {
745 r.recordDismissalSurface(dismissalSurface);
746 }
747 }
John Spurlocke6a7d932014-03-13 12:29:00 -0400748 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000749 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400750 true, userId, REASON_CANCEL, null);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400751 }
752
Adam Lesinski182f73f2013-12-05 16:48:06 -0800753 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400754 public void onPanelRevealed(boolean clearEffects, int items) {
Chris Wren9eb5e102017-01-26 13:15:06 -0500755 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Chris Wren621933f2017-06-14 15:59:03 -0400756 MetricsLogger.histogram(getContext(), "note_load", items);
Chris Wrenb659c4f2015-06-25 17:12:27 -0400757 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100758 if (clearEffects) {
759 clearEffects();
760 }
761 }
762
763 @Override
764 public void onPanelHidden() {
Chris Wren9eb5e102017-01-26 13:15:06 -0500765 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Christoph Studer1f32c652014-11-26 15:32:20 +0100766 EventLogTags.writeNotificationPanelHidden();
767 }
768
769 @Override
770 public void clearEffects() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500771 synchronized (mNotificationLock) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100772 if (DBG) Slog.d(TAG, "clearEffects");
Chris Wren93bb8b82016-03-29 14:35:05 -0400773 clearSoundLocked();
774 clearVibrateLocked();
775 clearLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 }
777 }
Joe Onorato005847b2010-06-04 16:08:02 -0400778
Adam Lesinski182f73f2013-12-05 16:48:06 -0800779 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400780 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000781 int uid, int initialPid, String message, int userId) {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400782 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
783 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
John Spurlocke6a7d932014-03-13 12:29:00 -0400784 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400785 REASON_ERROR, null);
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700786 long ident = Binder.clearCallingIdentity();
787 try {
Christopher Tate8aa8fe12017-01-20 17:50:32 -0800788 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700789 "Bad notification posted from package " + pkg
790 + ": " + message);
791 } catch (RemoteException e) {
792 }
793 Binder.restoreCallingIdentity(ident);
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 }
Chris Wrend1dbc922015-06-19 17:51:16 -0400820 r.setVisibility(true, nv.rank);
821 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200822 }
823 // Note that we might receive this event after notifications
824 // have already left the system, e.g. after dismissing from the
825 // shade. Hence not finding notifications in
826 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400827 for (NotificationVisibility nv : noLongerVisibleKeys) {
828 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200829 if (r == null) continue;
Chris Wrend1dbc922015-06-19 17:51:16 -0400830 r.setVisibility(false, nv.rank);
831 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200832 }
833 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200834 }
Chris Wren78403d72014-07-28 10:23:24 +0100835
836 @Override
837 public void onNotificationExpansionChanged(String key,
838 boolean userAction, boolean expanded) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500839 synchronized (mNotificationLock) {
Chris Wren78403d72014-07-28 10:23:24 +0100840 NotificationRecord r = mNotificationsByKey.get(key);
841 if (r != null) {
842 r.stats.onExpansionChanged(userAction, expanded);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400843 final long now = System.currentTimeMillis();
Chris Wrenf7342712017-09-14 10:55:55 -0400844 if (userAction) {
Chris Wren377ac6d2017-09-12 14:15:23 -0400845 MetricsLogger.action(r.getLogMaker(now)
846 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
Chris Wrenf7342712017-09-14 10:55:55 -0400847 .setType(expanded ? MetricsEvent.TYPE_DETAIL
848 : MetricsEvent.TYPE_COLLAPSE));
Chris Wren377ac6d2017-09-12 14:15:23 -0400849 }
Julia Reynolds84dc96b2017-11-14 09:51:01 -0500850 if (expanded && userAction) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400851 r.recordExpanded();
852 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400853 EventLogTags.writeNotificationExpansion(key,
854 userAction ? 1 : 0, expanded ? 1 : 0,
855 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Chris Wren78403d72014-07-28 10:23:24 +0100856 }
857 }
858 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400859
860 @Override
861 public void onNotificationDirectReplied(String key) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800862 exitIdle();
Julia Reynolds503ed942017-10-04 16:04:56 -0400863 synchronized (mNotificationLock) {
864 NotificationRecord r = mNotificationsByKey.get(key);
865 if (r != null) {
866 r.recordDirectReplied();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800867 reportUserInteraction(r);
Julia Reynolds503ed942017-10-04 16:04:56 -0400868 }
869 }
870 }
871
872 @Override
Kenny Guy23991102018-04-05 21:18:38 +0100873 public void onNotificationSmartRepliesAdded(String key, int replyCount) {
874 synchronized (mNotificationLock) {
875 NotificationRecord r = mNotificationsByKey.get(key);
876 if (r != null) {
877 r.setNumSmartRepliesAdded(replyCount);
878 }
879 }
880 }
881
882 @Override
883 public void onNotificationSmartReplySent(String key, int replyIndex) {
884 synchronized (mNotificationLock) {
885 NotificationRecord r = mNotificationsByKey.get(key);
886 if (r != null) {
887 LogMaker logMaker = r.getLogMaker()
888 .setCategory(MetricsEvent.SMART_REPLY_ACTION)
889 .setSubtype(replyIndex);
890 mMetricsLogger.write(logMaker);
891 // Treat clicking on a smart reply as a user interaction.
892 reportUserInteraction(r);
893 }
894 }
895 }
896
897 @Override
Julia Reynolds503ed942017-10-04 16:04:56 -0400898 public void onNotificationSettingsViewed(String key) {
899 synchronized (mNotificationLock) {
900 NotificationRecord r = mNotificationsByKey.get(key);
901 if (r != null) {
902 r.recordViewedSettings();
903 }
904 }
905 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906 };
907
Julia Reynolds88860ce2017-06-01 16:55:49 -0400908 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400909 private void clearSoundLocked() {
910 mSoundNotificationKey = null;
911 long identity = Binder.clearCallingIdentity();
912 try {
913 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
914 if (player != null) {
915 player.stopAsync();
916 }
917 } catch (RemoteException e) {
918 } finally {
919 Binder.restoreCallingIdentity(identity);
920 }
921 }
922
Julia Reynolds88860ce2017-06-01 16:55:49 -0400923 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400924 private void clearVibrateLocked() {
925 mVibrateNotificationKey = null;
926 long identity = Binder.clearCallingIdentity();
927 try {
928 mVibrator.cancel();
929 } finally {
930 Binder.restoreCallingIdentity(identity);
931 }
932 }
933
Julia Reynolds88860ce2017-06-01 16:55:49 -0400934 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400935 private void clearLightsLocked() {
936 // light
937 mLights.clear();
938 updateLightsLocked();
939 }
940
Beverlyd4f96492017-08-02 13:36:11 -0400941 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
942 @Override
943 public void onReceive(Context context, Intent intent) {
944 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
Beverly70dcd002018-03-29 17:09:16 -0400945 // update system notification channels
946 SystemNotificationChannels.createAll(context);
Beverlyd4f96492017-08-02 13:36:11 -0400947 mZenModeHelper.updateDefaultZenRules();
Julia Reynolds816797a2017-08-11 15:47:09 -0400948 mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
Beverlyd4f96492017-08-02 13:36:11 -0400949 }
950 }
951 };
952
Julia Reynoldsb852e562017-06-06 16:14:18 -0400953 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
954 @Override
955 public void onReceive(Context context, Intent intent) {
956 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
957 try {
958 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
959 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
Michal Karpinski6135a262017-08-11 10:45:58 +0100960 int restoredFromSdkInt = intent.getIntExtra(
961 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400962 mListeners.onSettingRestored(
963 element, newValue, restoredFromSdkInt, getSendingUserId());
964 mConditionProviders.onSettingRestored(
965 element, newValue, restoredFromSdkInt, getSendingUserId());
Julia Reynoldsb852e562017-06-06 16:14:18 -0400966 } catch (Exception e) {
967 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
968 }
969 }
970 }
971 };
972
Julia Reynolds2a128742016-11-28 14:29:25 -0500973 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
974 @Override
975 public void onReceive(Context context, Intent intent) {
976 String action = intent.getAction();
977 if (action == null) {
978 return;
979 }
980 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
981 final NotificationRecord record;
982 synchronized (mNotificationLock) {
983 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
984 }
985 if (record != null) {
986 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
987 record.sbn.getPackageName(), record.sbn.getTag(),
988 record.sbn.getId(), 0,
989 Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
990 REASON_TIMEOUT, null);
991 }
992 }
993 }
994 };
995
Kenny Guy70058402014-10-28 20:45:06 +0000996 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 @Override
998 public void onReceive(Context context, Intent intent) {
999 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -08001000 if (action == null) {
1001 return;
1002 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001004 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -04001005 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -04001006 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -04001007 boolean cancelNotifications = true;
Beverly5a20a5e2018-03-06 15:02:44 -05001008 boolean hideNotifications = false;
1009 boolean unhideNotifications = false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001010 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -04001011
Chris Wren3da73022013-05-10 14:41:21 -04001012 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -04001013 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001014 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -04001015 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001016 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001017 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
Beverly5a20a5e2018-03-06 15:02:44 -05001018 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
1019 || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
Kenny Guy70058402014-10-28 20:45:06 +00001020 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1021 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001022 String pkgList[] = null;
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001023 int uidList[] = null;
Julia Reynolds6434eb22016-08-08 17:19:26 -04001024 boolean removingPackage = queryRemove &&
1025 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
1026 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001027 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001028 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001029 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001030 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
1031 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Beverly5a20a5e2018-03-06 15:02:44 -05001032 cancelNotifications = false;
1033 hideNotifications = true;
1034 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
1035 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1036 cancelNotifications = false;
1037 unhideNotifications = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001038 } else if (queryRestart) {
1039 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001040 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001041 } else {
1042 Uri uri = intent.getData();
1043 if (uri == null) {
1044 return;
1045 }
1046 String pkgName = uri.getSchemeSpecificPart();
1047 if (pkgName == null) {
1048 return;
1049 }
Daniel Sandler26ece572012-06-01 15:38:46 -04001050 if (packageChanged) {
1051 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -07001052 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001053 final int enabled = mPackageManager.getApplicationEnabledSetting(
1054 pkgName,
Kenny Guy70058402014-10-28 20:45:06 +00001055 changeUserId != UserHandle.USER_ALL ? changeUserId :
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001056 USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -07001057 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1058 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
1059 cancelNotifications = false;
1060 }
1061 } catch (IllegalArgumentException e) {
1062 // Package doesn't exist; probably racing with uninstall.
1063 // cancelNotifications is already true, so nothing to do here.
1064 if (DBG) {
1065 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
1066 }
Kenny Guy70058402014-10-28 20:45:06 +00001067 } catch (RemoteException e) {
1068 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -04001069 }
1070 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001071 pkgList = new String[]{pkgName};
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001072 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001074 if (pkgList != null && (pkgList.length > 0)) {
1075 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -04001076 if (cancelNotifications) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001077 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
1078 !queryRestart, changeUserId, reason, null);
Beverly5a20a5e2018-03-06 15:02:44 -05001079 } else if (hideNotifications) {
1080 hideNotificationsForPackages(pkgList);
1081 } else if (unhideNotifications) {
1082 unhideNotificationsForPackages(pkgList);
John Spurlock79f78922013-05-16 09:10:05 -04001083 }
Beverly5a20a5e2018-03-06 15:02:44 -05001084
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001085 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 }
Beverly5a20a5e2018-03-06 15:02:44 -05001087
Julia Reynoldsb852e562017-06-06 16:14:18 -04001088 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001089 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsb852e562017-06-06 16:14:18 -04001090 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001091 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
1092 savePolicyFile();
Kenny Guy70058402014-10-28 20:45:06 +00001093 }
1094 }
1095 };
1096
1097 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1098 @Override
1099 public void onReceive(Context context, Intent intent) {
1100 String action = intent.getAction();
1101
1102 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001103 // Keep track of screen on/off state, but do not turn off the notification light
1104 // until user passes through the lock screen or views the notification.
1105 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +01001106 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001107 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1108 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +01001109 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001110 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -05001111 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
1112 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001113 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001114 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
1115 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1116 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001117 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001118 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001119 }
Rubin Xue95057a2016-04-01 16:49:25 +01001120 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001121 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +01001122 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001123 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001124 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001125 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001126 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1127 // turn off LED when user passes through lock screen
1128 mNotificationLight.turnOff();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001129 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001130 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001131 // reload per-user settings
1132 mSettingsObserver.update(null);
John Spurlockb408e8e2014-04-23 21:12:45 -04001133 mUserProfiles.updateCache(context);
Christoph Studerb53dfd42014-09-12 14:45:59 +02001134 // Refresh managed services
John Spurlock1b8b22b2015-05-20 09:47:13 -04001135 mConditionProviders.onUserSwitched(user);
1136 mListeners.onUserSwitched(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001137 mAssistants.onUserSwitched(user);
John Spurlock21258a32015-05-27 18:22:55 -04001138 mZenModeHelper.onUserSwitched(user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001139 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001140 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1141 if (userId != USER_NULL) {
1142 mUserProfiles.updateCache(context);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001143 if (!mUserProfiles.isManagedProfile(userId)) {
1144 readDefaultApprovedServices(userId);
1145 }
Julia Reynolds88a879f2017-07-26 17:06:46 -04001146 }
John Spurlock21258a32015-05-27 18:22:55 -04001147 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001148 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001149 mUserProfiles.updateCache(context);
John Spurlock21258a32015-05-27 18:22:55 -04001150 mZenModeHelper.onUserRemoved(user);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -04001151 mRankingHelper.onUserRemoved(user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001152 mListeners.onUserRemoved(user);
1153 mConditionProviders.onUserRemoved(user);
1154 mAssistants.onUserRemoved(user);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -04001155 savePolicyFile();
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001156 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001157 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001158 mConditionProviders.onUserUnlocked(user);
1159 mListeners.onUserUnlocked(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001160 mAssistants.onUserUnlocked(user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001161 mZenModeHelper.onUserUnlocked(user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 }
1163 }
1164 };
1165
John Spurlock7c74f782015-06-04 13:01:42 -04001166 private final class SettingsObserver extends ContentObserver {
Chris Wren89aa2262017-05-05 18:05:56 -04001167 private final Uri NOTIFICATION_BADGING_URI
1168 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001169 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1170 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wren763a9bb2016-05-31 17:14:12 -04001171 private final Uri NOTIFICATION_RATE_LIMIT_URI
1172 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001173
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001174 SettingsObserver(Handler handler) {
1175 super(handler);
1176 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001177
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001178 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001179 ContentResolver resolver = getContext().getContentResolver();
Chris Wren89aa2262017-05-05 18:05:56 -04001180 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1181 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001182 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -07001183 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -04001184 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1185 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001186 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001187 }
1188
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001189 @Override public void onChange(boolean selfChange, Uri uri) {
1190 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001191 }
1192
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001193 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001194 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001195 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
zhoulei7e376972017-05-17 18:41:25 +08001196 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
1197 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001198 if (mNotificationPulseEnabled != pulseEnabled) {
1199 mNotificationPulseEnabled = pulseEnabled;
1200 updateNotificationPulse();
1201 }
1202 }
Chris Wren763a9bb2016-05-31 17:14:12 -04001203 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1204 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1205 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1206 }
Chris Wren89aa2262017-05-05 18:05:56 -04001207 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
1208 mRankingHelper.updateBadgingEnabled();
1209 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001210 }
1211 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001212
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001213 private SettingsObserver mSettingsObserver;
Beverlyd4f96492017-08-02 13:36:11 -04001214 protected ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001215
Daniel Sandleredbb3802012-11-13 20:49:47 -08001216 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1217 int[] ar = r.getIntArray(resid);
1218 if (ar == null) {
1219 return def;
1220 }
1221 final int len = ar.length > maxlen ? maxlen : ar.length;
1222 long[] out = new long[len];
1223 for (int i=0; i<len; i++) {
1224 out[i] = ar[i];
1225 }
1226 return out;
1227 }
1228
Jeff Brownb880d882014-02-10 19:47:07 -08001229 public NotificationManagerService(Context context) {
1230 super(context);
Dianne Hackborn98305522017-05-05 17:53:53 -07001231 Notification.processWhitelistToken = WHITELIST_TOKEN;
Jeff Brownb880d882014-02-10 19:47:07 -08001232 }
1233
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001234 // TODO - replace these methods with a single VisibleForTesting constructor
Chris Wren93bb8b82016-03-29 14:35:05 -04001235 @VisibleForTesting
1236 void setAudioManager(AudioManager audioMananger) {
1237 mAudioManager = audioMananger;
1238 }
1239
1240 @VisibleForTesting
1241 void setVibrator(Vibrator vibrator) {
1242 mVibrator = vibrator;
1243 }
1244
1245 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001246 void setLights(Light light) {
1247 mNotificationLight = light;
1248 mAttentionLight = light;
Julia Reynolds033a4122017-01-31 16:50:38 -05001249 mNotificationPulseEnabled = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001250 }
1251
1252 @VisibleForTesting
1253 void setScreenOn(boolean on) {
1254 mScreenOn = on;
1255 }
1256
1257 @VisibleForTesting
Julia Reynolds080361e2017-07-13 11:23:12 -04001258 int getNotificationRecordCount() {
1259 synchronized (mNotificationLock) {
1260 int count = mNotificationList.size() + mNotificationsByKey.size()
1261 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1262 // subtract duplicates
1263 for (NotificationRecord posted : mNotificationList) {
1264 if (mNotificationsByKey.containsKey(posted.getKey())) {
1265 count--;
1266 }
1267 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001268 count--;
Julia Reynolds080361e2017-07-13 11:23:12 -04001269 }
1270 }
1271
1272 return count;
1273 }
1274 }
1275
Julia Reynolds7380d872018-01-12 10:28:26 -05001276 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001277 void clearNotifications() {
1278 mEnqueuedNotifications.clear();
1279 mNotificationList.clear();
1280 mNotificationsByKey.clear();
1281 mSummaryByGroupKey.clear();
1282 }
1283
Julia Reynolds080361e2017-07-13 11:23:12 -04001284 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001285 void addNotification(NotificationRecord r) {
1286 mNotificationList.add(r);
1287 mNotificationsByKey.put(r.sbn.getKey(), r);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001288 if (r.sbn.isGroup()) {
1289 mSummaryByGroupKey.put(r.getGroupKey(), r);
1290 }
1291 }
1292
1293 @VisibleForTesting
1294 void addEnqueuedNotification(NotificationRecord r) {
1295 mEnqueuedNotifications.add(r);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001296 }
1297
1298 @VisibleForTesting
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001299 NotificationRecord getNotificationRecord(String key) {
1300 return mNotificationsByKey.get(key);
1301 }
1302
1303
1304 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001305 void setSystemReady(boolean systemReady) {
1306 mSystemReady = systemReady;
1307 }
1308
1309 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001310 void setHandler(WorkerHandler handler) {
Chris Wren93bb8b82016-03-29 14:35:05 -04001311 mHandler = handler;
1312 }
1313
Chris Wrend4054312016-06-24 17:07:40 -04001314 @VisibleForTesting
Julia Reynolds0c299d42016-11-15 14:37:04 -05001315 void setFallbackVibrationPattern(long[] vibrationPattern) {
1316 mFallbackVibrationPattern = vibrationPattern;
Chris Wrend4054312016-06-24 17:07:40 -04001317 }
1318
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001319 @VisibleForTesting
1320 void setPackageManager(IPackageManager packageManager) {
1321 mPackageManager = packageManager;
1322 }
1323
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001324 @VisibleForTesting
1325 void setRankingHelper(RankingHelper rankingHelper) {
1326 mRankingHelper = rankingHelper;
1327 }
1328
1329 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001330 void setRankingHandler(RankingHandler rankingHandler) {
1331 mRankingHandler = rankingHandler;
1332 }
1333
1334 @VisibleForTesting
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001335 void setIsTelevision(boolean isTelevision) {
1336 mIsTelevision = isTelevision;
1337 }
1338
Julia Reynolds76c096d2017-06-19 08:16:04 -04001339 @VisibleForTesting
1340 void setUsageStats(NotificationUsageStats us) {
1341 mUsageStats = us;
1342 }
1343
Julia Reynolds94187562017-10-10 13:58:49 -04001344 @VisibleForTesting
1345 void setAccessibilityManager(AccessibilityManager am) {
1346 mAccessibilityManager = am;
1347 }
1348
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001349 // TODO: All tests should use this init instead of the one-off setters above.
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001350 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001351 void init(Looper looper, IPackageManager packageManager,
1352 PackageManager packageManagerClient,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001353 LightsManager lightsManager, NotificationListeners notificationListeners,
Julia Reynoldsb852e562017-06-06 16:14:18 -04001354 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001355 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
Julia Reynolds68263d12017-06-21 14:21:19 -04001356 NotificationUsageStats usageStats, AtomicFile policyFile,
Julia Reynolds7217dc92018-03-07 12:12:09 -05001357 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
1358 UsageStatsManagerInternal appUsageStats) {
Chris Wren54bbef42014-07-09 18:37:56 -04001359 Resources resources = getContext().getResources();
Chris Wren763a9bb2016-05-31 17:14:12 -04001360 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1361 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1362 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1363
Julia Reynolds94187562017-10-10 13:58:49 -04001364 mAccessibilityManager =
1365 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001366 mAm = am;
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001367 mPackageManager = packageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001368 mPackageManagerClient = packageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001369 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1370 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Julia Reynolds7217dc92018-03-07 12:12:09 -05001371 mAppUsageStats = appUsageStats;
Julia Reynolds2a128742016-11-28 14:29:25 -05001372 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001373 mCompanionManager = companionManager;
Julia Reynolds68263d12017-06-21 14:21:19 -04001374 mActivityManager = activityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -08001375 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1376 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001377 try {
1378 mPermissionOwner = mAm.newUriPermissionOwner("notification");
1379 } catch (RemoteException e) {
1380 Slog.w(TAG, "AM dead", e);
1381 }
San Mehat3ee13172010-02-04 20:54:43 -08001382
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001383 mHandler = new WorkerHandler(looper);
Chris Wrenf9536642014-04-17 10:01:54 -04001384 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -04001385 String[] extractorNames;
1386 try {
1387 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1388 } catch (Resources.NotFoundException e) {
1389 extractorNames = new String[0];
1390 }
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001391 mUsageStats = usageStats;
Kenny Guy23991102018-04-05 21:18:38 +01001392 mMetricsLogger = new MetricsLogger();
Chris Wren51017d02015-12-15 15:34:46 -05001393 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Julia Reynoldsb852e562017-06-06 16:14:18 -04001394 mConditionProviders = conditionProviders;
John Spurlockb2278d62015-04-07 12:47:12 -04001395 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -04001396 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -04001397 @Override
1398 public void onConfigChanged() {
1399 savePolicyFile();
1400 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001401
1402 @Override
1403 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001404 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -05001405 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -05001406 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1407 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -05001408 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001409 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02001410 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001411 }
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001412 mRankingHandler.requestSort();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001413 }
John Spurlock1fc476d2015-04-14 16:05:20 -04001414
1415 @Override
1416 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001417 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001418 mRankingHandler.requestSort();
John Spurlock80774932015-05-07 17:38:50 -04001419 }
John Spurlock056c5192014-04-20 21:52:01 -04001420 });
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001421 mRankingHelper = new RankingHelper(getContext(),
1422 mPackageManagerClient,
1423 mRankingHandler,
1424 mZenModeHelper,
1425 mUsageStats,
1426 extractorNames);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001427 mSnoozeHelper = snoozeHelper;
Julia Reynolds8aebf352017-06-26 11:35:33 -04001428 mGroupHelper = groupHelper;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04001429
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001430 // This is a ManagedServices object that keeps track of the listeners.
1431 mListeners = notificationListeners;
Chris Wren0efdb882016-03-01 17:17:47 -05001432
Julia Reynolds77b2cc92016-11-08 14:41:09 -05001433 // This is a MangedServices object that keeps track of the assistant.
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001434 mAssistants = notificationAssistants;
Julia Reynoldsb852e562017-06-06 16:14:18 -04001435
1436 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(),
1515 LocalServices.getService(UsageStatsManagerInternal.class));
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001516
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001517 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001519 filter.addAction(Intent.ACTION_SCREEN_ON);
1520 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001521 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001522 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001523 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001524 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001525 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001526 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001527 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001528 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001529 getContext().registerReceiver(mIntentReceiver, filter);
Kenny Guy70058402014-10-28 20:45:06 +00001530
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001531 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001532 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001533 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001534 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001535 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1536 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1537 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001538 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1539 null);
1540
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001541 IntentFilter suspendedPkgFilter = new IntentFilter();
1542 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
Beverly5a20a5e2018-03-06 15:02:44 -05001543 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001544 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1545 suspendedPkgFilter, null, null);
1546
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001547 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001548 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1549 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001550
Julia Reynolds2a128742016-11-28 14:29:25 -05001551 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1552 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1553 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1554
Julia Reynoldsb852e562017-06-06 16:14:18 -04001555 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1556 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1557
Beverlyd4f96492017-08-02 13:36:11 -04001558 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1559 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1560
Vishnu Naire3e4d252018-03-01 11:26:57 -08001561 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
1562 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001563 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 }
1565
Julia Reynolds8aebf352017-06-26 11:35:33 -04001566 private GroupHelper getGroupHelper() {
1567 return new GroupHelper(new GroupHelper.Callback() {
1568 @Override
1569 public void addAutoGroup(String key) {
1570 synchronized (mNotificationLock) {
1571 addAutogroupKeyLocked(key);
1572 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001573 }
1574
1575 @Override
1576 public void removeAutoGroup(String key) {
1577 synchronized (mNotificationLock) {
1578 removeAutogroupKeyLocked(key);
1579 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001580 }
1581
1582 @Override
1583 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1584 createAutoGroupSummary(userId, pkg, triggeringKey);
1585 }
1586
1587 @Override
1588 public void removeAutoGroupSummary(int userId, String pkg) {
1589 synchronized (mNotificationLock) {
1590 clearAutogroupSummaryLocked(userId, pkg);
1591 }
1592 }
1593 });
1594 }
1595
John Spurlocke7a835b2015-05-13 10:47:05 -04001596 private void sendRegisteredOnlyBroadcast(String action) {
1597 getContext().sendBroadcastAsUser(new Intent(action)
1598 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1599 }
1600
Adam Lesinski182f73f2013-12-05 16:48:06 -08001601 @Override
1602 public void onBootPhase(int phase) {
1603 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1604 // no beeping until we're basically done booting
1605 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001606
Adam Lesinski182f73f2013-12-05 16:48:06 -08001607 // Grab our optional AudioService
1608 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001609 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001610 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001611 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001612 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1613 // This observer will force an update when observe is called, causing us to
1614 // bind to listener services.
1615 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001616 mListeners.onBootPhaseAppsCanStart();
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001617 mAssistants.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001618 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 }
1620 }
1621
Julia Reynolds88860ce2017-06-01 16:55:49 -04001622 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04001623 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001624 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001625 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001626 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001627 mListenerHints = hints;
1628 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001629 }
1630
Julia Reynolds88860ce2017-06-01 16:55:49 -04001631 @GuardedBy("mNotificationLock")
John Spurlockb4782522014-08-22 14:54:46 -04001632 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001633 final long updatedSuppressedEffects = calculateSuppressedEffects();
1634 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1635 final List<ComponentName> suppressors = getSuppressors();
1636 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1637 mEffectsSuppressors = suppressors;
1638 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001639 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001640 }
1641
Amith Yamasani396a10c2018-01-19 10:58:07 -08001642 private void exitIdle() {
1643 try {
1644 if (mDeviceIdleController != null) {
1645 mDeviceIdleController.exitIdle("notification interaction");
1646 }
1647 } catch (RemoteException e) {
1648 }
1649 }
1650
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001651 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1652 boolean fromListener) {
Julia Reynolds924eed12017-01-19 09:52:07 -05001653 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1654 // cancel
1655 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001656 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
Julia Reynolds924eed12017-01-19 09:52:07 -05001657 null);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001658 if (isUidSystemOrPhone(uid)) {
1659 int[] profileIds = mUserProfiles.getCurrentProfileIds();
1660 int N = profileIds.length;
1661 for (int i = 0; i < N; i++) {
1662 int profileId = profileIds[i];
1663 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1664 profileId, REASON_CHANNEL_BANNED,
1665 null);
1666 }
1667 }
Julia Reynolds924eed12017-01-19 09:52:07 -05001668 }
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001669 final NotificationChannel preUpdate =
1670 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
1671
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001672 mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001673 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
Julia Reynolds924eed12017-01-19 09:52:07 -05001674
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001675 if (!fromListener) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001676 final NotificationChannel modifiedChannel =
1677 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001678 mListeners.notifyNotificationChannelChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001679 pkg, UserHandle.getUserHandleForUid(uid),
1680 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001681 }
1682
Julia Reynolds924eed12017-01-19 09:52:07 -05001683 savePolicyFile();
1684 }
1685
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001686 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1687 NotificationChannel update) {
1688 try {
1689 if ((preUpdate.getImportance() == IMPORTANCE_NONE
1690 && update.getImportance() != IMPORTANCE_NONE)
1691 || (preUpdate.getImportance() != IMPORTANCE_NONE
1692 && update.getImportance() == IMPORTANCE_NONE)) {
1693 getContext().sendBroadcastAsUser(
1694 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001695 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001696 update.getId())
1697 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1698 update.getImportance() == IMPORTANCE_NONE)
1699 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1700 .setPackage(pkg),
1701 UserHandle.of(UserHandle.getUserId(uid)), null);
1702 }
1703 } catch (SecurityException e) {
1704 Slog.w(TAG, "Can't notify app about channel change", e);
1705 }
1706 }
1707
Julia Reynolds005c8b92017-08-24 10:35:53 -04001708 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
1709 boolean fromApp, boolean fromListener) {
1710 Preconditions.checkNotNull(group);
1711 Preconditions.checkNotNull(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001712
1713 final NotificationChannelGroup preUpdate =
1714 mRankingHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
Julia Reynolds005c8b92017-08-24 10:35:53 -04001715 mRankingHelper.createNotificationChannelGroup(pkg, uid, group,
1716 fromApp);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001717 if (!fromApp) {
1718 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
1719 }
Julia Reynolds005c8b92017-08-24 10:35:53 -04001720 if (!fromListener) {
1721 mListeners.notifyNotificationChannelGroupChanged(pkg,
1722 UserHandle.of(UserHandle.getCallingUserId()), group,
1723 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1724 }
1725 }
1726
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001727 private void maybeNotifyChannelGroupOwner(String pkg, int uid,
1728 NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
1729 try {
1730 if (preUpdate.isBlocked() != update.isBlocked()) {
1731 getContext().sendBroadcastAsUser(
1732 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001733 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001734 update.getId())
1735 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1736 update.isBlocked())
1737 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1738 .setPackage(pkg),
1739 UserHandle.of(UserHandle.getUserId(uid)), null);
1740 }
1741 } catch (SecurityException e) {
1742 Slog.w(TAG, "Can't notify app about group change", e);
1743 }
1744 }
1745
Bryce Lee7219ada2016-04-08 10:54:23 -07001746 private ArrayList<ComponentName> getSuppressors() {
1747 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1748 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1749 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1750
1751 for (ManagedServiceInfo info : serviceInfoList) {
1752 names.add(info.component);
1753 }
1754 }
1755
1756 return names;
1757 }
1758
1759 private boolean removeDisabledHints(ManagedServiceInfo info) {
1760 return removeDisabledHints(info, 0);
1761 }
1762
1763 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1764 boolean removed = false;
1765
1766 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1767 final int hint = mListenersDisablingEffects.keyAt(i);
1768 final ArraySet<ManagedServiceInfo> listeners =
1769 mListenersDisablingEffects.valueAt(i);
1770
1771 if (hints == 0 || (hint & hints) == hint) {
1772 removed = removed || listeners.remove(info);
1773 }
1774 }
1775
1776 return removed;
1777 }
1778
1779 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1780 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1781 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1782 }
1783
1784 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1785 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1786 }
1787
1788 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1789 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1790 }
1791 }
1792
1793 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1794 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1795 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1796 }
1797
1798 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1799 hintListeners.add(info);
1800 }
1801
1802 private int calculateHints() {
1803 int hints = 0;
1804 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1805 int hint = mListenersDisablingEffects.keyAt(i);
1806 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1807
1808 if (!serviceInfoList.isEmpty()) {
1809 hints |= hint;
1810 }
1811 }
1812
1813 return hints;
1814 }
1815
1816 private long calculateSuppressedEffects() {
1817 int hints = calculateHints();
1818 long suppressedEffects = 0;
1819
1820 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1821 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1822 }
1823
1824 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1825 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1826 }
1827
1828 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1829 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1830 }
1831
1832 return suppressedEffects;
1833 }
1834
Julia Reynolds88860ce2017-06-01 16:55:49 -04001835 @GuardedBy("mNotificationLock")
Christoph Studer85a384b2014-08-27 20:16:15 +02001836 private void updateInterruptionFilterLocked() {
1837 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1838 if (interruptionFilter == mInterruptionFilter) return;
1839 mInterruptionFilter = interruptionFilter;
1840 scheduleInterruptionFilterChanged(interruptionFilter);
1841 }
1842
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001843 @VisibleForTesting
1844 INotificationManager getBinderService() {
1845 return INotificationManager.Stub.asInterface(mService);
1846 }
1847
Amith Yamasani7ec89412018-02-07 08:48:49 -08001848 /**
1849 * Report to usage stats that the notification was seen.
1850 * @param r notification record
1851 */
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001852 @GuardedBy("mNotificationLock")
Amith Yamasani803eab692017-11-09 17:47:04 -08001853 protected void reportSeen(NotificationRecord r) {
Amith Yamasani803eab692017-11-09 17:47:04 -08001854 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001855 getRealUserId(r.sbn.getUserId()),
Amith Yamasani803eab692017-11-09 17:47:04 -08001856 UsageEvents.Event.NOTIFICATION_SEEN);
1857 }
1858
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001859 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
1860 int targetSdkVersion) {
1861 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
1862 return incomingPolicy.suppressedVisualEffects;
1863 }
1864 final int[] effectsIntroducedInP = {
1865 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
1866 SUPPRESSED_EFFECT_LIGHTS,
1867 SUPPRESSED_EFFECT_PEEK,
1868 SUPPRESSED_EFFECT_STATUS_BAR,
1869 SUPPRESSED_EFFECT_BADGE,
1870 SUPPRESSED_EFFECT_AMBIENT,
1871 SUPPRESSED_EFFECT_NOTIFICATION_LIST
1872 };
1873
1874 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06001875 if (targetSdkVersion < Build.VERSION_CODES.P) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001876 // unset higher order bits introduced in P, maintain the user's higher order bits
1877 for (int i = 0; i < effectsIntroducedInP.length ; i++) {
1878 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
1879 newSuppressedVisualEffects |=
1880 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
1881 }
1882 // set higher order bits according to lower order bits
1883 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1884 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1885 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001886 }
1887 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1888 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1889 }
1890 } else {
1891 boolean hasNewEffects = (newSuppressedVisualEffects
1892 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
1893 // if any of the new effects introduced in P are set
1894 if (hasNewEffects) {
1895 // clear out the deprecated effects
1896 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
1897 | SUPPRESSED_EFFECT_SCREEN_OFF);
1898
1899 // set the deprecated effects according to the new more specific effects
1900 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
1901 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
1902 }
1903 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
1904 && (newSuppressedVisualEffects
1905 & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
1906 && (newSuppressedVisualEffects
1907 & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
1908 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
1909 }
1910 } else {
1911 // set higher order bits according to lower order bits
1912 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1913 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1914 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
1915 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
1916 }
1917 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1918 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1919 }
1920 }
1921 }
1922
1923 return newSuppressedVisualEffects;
1924 }
1925
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001926 @GuardedBy("mNotificationLock")
1927 protected void maybeRecordInterruptionLocked(NotificationRecord r) {
1928 if (r.isInterruptive()) {
1929 mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
1930 r.getChannel().getId(),
1931 getRealUserId(r.sbn.getUserId()));
Julia Reynoldsad7d7132018-03-21 16:05:00 -04001932 logRecentLocked(r);
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001933 }
1934 }
1935
Amith Yamasani7ec89412018-02-07 08:48:49 -08001936 /**
1937 * Report to usage stats that the notification was clicked.
1938 * @param r notification record
1939 */
1940 protected void reportUserInteraction(NotificationRecord r) {
Amith Yamasani7ec89412018-02-07 08:48:49 -08001941 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001942 getRealUserId(r.sbn.getUserId()),
Amith Yamasani7ec89412018-02-07 08:48:49 -08001943 UsageEvents.Event.USER_INTERACTION);
1944 }
1945
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001946 private int getRealUserId(int userId) {
1947 return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
1948 }
1949
Geoffrey Pitsch415e4542017-04-10 13:12:58 -04001950 @VisibleForTesting
1951 NotificationManagerInternal getInternalService() {
1952 return mInternalService;
1953 }
1954
Adam Lesinski182f73f2013-12-05 16:48:06 -08001955 private final IBinder mService = new INotificationManager.Stub() {
1956 // Toasts
1957 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001958
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001960 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001961 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001962 if (DBG) {
1963 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1964 + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001966
1967 if (pkg == null || callback == null) {
1968 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1969 return ;
1970 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001971 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001972 final boolean isPackageSuspended =
1973 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
Adam Lesinski182f73f2013-12-05 16:48:06 -08001974
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001975 if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001976 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1977 || isPackageSuspended)) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001978 Slog.e(TAG, "Suppressing toast from package " + pkg
1979 + (isPackageSuspended
1980 ? " due to package suspended by administrator."
1981 : " by user request."));
1982 return;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001983 }
1984
1985 synchronized (mToastQueue) {
1986 int callingPid = Binder.getCallingPid();
1987 long callingId = Binder.clearCallingIdentity();
1988 try {
1989 ToastRecord record;
Beverly4ee785b2017-08-11 12:49:56 -04001990 int index;
1991 // All packages aside from the android package can enqueue one toast at a time
1992 if (!isSystemToast) {
1993 index = indexOfToastPackageLocked(pkg);
1994 } else {
1995 index = indexOfToastLocked(pkg, callback);
1996 }
1997
1998 // If the package already has a toast, we update its toast
1999 // in the queue, we don't move it to the end of the queue.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002000 if (index >= 0) {
2001 record = mToastQueue.get(index);
2002 record.update(duration);
Beverly99298432018-02-15 17:07:04 -05002003 try {
2004 record.callback.hide();
2005 } catch (RemoteException e) {
2006 }
Beverly4ee785b2017-08-11 12:49:56 -04002007 record.update(callback);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002008 } else {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002009 Binder token = new Binder();
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002010 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002011 record = new ToastRecord(callingPid, pkg, callback, duration, token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002012 mToastQueue.add(record);
2013 index = mToastQueue.size() - 1;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002014 }
Beverly4ee785b2017-08-11 12:49:56 -04002015 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002016 // If it's at index 0, it's the current toast. It doesn't matter if it's
2017 // new or just been updated. Call back and tell it to show itself.
2018 // If the callback fails, this will remove it from the list, so don't
2019 // assume that it's valid after this.
2020 if (index == 0) {
2021 showNextToastLocked();
2022 }
2023 } finally {
2024 Binder.restoreCallingIdentity(callingId);
2025 }
2026 }
2027 }
2028
2029 @Override
2030 public void cancelToast(String pkg, ITransientNotification callback) {
2031 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
2032
2033 if (pkg == null || callback == null) {
2034 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
2035 return ;
2036 }
2037
2038 synchronized (mToastQueue) {
2039 long callingId = Binder.clearCallingIdentity();
2040 try {
2041 int index = indexOfToastLocked(pkg, callback);
2042 if (index >= 0) {
2043 cancelToastLocked(index);
2044 } else {
2045 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
2046 + " callback=" + callback);
2047 }
2048 } finally {
2049 Binder.restoreCallingIdentity(callingId);
2050 }
2051 }
2052 }
2053
2054 @Override
Robert Carr997427342018-02-28 18:06:10 -08002055 public void finishToken(String pkg, ITransientNotification callback) {
2056 synchronized (mToastQueue) {
2057 long callingId = Binder.clearCallingIdentity();
2058 try {
2059 int index = indexOfToastLocked(pkg, callback);
2060 if (index >= 0) {
2061 ToastRecord record = mToastQueue.get(index);
2062 finishTokenLocked(record.token);
2063 } else {
2064 Slog.w(TAG, "Toast already killed. pkg=" + pkg
2065 + " callback=" + callback);
2066 }
2067 } finally {
2068 Binder.restoreCallingIdentity(callingId);
2069 }
2070 }
2071 }
2072
2073 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002074 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002075 Notification notification, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002076 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002077 Binder.getCallingPid(), tag, id, notification, userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002078 }
2079
2080 @Override
2081 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002082 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002083 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2084 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002085 // Don't allow client applications to cancel foreground service notis or autobundled
2086 // summaries.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002087 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
2088 (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
John Spurlocke6a7d932014-03-13 12:29:00 -04002089 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002090 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002091 }
2092
2093 @Override
2094 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002095 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002096
2097 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2098 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
2099
2100 // Calling from user space, don't allow the canceling of actively
2101 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04002102 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002103 pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05002104 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002105 }
2106
2107 @Override
2108 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
Rohan Shahca0447e2018-03-30 15:18:27 -07002109 enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002110
Chris Wrenacf424a2016-03-15 12:48:55 -04002111 mRankingHelper.setEnabled(pkg, uid, enabled);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002112 // Now, cancel any outstanding notifications that are part of a just-disabled app
Julia Reynolds4da79702017-06-01 11:06:10 -04002113 if (!enabled) {
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002114 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
2115 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
2116 }
Julia Reynoldsfc9767b2018-01-22 17:45:16 -05002117
2118 try {
2119 getContext().sendBroadcastAsUser(
2120 new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
2121 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
2122 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2123 .setPackage(pkg),
2124 UserHandle.of(UserHandle.getUserId(uid)), null);
2125 } catch (SecurityException e) {
2126 Slog.w(TAG, "Can't notify app about app block change", e);
2127 }
2128
Chris Wrenacf424a2016-03-15 12:48:55 -04002129 savePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002130 }
2131
2132 /**
Rohan Shah590e1b22018-04-10 23:48:47 -04002133 * Updates the enabled state for notifications for the given package (and uid).
2134 * Additionally, this method marks the app importance as locked by the user, which means
2135 * that notifications from the app will <b>not</b> be considered for showing a
2136 * blocking helper.
2137 *
2138 * @param pkg package that owns the notifications to update
2139 * @param uid uid of the app providing notifications
2140 * @param enabled whether notifications should be enabled for the app
2141 *
2142 * @see #setNotificationsEnabledForPackage(String, int, boolean)
2143 */
2144 @Override
2145 public void setNotificationsEnabledWithImportanceLockForPackage(
2146 String pkg, int uid, boolean enabled) {
2147 setNotificationsEnabledForPackage(pkg, uid, enabled);
2148
2149 mRankingHelper.setAppImportanceLocked(pkg, uid);
2150 }
2151
2152 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002153 * Use this when you just want to know if notifications are OK for this package.
2154 */
2155 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002156 public boolean areNotificationsEnabled(String pkg) {
2157 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
2158 }
2159
2160 /**
2161 * Use this when you just want to know if notifications are OK for this package.
2162 */
2163 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002164 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002165 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002166
2167 return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002168 }
2169
Chris Wren54bbef42014-07-09 18:37:56 -04002170 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05002171 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002172 checkCallerIsSystemOrSameApp(pkg);
Julia Reynoldsef37f282016-02-12 09:11:27 -05002173 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002174 }
2175
2176 @Override
Julia Reynolds924eed12017-01-19 09:52:07 -05002177 public boolean canShowBadge(String pkg, int uid) {
2178 checkCallerIsSystem();
2179 return mRankingHelper.canShowBadge(pkg, uid);
2180 }
2181
2182 @Override
2183 public void setShowBadge(String pkg, int uid, boolean showBadge) {
2184 checkCallerIsSystem();
2185 mRankingHelper.setShowBadge(pkg, uid, showBadge);
2186 savePolicyFile();
2187 }
2188
2189 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002190 public void updateNotificationChannelGroupForPackage(String pkg, int uid,
2191 NotificationChannelGroup group) throws RemoteException {
2192 enforceSystemOrSystemUI("Caller not system or systemui");
2193 createNotificationChannelGroup(pkg, uid, group, false, false);
2194 savePolicyFile();
2195 }
2196
2197 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002198 public void createNotificationChannelGroups(String pkg,
2199 ParceledListSlice channelGroupList) throws RemoteException {
2200 checkCallerIsSystemOrSameApp(pkg);
2201 List<NotificationChannelGroup> groups = channelGroupList.getList();
2202 final int groupSize = groups.size();
2203 for (int i = 0; i < groupSize; i++) {
2204 final NotificationChannelGroup group = groups.get(i);
Julia Reynolds005c8b92017-08-24 10:35:53 -04002205 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002206 }
2207 savePolicyFile();
2208 }
2209
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002210 private void createNotificationChannelsImpl(String pkg, int uid,
2211 ParceledListSlice channelsList) {
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002212 List<NotificationChannel> channels = channelsList.getList();
2213 final int channelsSize = channels.size();
2214 for (int i = 0; i < channelsSize; i++) {
2215 final NotificationChannel channel = channels.get(i);
2216 Preconditions.checkNotNull(channel, "channel in list is null");
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002217 mRankingHelper.createNotificationChannel(pkg, uid, channel,
Julia Reynolds1fe10942018-03-28 12:46:51 -04002218 true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed(
2219 pkg, UserHandle.getUserId(uid)));
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002220 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002221 UserHandle.getUserHandleForUid(uid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002222 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
2223 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002224 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002225 savePolicyFile();
2226 }
2227
2228 @Override
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002229 public void createNotificationChannels(String pkg,
2230 ParceledListSlice channelsList) throws RemoteException {
2231 checkCallerIsSystemOrSameApp(pkg);
2232 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
2233 }
2234
2235 @Override
2236 public void createNotificationChannelsForPackage(String pkg, int uid,
2237 ParceledListSlice channelsList) throws RemoteException {
2238 checkCallerIsSystem();
2239 createNotificationChannelsImpl(pkg, uid, channelsList);
2240 }
2241
2242 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002243 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002244 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002245 return mRankingHelper.getNotificationChannel(
2246 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002247 }
2248
2249 @Override
2250 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002251 String channelId, boolean includeDeleted) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002252 checkCallerIsSystem();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002253 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002254 }
2255
2256 @Override
2257 public void deleteNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002258 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002259 final int callingUid = Binder.getCallingUid();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002260 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
2261 throw new IllegalArgumentException("Cannot delete default channel");
2262 }
2263 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002264 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
2265 mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
2266 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002267 UserHandle.getUserHandleForUid(callingUid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002268 mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
2269 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002270 savePolicyFile();
2271 }
2272
2273 @Override
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002274 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
2275 checkCallerIsSystemOrSameApp(pkg);
2276 return mRankingHelper.getNotificationChannelGroupWithChannels(
2277 pkg, Binder.getCallingUid(), groupId, false);
2278 }
2279
2280 @Override
Julia Reynolds9bfba592017-03-15 14:03:55 -04002281 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
2282 String pkg) {
2283 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002284 return mRankingHelper.getNotificationChannelGroups(
2285 pkg, Binder.getCallingUid(), false, false);
Julia Reynolds9bfba592017-03-15 14:03:55 -04002286 }
2287
2288 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002289 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04002290 checkCallerIsSystemOrSameApp(pkg);
2291
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002292 final int callingUid = Binder.getCallingUid();
2293 NotificationChannelGroup groupToDelete =
2294 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
2295 if (groupToDelete != null) {
2296 List<NotificationChannel> deletedChannels =
2297 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
2298 for (int i = 0; i < deletedChannels.size(); i++) {
2299 final NotificationChannel deletedChannel = deletedChannels.get(i);
2300 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2301 true,
2302 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2303 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002304 mListeners.notifyNotificationChannelChanged(pkg,
2305 UserHandle.getUserHandleForUid(callingUid),
2306 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002307 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2308 }
2309 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002310 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2311 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002312 savePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002313 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04002314 }
2315
2316 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002317 public void updateNotificationChannelForPackage(String pkg, int uid,
2318 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002319 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05002320 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002321 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002322 }
2323
2324 @Override
2325 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002326 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002327 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002328 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002329 }
2330
2331 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002332 public int getNumNotificationChannelsForPackage(String pkg, int uid,
2333 boolean includeDeleted) {
2334 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
2335 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
2336 .getList().size();
2337 }
2338
2339 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04002340 public boolean onlyHasDefaultChannel(String pkg, int uid) {
2341 enforceSystemOrSystemUI("onlyHasDefaultChannel");
2342 return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
2343 }
2344
2345 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04002346 public int getDeletedChannelCount(String pkg, int uid) {
2347 enforceSystemOrSystemUI("getDeletedChannelCount");
2348 return mRankingHelper.getDeletedChannelCount(pkg, uid);
2349 }
2350
2351 @Override
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002352 public int getBlockedChannelCount(String pkg, int uid) {
2353 enforceSystemOrSystemUI("getBlockedChannelCount");
2354 return mRankingHelper.getBlockedChannelCount(pkg, uid);
2355 }
2356
2357 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002358 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2359 String pkg, int uid, boolean includeDeleted) {
2360 checkCallerIsSystem();
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002361 return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted, true);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002362 }
2363
2364 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002365 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2366 String pkg, int uid, String groupId, boolean includeDeleted) {
2367 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
2368 return mRankingHelper.getNotificationChannelGroupWithChannels(
2369 pkg, uid, groupId, includeDeleted);
2370 }
2371
2372 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002373 public NotificationChannelGroup getNotificationChannelGroupForPackage(
2374 String groupId, String pkg, int uid) {
2375 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
2376 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
2377 }
2378
2379 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002380 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
2381 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002382 return mRankingHelper.getNotificationChannels(
2383 pkg, Binder.getCallingUid(), false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002384 }
2385
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002386 @Override
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05002387 public ParceledListSlice<NotifyingApp> getRecentNotifyingAppsForUser(int userId) {
2388 checkCallerIsSystem();
2389 synchronized (mNotificationLock) {
2390 List<NotifyingApp> apps = new ArrayList<>(
2391 mRecentApps.getOrDefault(userId, new ArrayList<>()));
2392 return new ParceledListSlice<>(apps);
2393 }
2394 }
2395
2396 @Override
Julia Reynoldse273f082018-04-12 13:48:49 -04002397 public int getBlockedAppCount(int userId) {
2398 checkCallerIsSystem();
2399 return mRankingHelper.getBlockedAppCount(userId);
2400 }
2401
2402 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05002403 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002404 checkCallerIsSystem();
2405
2406 // Cancel posted notifications
2407 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2408 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2409
Julia Reynoldsb852e562017-06-06 16:14:18 -04002410 final String[] packages = new String[] {packageName};
2411 final int[] uids = new int[] {uid};
2412
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002413 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04002414 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002415 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002416
2417 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04002418 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002419
2420 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05002421 if (!fromApp) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002422 mRankingHelper.onPackagesChanged(
2423 true, UserHandle.getCallingUserId(), packages, uids);
Julia Reynolds5355e852017-02-07 14:54:13 -05002424 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002425
2426 savePolicyFile();
2427 }
2428
2429
Adam Lesinski182f73f2013-12-05 16:48:06 -08002430 /**
2431 * System-only API for getting a list of current (i.e. not cleared) notifications.
2432 *
2433 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04002434 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002435 */
2436 @Override
2437 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2438 // enforce() will ensure the calling uid has the correct permission
2439 getContext().enforceCallingOrSelfPermission(
2440 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2441 "NotificationManagerService.getActiveNotifications");
2442
2443 StatusBarNotification[] tmp = null;
2444 int uid = Binder.getCallingUid();
2445
2446 // noteOp will check to make sure the callingPkg matches the uid
2447 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2448 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002449 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002450 tmp = new StatusBarNotification[mNotificationList.size()];
2451 final int N = mNotificationList.size();
2452 for (int i=0; i<N; i++) {
2453 tmp[i] = mNotificationList.get(i).sbn;
2454 }
2455 }
2456 }
2457 return tmp;
2458 }
2459
2460 /**
Dan Sandler994349c2015-04-15 11:02:54 -04002461 * Public API for getting a list of current notifications for the calling package/uid.
2462 *
Julia Reynolds573c6532017-01-24 17:44:38 -05002463 * Note that since notification posting is done asynchronously, this will not return
2464 * notifications that are in the process of being posted.
2465 *
Dan Sandler994349c2015-04-15 11:02:54 -04002466 * @returns A list of all the package's notifications, in natural order.
2467 */
2468 @Override
2469 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2470 int incomingUserId) {
2471 checkCallerIsSystemOrSameApp(pkg);
2472 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2473 Binder.getCallingUid(), incomingUserId, true, false,
2474 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002475 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002476 final ArrayMap<String, StatusBarNotification> map
2477 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002478 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002479 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002480 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2481 mNotificationList.get(i).sbn);
2482 if (sbn != null) {
2483 map.put(sbn.getKey(), sbn);
2484 }
2485 }
2486 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2487 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2488 if (sbn != null) {
2489 map.put(sbn.getKey(), sbn);
2490 }
2491 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002492 final int M = mEnqueuedNotifications.size();
2493 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002494 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2495 mEnqueuedNotifications.get(i).sbn);
2496 if (sbn != null) {
2497 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04002498 }
2499 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002500 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2501 list.addAll(map.values());
2502 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04002503 }
Dan Sandler994349c2015-04-15 11:02:54 -04002504 }
2505
Chris Wren6676dab2016-12-21 18:26:27 -05002506 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2507 StatusBarNotification sbn) {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04002508 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
Chris Wren6676dab2016-12-21 18:26:27 -05002509 // We could pass back a cloneLight() but clients might get confused and
2510 // try to send this thing back to notify() again, which would not work
2511 // very well.
2512 return new StatusBarNotification(
2513 sbn.getPackageName(),
2514 sbn.getOpPkg(),
Chris Wren6676dab2016-12-21 18:26:27 -05002515 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2516 sbn.getNotification().clone(),
2517 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2518 }
2519 return null;
2520 }
2521
Dan Sandler994349c2015-04-15 11:02:54 -04002522 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002523 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2524 *
2525 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2526 */
2527 @Override
2528 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2529 // enforce() will ensure the calling uid has the correct permission
2530 getContext().enforceCallingOrSelfPermission(
2531 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2532 "NotificationManagerService.getHistoricalNotifications");
2533
2534 StatusBarNotification[] tmp = null;
2535 int uid = Binder.getCallingUid();
2536
2537 // noteOp will check to make sure the callingPkg matches the uid
2538 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2539 == AppOpsManager.MODE_ALLOWED) {
2540 synchronized (mArchive) {
2541 tmp = mArchive.getArray(count);
2542 }
2543 }
2544 return tmp;
2545 }
2546
2547 /**
2548 * Register a listener binder directly with the notification manager.
2549 *
2550 * Only works with system callers. Apps should extend
2551 * {@link android.service.notification.NotificationListenerService}.
2552 */
2553 @Override
2554 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05002555 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02002556 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05002557 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002558 }
2559
2560 /**
2561 * Remove a listener binder directly
2562 */
2563 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002564 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05002565 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002566 }
2567
2568 /**
2569 * Allow an INotificationListener to simulate a "clear all" operation.
2570 *
2571 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2572 *
2573 * @param token The binder for the listener, to check that the caller is allowed
2574 */
2575 @Override
John Spurlocka4294292014-03-24 18:02:32 -04002576 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002577 final int callingUid = Binder.getCallingUid();
2578 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002579 long identity = Binder.clearCallingIdentity();
2580 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002581 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002582 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Beverly5a20a5e2018-03-06 15:02:44 -05002583
John Spurlocka4294292014-03-24 18:02:32 -04002584 if (keys != null) {
2585 final int N = keys.length;
2586 for (int i = 0; i < N; i++) {
2587 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07002588 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00002589 final int userId = r.sbn.getUserId();
2590 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04002591 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00002592 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04002593 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00002594 }
Griff Hazen335e1f02014-09-11 14:49:31 -07002595 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2596 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2597 userId);
John Spurlocka4294292014-03-24 18:02:32 -04002598 }
2599 } else {
2600 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00002601 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04002602 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002603 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002604 } finally {
2605 Binder.restoreCallingIdentity(identity);
2606 }
2607 }
2608
Chris Wrenab41eec2016-01-04 18:01:27 -05002609 /**
2610 * Handle request from an approved listener to re-enable itself.
2611 *
2612 * @param component The componenet to be re-enabled, caller must match package.
2613 */
2614 @Override
2615 public void requestBindListener(ComponentName component) {
2616 checkCallerIsSystemOrSameApp(component.getPackageName());
2617 long identity = Binder.clearCallingIdentity();
2618 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002619 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002620 mAssistants.isComponentEnabledForCurrentProfiles(component)
2621 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05002622 : mListeners;
2623 manager.setComponentState(component, true);
2624 } finally {
2625 Binder.restoreCallingIdentity(identity);
2626 }
2627 }
2628
2629 @Override
2630 public void requestUnbindListener(INotificationListener token) {
2631 long identity = Binder.clearCallingIdentity();
2632 try {
2633 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002634 synchronized (mNotificationLock) {
2635 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2636 info.getOwner().setComponentState(info.component, false);
2637 }
Chris Wrenab41eec2016-01-04 18:01:27 -05002638 } finally {
2639 Binder.restoreCallingIdentity(identity);
2640 }
2641 }
2642
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002643 @Override
2644 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002645 long identity = Binder.clearCallingIdentity();
2646 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002647 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002648 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2649 if (keys != null) {
2650 final int N = keys.length;
2651 for (int i = 0; i < N; i++) {
2652 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2653 if (r == null) continue;
2654 final int userId = r.sbn.getUserId();
2655 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2656 !mUserProfiles.isCurrentProfile(userId)) {
2657 throw new SecurityException("Disallowed call from listener: "
2658 + info.service);
2659 }
2660 if (!r.isSeen()) {
2661 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
Amith Yamasani803eab692017-11-09 17:47:04 -08002662 reportSeen(r);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002663 r.setSeen();
2664 }
2665 }
2666 }
2667 }
2668 } finally {
2669 Binder.restoreCallingIdentity(identity);
2670 }
2671 }
2672
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002673 /**
2674 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2675 *
2676 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2677 *
Julia Reynolds79672302017-01-12 08:30:16 -05002678 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002679 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04002680 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04002681 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00002682 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04002683 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2684 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2685 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00002686 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04002687 }
2688
Adam Lesinski182f73f2013-12-05 16:48:06 -08002689 /**
Julia Reynolds79672302017-01-12 08:30:16 -05002690 * Allow an INotificationListener to snooze a single notification until a context.
2691 *
2692 * @param token The binder for the listener, to check that the caller is allowed
2693 */
2694 @Override
2695 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2696 String key, String snoozeCriterionId) {
2697 long identity = Binder.clearCallingIdentity();
2698 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002699 synchronized (mNotificationLock) {
2700 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2701 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2702 }
Julia Reynolds79672302017-01-12 08:30:16 -05002703 } finally {
2704 Binder.restoreCallingIdentity(identity);
2705 }
2706 }
2707
2708 /**
2709 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002710 *
2711 * @param token The binder for the listener, to check that the caller is allowed
2712 */
2713 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002714 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05002715 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002716 long identity = Binder.clearCallingIdentity();
2717 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002718 synchronized (mNotificationLock) {
2719 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2720 snoozeNotificationInt(key, duration, null, info);
2721 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002722 } finally {
2723 Binder.restoreCallingIdentity(identity);
2724 }
2725 }
2726
2727 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002728 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002729 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002730 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002731 */
2732 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002733 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002734 long identity = Binder.clearCallingIdentity();
2735 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002736 synchronized (mNotificationLock) {
2737 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002738 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002739 unsnoozeNotificationInt(key, info);
2740 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002741 } finally {
2742 Binder.restoreCallingIdentity(identity);
2743 }
2744 }
2745
2746 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002747 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2748 *
2749 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2750 *
2751 * @param token The binder for the listener, to check that the caller is allowed
2752 */
2753 @Override
2754 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2755 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002756 final int callingUid = Binder.getCallingUid();
2757 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002758 long identity = Binder.clearCallingIdentity();
2759 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002760 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002761 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00002762 if (info.supportsProfiles()) {
2763 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2764 + "from " + info.component
2765 + " use cancelNotification(key) instead.");
2766 } else {
2767 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2768 pkg, tag, id, info.userid);
2769 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002770 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002771 } finally {
2772 Binder.restoreCallingIdentity(identity);
2773 }
2774 }
2775
2776 /**
2777 * Allow an INotificationListener to request the list of outstanding notifications seen by
2778 * the current user. Useful when starting up, after which point the listener callbacks
2779 * should be used.
2780 *
2781 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002782 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04002783 * @returns The return value will contain the notifications specified in keys, in that
2784 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002785 */
2786 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02002787 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02002788 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002789 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002790 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002791 final boolean getKeys = keys != null;
2792 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02002793 final ArrayList<StatusBarNotification> list
2794 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02002795 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002796 final NotificationRecord r = getKeys
2797 ? mNotificationsByKey.get(keys[i])
2798 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02002799 if (r == null) continue;
2800 StatusBarNotification sbn = r.sbn;
2801 if (!isVisibleToListener(sbn, info)) continue;
2802 StatusBarNotification sbnToSend =
2803 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2804 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002805 }
Christoph Studercee44ba2014-05-20 18:36:43 +02002806 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002807 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002808 }
2809
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002810 /**
2811 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2812 * seen by the current user. Useful when starting up, after which point the listener
2813 * callbacks should be used.
2814 *
2815 * @param token The binder for the listener, to check that the caller is allowed
2816 * @returns The return value will contain the notifications specified in keys, in that
2817 * order, or if keys is null, all the notifications, in natural order.
2818 */
2819 @Override
2820 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2821 INotificationListener token, int trim) {
2822 synchronized (mNotificationLock) {
2823 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2824 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2825 final int N = snoozedRecords.size();
2826 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2827 for (int i=0; i < N; i++) {
2828 final NotificationRecord r = snoozedRecords.get(i);
2829 if (r == null) continue;
2830 StatusBarNotification sbn = r.sbn;
2831 if (!isVisibleToListener(sbn, info)) continue;
2832 StatusBarNotification sbnToSend =
2833 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2834 list.add(sbnToSend);
2835 }
2836 return new ParceledListSlice<>(list);
2837 }
2838 }
2839
Adam Lesinski182f73f2013-12-05 16:48:06 -08002840 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002841 public void requestHintsFromListener(INotificationListener token, int hints) {
2842 final long identity = Binder.clearCallingIdentity();
2843 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002844 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002845 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07002846 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2847 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2848 | HINT_HOST_DISABLE_CALL_EFFECTS;
2849 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04002850 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07002851 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002852 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07002853 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002854 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002855 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04002856 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04002857 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002858 } finally {
2859 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04002860 }
2861 }
2862
2863 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002864 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002865 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002866 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04002867 }
2868 }
2869
2870 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02002871 public void requestInterruptionFilterFromListener(INotificationListener token,
2872 int interruptionFilter) throws RemoteException {
2873 final long identity = Binder.clearCallingIdentity();
2874 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002875 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002876 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2877 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02002878 updateInterruptionFilterLocked();
2879 }
2880 } finally {
2881 Binder.restoreCallingIdentity(identity);
2882 }
2883 }
2884
2885 @Override
2886 public int getInterruptionFilterFromListener(INotificationListener token)
2887 throws RemoteException {
2888 synchronized (mNotificationLight) {
2889 return mInterruptionFilter;
2890 }
2891 }
2892
2893 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02002894 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2895 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002896 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02002897 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2898 if (info == null) return;
2899 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2900 }
2901 }
2902
2903 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002904 public int getZenMode() {
2905 return mZenModeHelper.getZenMode();
2906 }
2907
2908 @Override
John Spurlock056c5192014-04-20 21:52:01 -04002909 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002910 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04002911 return mZenModeHelper.getConfig();
2912 }
2913
2914 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002915 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002916 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05002917 final long identity = Binder.clearCallingIdentity();
2918 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002919 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05002920 } finally {
2921 Binder.restoreCallingIdentity(identity);
2922 }
2923 }
2924
2925 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002926 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002927 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05002928 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002929 }
2930
2931 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002932 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2933 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002934 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002935 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002936 }
2937
2938 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002939 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002940 throws RemoteException {
2941 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2942 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2943 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2944 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002945 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002946
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002947 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2948 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002949 }
2950
2951 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002952 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002953 throws RemoteException {
2954 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2955 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2956 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2957 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2958 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002959
Julia Reynolds361e82d32016-02-26 18:19:49 -05002960 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002961 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002962 }
2963
2964 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002965 public boolean removeAutomaticZenRule(String id) throws RemoteException {
2966 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002967 // Verify that they can modify zen rules.
2968 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2969
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002970 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002971 }
2972
2973 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05002974 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2975 Preconditions.checkNotNull(packageName, "Package name is null");
2976 enforceSystemOrSystemUI("removeAutomaticZenRules");
2977
2978 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2979 }
2980
2981 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05002982 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2983 Preconditions.checkNotNull(owner, "Owner is null");
2984 enforceSystemOrSystemUI("getRuleInstanceCount");
2985
2986 return mZenModeHelper.getCurrentInstanceCount(owner);
2987 }
2988
2989 @Override
John Spurlock80774932015-05-07 17:38:50 -04002990 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2991 enforcePolicyAccess(pkg, "setInterruptionFilter");
2992 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2993 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2994 final long identity = Binder.clearCallingIdentity();
2995 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002996 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04002997 } finally {
2998 Binder.restoreCallingIdentity(identity);
2999 }
3000 }
3001
3002 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04003003 public void notifyConditions(final String pkg, IConditionProvider provider,
3004 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04003005 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3006 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04003007 mHandler.post(new Runnable() {
3008 @Override
3009 public void run() {
3010 mConditionProviders.notifyConditions(pkg, info, conditions);
3011 }
3012 });
John Spurlocke77bb362014-04-26 10:24:59 -04003013 }
3014
Julia Reynolds38e6ca42016-08-08 08:38:09 -04003015 @Override
3016 public void requestUnbindProvider(IConditionProvider provider) {
3017 long identity = Binder.clearCallingIdentity();
3018 try {
3019 // allow bound services to disable themselves
3020 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3021 info.getOwner().setComponentState(info.component, false);
3022 } finally {
3023 Binder.restoreCallingIdentity(identity);
3024 }
3025 }
3026
3027 @Override
3028 public void requestBindProvider(ComponentName component) {
3029 checkCallerIsSystemOrSameApp(component.getPackageName());
3030 long identity = Binder.clearCallingIdentity();
3031 try {
3032 mConditionProviders.setComponentState(component, true);
3033 } finally {
3034 Binder.restoreCallingIdentity(identity);
3035 }
3036 }
3037
John Spurlocke77bb362014-04-26 10:24:59 -04003038 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003039 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04003040 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
3041 message);
John Spurlock7340fc82014-04-24 18:50:12 -04003042 }
3043
Julia Reynolds48034f82016-03-09 10:15:16 -05003044 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
3045 try {
3046 checkCallerIsSystemOrSameApp(pkg);
3047 } catch (SecurityException e) {
3048 getContext().enforceCallingPermission(
3049 android.Manifest.permission.STATUS_BAR_SERVICE,
3050 message);
3051 }
3052 }
3053
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003054 private void enforcePolicyAccess(int uid, String method) {
3055 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3056 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3057 return;
3058 }
3059 boolean accessAllowed = false;
3060 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
3061 final int packageCount = packages.length;
3062 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003063 if (mConditionProviders.isPackageOrComponentAllowed(
3064 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003065 accessAllowed = true;
3066 }
3067 }
3068 if (!accessAllowed) {
3069 Slog.w(TAG, "Notification policy access denied calling " + method);
3070 throw new SecurityException("Notification policy access denied");
3071 }
3072 }
3073
John Spurlock80774932015-05-07 17:38:50 -04003074 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04003075 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3076 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3077 return;
3078 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04003079 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003080 if (!checkPolicyAccess(pkg)) {
3081 Slog.w(TAG, "Notification policy access denied calling " + method);
3082 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04003083 }
3084 }
3085
John Spurlock80774932015-05-07 17:38:50 -04003086 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003087 return mConditionProviders.isPackageOrComponentAllowed(
3088 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04003089 }
3090
3091 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003092 try {
3093 int uid = getContext().getPackageManager().getPackageUidAsUser(
3094 pkg, UserHandle.getCallingUserId());
3095 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
3096 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
3097 -1, true)) {
3098 return true;
3099 }
3100 } catch (NameNotFoundException e) {
3101 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003102 }
John Spurlock80774932015-05-07 17:38:50 -04003103 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04003104 }
3105
John Spurlock7340fc82014-04-24 18:50:12 -04003106 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08003107 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003108 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04003109 final DumpFilter filter = DumpFilter.parseFromArguments(args);
Kweku Adams887f09c2017-11-13 17:12:20 -08003110 if (filter.stats) {
Chris Wrene4b38802015-07-07 15:54:19 -04003111 dumpJson(pw, filter);
Kweku Adams887f09c2017-11-13 17:12:20 -08003112 } else if (filter.proto) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003113 dumpProto(fd, filter);
Vishnu Naire3e4d252018-03-01 11:26:57 -08003114 } else if (filter.criticalPriority) {
3115 dumpNotificationRecords(pw, filter);
Chris Wrene4b38802015-07-07 15:54:19 -04003116 } else {
3117 dumpImpl(pw, filter);
3118 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003119 }
John Spurlockb4782522014-08-22 14:54:46 -04003120
3121 @Override
3122 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07003123 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04003124 }
John Spurlock2b122f42014-08-27 16:29:47 -04003125
3126 @Override
3127 public boolean matchesCallFilter(Bundle extras) {
3128 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02003129 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003130 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02003131 extras,
3132 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
3133 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
3134 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04003135 }
John Spurlock530052a2014-11-30 16:26:19 -05003136
3137 @Override
3138 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003139 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04003140 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05003141 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003142
Christopher Tatef9767d62015-04-08 14:35:43 -07003143 // Backup/restore interface
3144 @Override
3145 public byte[] getBackupPayload(int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003146 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003147 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003148 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003149 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003150 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
3151 return null;
3152 }
songjinshi9bf22712017-02-04 10:47:45 +08003153 synchronized(mPolicyFile) {
3154 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
3155 try {
3156 writePolicyXml(baos, true /*forBackup*/);
3157 return baos.toByteArray();
3158 } catch (IOException e) {
3159 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
3160 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003161 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003162 return null;
3163 }
3164
3165 @Override
3166 public void applyRestore(byte[] payload, int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003167 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003168 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
3169 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
3170 if (payload == null) {
3171 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
3172 return;
3173 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07003174 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003175 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04003176 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
3177 return;
3178 }
songjinshi9bf22712017-02-04 10:47:45 +08003179 synchronized(mPolicyFile) {
3180 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
3181 try {
3182 readPolicyXml(bais, true /*forRestore*/);
3183 savePolicyFile();
3184 } catch (NumberFormatException | XmlPullParserException | IOException e) {
3185 Slog.w(TAG, "applyRestore: error reading payload", e);
3186 }
John Spurlock35ef0a62015-05-28 11:24:10 -04003187 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003188 }
3189
John Spurlock1fc476d2015-04-14 16:05:20 -04003190 @Override
John Spurlock80774932015-05-07 17:38:50 -04003191 public boolean isNotificationPolicyAccessGranted(String pkg) {
3192 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04003193 }
3194
3195 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05003196 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
3197 enforceSystemOrSystemUIOrSamePackage(pkg,
3198 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003199 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003200 }
3201
3202 @Override
John Spurlock80774932015-05-07 17:38:50 -04003203 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
3204 throws RemoteException {
Julia Reynolds92febc32017-10-26 11:30:31 -04003205 setNotificationPolicyAccessGrantedForUser(
3206 pkg, getCallingUserHandle().getIdentifier(), granted);
3207 }
3208
3209 @Override
3210 public void setNotificationPolicyAccessGrantedForUser(
3211 String pkg, int userId, boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003212 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003213 final long identity = Binder.clearCallingIdentity();
3214 try {
Julia Reynoldse1816412017-10-24 10:39:11 -04003215 if (canUseManagedServices()) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003216 mConditionProviders.setPackageOrComponentEnabled(
Julia Reynolds92febc32017-10-26 11:30:31 -04003217 pkg, userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003218
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003219 getContext().sendBroadcastAsUser(new Intent(
3220 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3221 .setPackage(pkg)
3222 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003223 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003224 savePolicyFile();
3225 }
3226 } finally {
3227 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003228 }
John Spurlock80774932015-05-07 17:38:50 -04003229 }
3230
3231 @Override
3232 public Policy getNotificationPolicy(String pkg) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003233 final long identity = Binder.clearCallingIdentity();
3234 try {
3235 return mZenModeHelper.getNotificationPolicy();
3236 } finally {
3237 Binder.restoreCallingIdentity(identity);
3238 }
3239 }
3240
Beverly6697eff2017-12-14 15:00:27 -05003241 /**
3242 * Sets the notification policy. Apps that target API levels below
Beverly98ef61b2018-02-15 10:36:28 -05003243 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
Beverlyd6964762018-02-16 14:07:03 -05003244 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3245 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3246 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
Beverly6697eff2017-12-14 15:00:27 -05003247 */
John Spurlock1fc476d2015-04-14 16:05:20 -04003248 @Override
John Spurlock80774932015-05-07 17:38:50 -04003249 public void setNotificationPolicy(String pkg, Policy policy) {
3250 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04003251 final long identity = Binder.clearCallingIdentity();
3252 try {
Beverly6697eff2017-12-14 15:00:27 -05003253 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3254 0, UserHandle.getUserId(MY_UID));
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003255 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
Beverly6697eff2017-12-14 15:00:27 -05003256
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06003257 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
Beverly98ef61b2018-02-15 10:36:28 -05003258 int priorityCategories = policy.priorityCategories;
3259 // ignore alarm and media values from new policy
3260 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
Beverlyd6964762018-02-16 14:07:03 -05003261 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3262 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003263 // use user-designated values
Beverlyd6964762018-02-16 14:07:03 -05003264 priorityCategories |= currPolicy.priorityCategories
3265 & Policy.PRIORITY_CATEGORY_ALARMS;
3266 priorityCategories |= currPolicy.priorityCategories
3267 & Policy.PRIORITY_CATEGORY_MEDIA;
3268 priorityCategories |= currPolicy.priorityCategories
3269 & Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003270
Beverly6697eff2017-12-14 15:00:27 -05003271 policy = new Policy(priorityCategories,
3272 policy.priorityCallSenders, policy.priorityMessageSenders,
3273 policy.suppressedVisualEffects);
3274 }
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003275 int newVisualEffects = calculateSuppressedVisualEffects(
3276 policy, currPolicy, applicationInfo.targetSdkVersion);
3277 policy = new Policy(policy.priorityCategories,
3278 policy.priorityCallSenders, policy.priorityMessageSenders,
3279 newVisualEffects);
Beverly6697eff2017-12-14 15:00:27 -05003280
Beverly5e073222018-03-08 10:36:25 -05003281 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
John Spurlock1fc476d2015-04-14 16:05:20 -04003282 mZenModeHelper.setNotificationPolicy(policy);
Beverly6697eff2017-12-14 15:00:27 -05003283 } catch (RemoteException e) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003284 } finally {
3285 Binder.restoreCallingIdentity(identity);
3286 }
3287 }
Chris Wren51017d02015-12-15 15:34:46 -05003288
3289 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003290 public List<String> getEnabledNotificationListenerPackages() {
3291 checkCallerIsSystem();
3292 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3293 }
3294
3295 @Override
3296 public List<ComponentName> getEnabledNotificationListeners(int userId) {
3297 checkCallerIsSystem();
3298 return mListeners.getAllowedComponents(userId);
3299 }
3300
3301 @Override
3302 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3303 Preconditions.checkNotNull(listener);
3304 checkCallerIsSystemOrSameApp(listener.getPackageName());
3305 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3306 getCallingUserHandle().getIdentifier());
3307 }
3308
3309 @Override
3310 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3311 int userId) {
3312 Preconditions.checkNotNull(listener);
3313 checkCallerIsSystem();
3314 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3315 userId);
3316 }
3317
3318 @Override
3319 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3320 Preconditions.checkNotNull(assistant);
3321 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003322 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04003323 getCallingUserHandle().getIdentifier());
3324 }
3325
3326 @Override
3327 public void setNotificationListenerAccessGranted(ComponentName listener,
3328 boolean granted) throws RemoteException {
3329 setNotificationListenerAccessGrantedForUser(
3330 listener, getCallingUserHandle().getIdentifier(), granted);
3331 }
3332
3333 @Override
3334 public void setNotificationAssistantAccessGranted(ComponentName assistant,
3335 boolean granted) throws RemoteException {
3336 setNotificationAssistantAccessGrantedForUser(
3337 assistant, getCallingUserHandle().getIdentifier(), granted);
3338 }
3339
3340 @Override
3341 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3342 boolean granted) throws RemoteException {
3343 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04003344 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003345 final long identity = Binder.clearCallingIdentity();
3346 try {
Julia Reynoldse1816412017-10-24 10:39:11 -04003347 if (canUseManagedServices()) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003348 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3349 userId, false, granted);
3350 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3351 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003352
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003353 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds92febc32017-10-26 11:30:31 -04003354 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003355 .setPackage(listener.getPackageName())
3356 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003357 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003358
3359 savePolicyFile();
3360 }
3361 } finally {
3362 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003363 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003364 }
3365
3366 @Override
3367 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3368 int userId, boolean granted) throws RemoteException {
3369 Preconditions.checkNotNull(assistant);
Julia Reynolds0d217642017-08-11 11:26:04 -04003370 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003371 final long identity = Binder.clearCallingIdentity();
3372 try {
Julia Reynoldse1816412017-10-24 10:39:11 -04003373 if (canUseManagedServices()) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003374 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
3375 userId, false, granted);
3376 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
3377 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003378
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003379 getContext().sendBroadcastAsUser(new Intent(
3380 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3381 .setPackage(assistant.getPackageName())
3382 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003383 UserHandle.of(userId), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003384
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003385 savePolicyFile();
3386 }
3387 } finally {
3388 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003389 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003390 }
3391
3392 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003393 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
3394 Adjustment adjustment) throws RemoteException {
3395 final long identity = Binder.clearCallingIdentity();
3396 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003397 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003398 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003399 int N = mEnqueuedNotifications.size();
3400 for (int i = 0; i < N; i++) {
3401 final NotificationRecord n = mEnqueuedNotifications.get(i);
3402 if (Objects.equals(adjustment.getKey(), n.getKey())
3403 && Objects.equals(adjustment.getUser(), n.getUserId())) {
3404 applyAdjustment(n, adjustment);
3405 break;
3406 }
3407 }
3408 }
3409 } finally {
3410 Binder.restoreCallingIdentity(identity);
3411 }
3412 }
3413
3414 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003415 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003416 Adjustment adjustment) throws RemoteException {
Chris Wren51017d02015-12-15 15:34:46 -05003417 final long identity = Binder.clearCallingIdentity();
3418 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003419 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003420 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003421 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3422 applyAdjustment(n, adjustment);
Chris Wren51017d02015-12-15 15:34:46 -05003423 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003424 mRankingHandler.requestSort();
Julia Reynoldse46bb372016-03-17 11:05:58 -04003425 } finally {
3426 Binder.restoreCallingIdentity(identity);
3427 }
3428 }
3429
3430 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003431 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003432 List<Adjustment> adjustments) throws RemoteException {
3433
3434 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 Reynoldse46bb372016-03-17 11:05:58 -04003438 for (Adjustment adjustment : adjustments) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003439 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3440 applyAdjustment(n, adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003441 }
3442 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003443 mRankingHandler.requestSort();
Chris Wren51017d02015-12-15 15:34:46 -05003444 } finally {
3445 Binder.restoreCallingIdentity(identity);
3446 }
3447 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003448
3449 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04003450 public void updateNotificationChannelGroupFromPrivilegedListener(
3451 INotificationListener token, String pkg, UserHandle user,
3452 NotificationChannelGroup group) throws RemoteException {
3453 Preconditions.checkNotNull(user);
3454 verifyPrivilegedListener(token, user);
3455 createNotificationChannelGroup(
3456 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
3457 savePolicyFile();
3458 }
3459
3460 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003461 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003462 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003463 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003464 Preconditions.checkNotNull(pkg);
3465 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003466
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003467 verifyPrivilegedListener(token, user);
3468 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003469 }
3470
3471 @Override
3472 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003473 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3474 Preconditions.checkNotNull(pkg);
3475 Preconditions.checkNotNull(user);
3476 verifyPrivilegedListener(token, user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003477
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003478 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
3479 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003480 }
3481
3482 @Override
3483 public ParceledListSlice<NotificationChannelGroup>
3484 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003485 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3486 Preconditions.checkNotNull(pkg);
3487 Preconditions.checkNotNull(user);
3488 verifyPrivilegedListener(token, user);
3489
3490 List<NotificationChannelGroup> groups = new ArrayList<>();
3491 groups.addAll(mRankingHelper.getNotificationChannelGroups(
3492 pkg, getUidForPackageAndUser(pkg, user)));
3493 return new ParceledListSlice<>(groups);
3494 }
3495
3496 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003497 ManagedServiceInfo info;
3498 synchronized (mNotificationLock) {
3499 info = mListeners.checkServiceTokenLocked(token);
3500 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003501 if (!hasCompanionDevice(info)) {
3502 throw new SecurityException(info + " does not have access");
3503 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003504 if (!info.enabledAndUserMatches(user.getIdentifier())) {
3505 throw new SecurityException(info + " does not have access");
3506 }
3507 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003508
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003509 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3510 int uid = 0;
3511 long identity = Binder.clearCallingIdentity();
3512 try {
3513 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3514 } finally {
3515 Binder.restoreCallingIdentity(identity);
3516 }
3517 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003518 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003519
3520 @Override
3521 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3522 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3523 throws RemoteException {
3524 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3525 }
John Spurlock1fc476d2015-04-14 16:05:20 -04003526 };
John Spurlocka4294292014-03-24 18:02:32 -04003527
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003528 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3529 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003530 return;
3531 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003532 if (adjustment.getSignals() != null) {
3533 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003534 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003535 }
3536 }
3537
Julia Reynolds88860ce2017-06-01 16:55:49 -04003538 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003539 void addAutogroupKeyLocked(String key) {
3540 NotificationRecord r = mNotificationsByKey.get(key);
3541 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003542 return;
3543 }
Julia Reynolds51710712017-07-19 13:48:07 -04003544 if (r.sbn.getOverrideGroupKey() == null) {
3545 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3546 EventLogTags.writeNotificationAutogrouped(key);
3547 mRankingHandler.requestSort();
3548 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003549 }
3550
Julia Reynolds88860ce2017-06-01 16:55:49 -04003551 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003552 void removeAutogroupKeyLocked(String key) {
3553 NotificationRecord r = mNotificationsByKey.get(key);
3554 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003555 return;
3556 }
Julia Reynolds51710712017-07-19 13:48:07 -04003557 if (r.sbn.getOverrideGroupKey() != null) {
3558 addAutoGroupAdjustment(r, null);
3559 EventLogTags.writeNotificationUnautogrouped(key);
3560 mRankingHandler.requestSort();
3561 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003562 }
3563
3564 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3565 Bundle signals = new Bundle();
3566 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3567 Adjustment adjustment =
3568 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3569 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003570 }
3571
3572 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04003573 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04003574 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3575 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3576 if (summaries != null && summaries.containsKey(pkg)) {
3577 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003578 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04003579 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04003580 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003581 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003582 }
3583 }
3584 }
3585
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003586 @GuardedBy("mNotificationLock")
3587 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3588 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3589 return summaries != null && summaries.containsKey(sbn.getPackageName());
3590 }
3591
Julia Reynoldse46bb372016-03-17 11:05:58 -04003592 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04003593 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3594 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003595 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003596 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3597 if (notificationRecord == null) {
3598 // The notification could have been cancelled again already. A successive
3599 // adjustment will post a summary if needed.
3600 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003601 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003602 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3603 userId = adjustedSbn.getUser().getIdentifier();
3604 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3605 if (summaries == null) {
3606 summaries = new ArrayMap<>();
3607 }
3608 mAutobundledSummaries.put(userId, summaries);
3609 if (!summaries.containsKey(pkg)) {
3610 // Add summary
3611 final ApplicationInfo appInfo =
3612 adjustedSbn.getNotification().extras.getParcelable(
3613 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3614 final Bundle extras = new Bundle();
3615 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003616 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04003617 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003618 new Notification.Builder(getContext(), channelId)
3619 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04003620 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04003621 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04003622 .setGroup(GroupHelper.AUTOGROUP_KEY)
3623 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3624 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3625 .setColor(adjustedSbn.getNotification().color)
3626 .setLocalOnly(true)
3627 .build();
3628 summaryNotification.extras.putAll(extras);
3629 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3630 if (appIntent != null) {
3631 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3632 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3633 }
3634 final StatusBarNotification summarySbn =
3635 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003636 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003637 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04003638 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3639 adjustedSbn.getInitialPid(), summaryNotification,
3640 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3641 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05003642 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003643 notificationRecord.getChannel());
Rohan Shah590e1b22018-04-10 23:48:47 -04003644 summaryRecord.setIsAppImportanceLocked(
3645 notificationRecord.getIsAppImportanceLocked());
Julia Reynolds8f488d32016-10-14 10:59:01 -04003646 summaries.put(pkg, summarySbn.getKey());
3647 }
3648 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003649 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04003650 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003651 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04003652 }
3653 }
3654
John Spurlock32fe4c62014-10-02 12:16:02 -04003655 private String disableNotificationEffects(NotificationRecord record) {
3656 if (mDisableNotificationEffects) {
3657 return "booleanState";
3658 }
3659 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3660 return "listenerHints";
3661 }
3662 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3663 return "callState";
3664 }
3665 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04003666 };
3667
Kweku Adams887f09c2017-11-13 17:12:20 -08003668 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
Chris Wrene4b38802015-07-07 15:54:19 -04003669 JSONObject dump = new JSONObject();
3670 try {
3671 dump.put("service", "Notification Manager");
Chris Wrenacf424a2016-03-15 12:48:55 -04003672 dump.put("bans", mRankingHelper.dumpBansJson(filter));
3673 dump.put("ranking", mRankingHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003674 dump.put("stats", mUsageStats.dumpJson(filter));
Julia Reynoldsd373d782017-03-03 13:32:57 -05003675 dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003676 } catch (JSONException e) {
3677 e.printStackTrace();
3678 }
3679 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04003680 }
3681
Kweku Adams887f09c2017-11-13 17:12:20 -08003682 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003683 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3684 synchronized (mNotificationLock) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003685 int N = mNotificationList.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003686 for (int i = 0; i < N; i++) {
3687 final NotificationRecord nr = mNotificationList.get(i);
3688 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3689 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3690 NotificationRecordProto.POSTED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003691 }
3692 N = mEnqueuedNotifications.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003693 for (int i = 0; i < N; i++) {
3694 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3695 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3696 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3697 NotificationRecordProto.ENQUEUED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003698 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003699 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3700 N = snoozed.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003701 for (int i = 0; i < N; i++) {
3702 final NotificationRecord nr = snoozed.get(i);
3703 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3704 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3705 NotificationRecordProto.SNOOZED);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003706 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003707
Kweku Adams93304b62017-09-20 17:03:00 -07003708 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3709 mZenModeHelper.dump(proto);
3710 for (ComponentName suppressor : mEffectsSuppressors) {
Kweku Adams99546332018-01-24 17:03:50 -08003711 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
Kweku Adams93304b62017-09-20 17:03:00 -07003712 }
3713 proto.end(zenLog);
3714
3715 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
3716 mListeners.dump(proto, filter);
3717 proto.end(listenersToken);
3718
3719 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
3720
3721 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
3722 long effectsToken = proto.start(
3723 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
3724
3725 proto.write(
3726 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
3727 final ArraySet<ManagedServiceInfo> listeners =
3728 mListenersDisablingEffects.valueAt(i);
3729 for (int j = 0; j < listeners.size(); j++) {
3730 final ManagedServiceInfo listener = listeners.valueAt(i);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08003731 listener.writeToProto(proto, ListenersDisablingEffectsProto.LISTENERS, null);
Kweku Adams93304b62017-09-20 17:03:00 -07003732 }
3733
3734 proto.end(effectsToken);
3735 }
3736
3737 long assistantsToken = proto.start(
3738 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
3739 mAssistants.dump(proto, filter);
3740 proto.end(assistantsToken);
3741
3742 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
3743 mConditionProviders.dump(proto, filter);
3744 proto.end(conditionsToken);
Kweku Adams62b42242017-09-25 12:54:02 -07003745
3746 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
3747 mRankingHelper.dump(proto, filter);
3748 proto.end(rankingToken);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003749 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003750
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003751 proto.flush();
3752 }
3753
Vishnu Naire3e4d252018-03-01 11:26:57 -08003754 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
3755 synchronized (mNotificationLock) {
3756 int N;
3757 N = mNotificationList.size();
3758 if (N > 0) {
3759 pw.println(" Notification List:");
3760 for (int i = 0; i < N; i++) {
3761 final NotificationRecord nr = mNotificationList.get(i);
3762 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3763 nr.dump(pw, " ", getContext(), filter.redact);
3764 }
3765 pw.println(" ");
3766 }
3767 }
3768 }
3769
Kweku Adams887f09c2017-11-13 17:12:20 -08003770 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
John Spurlock25e2d242014-06-27 13:58:23 -04003771 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04003772 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003773 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04003774 }
3775 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08003776 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003777 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003778
John Spurlock50806fc2014-07-15 10:22:02 -04003779 if (!zenOnly) {
3780 synchronized (mToastQueue) {
3781 N = mToastQueue.size();
3782 if (N > 0) {
3783 pw.println(" Toast Queue:");
3784 for (int i=0; i<N; i++) {
3785 mToastQueue.get(i).dump(pw, " ", filter);
3786 }
3787 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003788 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003789 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003790 }
3791
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003792 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04003793 if (!zenOnly) {
Vishnu Naire3e4d252018-03-01 11:26:57 -08003794 // Priority filters are only set when called via bugreport. If set
3795 // skip sections that are part of the critical section.
3796 if (!filter.normalPriority) {
3797 dumpNotificationRecords(pw, filter);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003798 }
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003799 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003800 N = mLights.size();
3801 if (N > 0) {
3802 pw.println(" Lights List:");
3803 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05003804 if (i == N - 1) {
3805 pw.print(" > ");
3806 } else {
3807 pw.print(" ");
3808 }
3809 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04003810 }
3811 pw.println(" ");
3812 }
John Spurlockcb566aa2014-08-03 22:58:28 -04003813 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
3814 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05003815 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3816 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003817 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04003818 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04003819 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04003820 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04003821 }
3822 pw.println(" mArchive=" + mArchive.toString());
3823 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003824 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04003825 while (iter.hasNext()) {
3826 final StatusBarNotification sbn = iter.next();
3827 if (filter != null && !filter.matches(sbn)) continue;
3828 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003829 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04003830 if (iter.hasNext()) pw.println(" ...");
3831 break;
3832 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003833 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003834
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003835 if (!zenOnly) {
3836 N = mEnqueuedNotifications.size();
3837 if (N > 0) {
3838 pw.println(" Enqueued Notification List:");
3839 for (int i = 0; i < N; i++) {
3840 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3841 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3842 nr.dump(pw, " ", getContext(), filter.redact);
3843 }
3844 pw.println(" ");
3845 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003846
3847 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003848 }
3849 }
3850
John Spurlock50806fc2014-07-15 10:22:02 -04003851 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04003852 pw.println("\n Ranking Config:");
3853 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04003854
John Spurlock50806fc2014-07-15 10:22:02 -04003855 pw.println("\n Notification listeners:");
3856 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003857 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3858 pw.print(" mListenersDisablingEffects: (");
3859 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04003860 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003861 final int hint = mListenersDisablingEffects.keyAt(i);
3862 if (i > 0) pw.print(';');
3863 pw.print("hint[" + hint + "]:");
3864
3865 final ArraySet<ManagedServiceInfo> listeners =
3866 mListenersDisablingEffects.valueAt(i);
3867 final int listenerSize = listeners.size();
3868
3869 for (int j = 0; j < listenerSize; j++) {
3870 if (i > 0) pw.print(',');
3871 final ManagedServiceInfo listener = listeners.valueAt(i);
3872 pw.print(listener.component);
3873 }
John Spurlock1fa865f2014-07-21 14:56:39 -04003874 }
3875 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05003876 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003877 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04003878 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003879
Julia Reynolds520df6e2017-02-13 09:05:10 -05003880 if (!filter.filtered || zenOnly) {
3881 pw.println("\n Zen Mode:");
3882 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3883 mZenModeHelper.dump(pw, " ");
3884
3885 pw.println("\n Zen Log:");
3886 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003887 }
3888
John Spurlocke77bb362014-04-26 10:24:59 -04003889 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04003890 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02003891
3892 pw.println("\n Group summaries:");
3893 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3894 NotificationRecord r = entry.getValue();
3895 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3896 if (mNotificationsByKey.get(r.getKey()) != r) {
3897 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04003898 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02003899 }
3900 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003901
3902 if (!zenOnly) {
3903 pw.println("\n Usage Stats:");
3904 mUsageStats.dump(pw, " ", filter);
3905 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003906 }
3907 }
3908
Adam Lesinski182f73f2013-12-05 16:48:06 -08003909 /**
3910 * The private API only accessible to the system process.
3911 */
3912 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3913 @Override
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04003914 public NotificationChannel getNotificationChannel(String pkg, int uid, String
3915 channelId) {
3916 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
3917 }
3918
3919 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003920 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003921 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003922 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003923 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003924 }
Christoph Studer365e4c32014-09-18 20:35:36 +02003925
3926 @Override
3927 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3928 int userId) {
3929 checkCallerIsSystem();
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003930 mHandler.post(new Runnable() {
3931 @Override
3932 public void run() {
3933 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003934 removeForegroundServiceFlagByListLocked(
3935 mEnqueuedNotifications, pkg, notificationId, userId);
3936 removeForegroundServiceFlagByListLocked(
3937 mNotificationList, pkg, notificationId, userId);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003938 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003939 }
3940 });
3941 }
3942
Julia Reynolds88860ce2017-06-01 16:55:49 -04003943 @GuardedBy("mNotificationLock")
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003944 private void removeForegroundServiceFlagByListLocked(
Julia Reynolds88860ce2017-06-01 16:55:49 -04003945 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3946 int userId) {
3947 NotificationRecord r = findNotificationByListLocked(
3948 notificationList, pkg, null, notificationId, userId);
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003949 if (r == null) {
3950 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02003951 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003952 StatusBarNotification sbn = r.sbn;
3953 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3954 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3955 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3956 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3957 sbn.getNotification().flags =
3958 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3959 mRankingHelper.sort(mNotificationList);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003960 mListeners.notifyPostedLocked(r, sbn /* oldSbn */);
Christoph Studer365e4c32014-09-18 20:35:36 +02003961 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003962 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003963
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003964 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04003965 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003966 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04003967 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08003968 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3969 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04003970 }
John Spurlock7340fc82014-04-24 18:50:12 -04003971 checkCallerIsSystemOrSameApp(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003972
Scott Greenwald9b05c612013-06-25 23:44:05 -04003973 final int userId = ActivityManager.handleIncomingUser(callingPid,
3974 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
Jeff Sharkey65c4a2b2012-09-25 17:22:27 -07003975 final UserHandle user = new UserHandle(userId);
Dianne Hackborn41203752012-08-31 14:05:51 -07003976
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003977 if (pkg == null || notification == null) {
3978 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3979 + " id=" + id + " notification=" + notification);
3980 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003981
3982 // The system can post notifications for any package, let us resolve that.
3983 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3984
Julia Reynoldse46bb372016-03-17 11:05:58 -04003985 // Fix the notification as best we can.
3986 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003987 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06003988 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003989 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
Julia Reynoldse071abd2017-03-22 10:52:11 -04003990 Notification.addFieldsFromContext(ai, notification);
Julia Reynolds4db59552017-06-30 13:34:01 -04003991
3992 int canColorize = mPackageManagerClient.checkPermission(
3993 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
3994 if (canColorize == PERMISSION_GRANTED) {
3995 notification.flags |= Notification.FLAG_CAN_COLORIZE;
3996 } else {
3997 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
3998 }
3999
Julia Reynoldse46bb372016-03-17 11:05:58 -04004000 } catch (NameNotFoundException e) {
4001 Slog.e(TAG, "Cannot create a context for sending app", e);
4002 return;
4003 }
4004
Chris Wren888b7a82016-06-17 15:47:19 -04004005 mUsageStats.registerEnqueuedByApp(pkg);
4006
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004007 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04004008 String channelId = notification.getChannelId();
4009 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
4010 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05004011 }
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004012 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004013 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004014 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004015 final String noChannelStr = "No Channel found for "
4016 + "pkg=" + pkg
4017 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04004018 + ", id=" + id
4019 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004020 + ", opPkg=" + opPkg
4021 + ", callingUid=" + callingUid
4022 + ", userId=" + userId
4023 + ", incomingUserId=" + incomingUserId
4024 + ", notificationUid=" + notificationUid
4025 + ", notification=" + notification;
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004026 Log.e(TAG, noChannelStr);
Beverly5d4564b2018-04-10 20:09:23 -04004027 boolean appNotificationsOff = mRankingHelper.getImportance(pkg, notificationUid)
4028 == NotificationManager.IMPORTANCE_NONE;
4029
4030 if (!appNotificationsOff) {
4031 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
4032 "Failed to post notification on channel \"" + channelId + "\"\n" +
4033 "See log for more details");
4034 }
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004035 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004036 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004037
Chris Wrena61f1792016-08-04 11:24:42 -04004038 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004039 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004040 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004041 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Rohan Shah590e1b22018-04-10 23:48:47 -04004042 r.setIsAppImportanceLocked(mRankingHelper.getIsAppImportanceLocked(pkg, callingUid));
Chris Wrena61f1792016-08-04 11:24:42 -04004043
Julia Reynolds8617e4e2017-09-18 16:52:37 -04004044 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
4045 && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
4046 && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
4047 // Increase the importance of foreground service notifications unless the user had an
4048 // opinion otherwise
4049 if (TextUtils.isEmpty(channelId)
4050 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4051 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
4052 } else {
4053 channel.setImportance(IMPORTANCE_LOW);
4054 mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
4055 r.updateNotificationChannel(channel);
4056 }
4057 }
4058
Julia Reynolds5e702192017-08-18 09:22:40 -04004059 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
4060 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004061 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07004062 }
4063
Felipe Lemedd85da62016-06-28 11:29:54 -07004064 // Whitelist pending intents.
4065 if (notification.allPendingIntents != null) {
4066 final int intentCount = notification.allPendingIntents.size();
4067 if (intentCount > 0) {
4068 final ActivityManagerInternal am = LocalServices
4069 .getService(ActivityManagerInternal.class);
4070 final long duration = LocalServices.getService(
4071 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
4072 for (int i = 0; i < intentCount; i++) {
4073 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4074 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07004075 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4076 WHITELIST_TOKEN, duration);
Felipe Lemedd85da62016-06-28 11:29:54 -07004077 }
4078 }
4079 }
4080 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07004081
Chris Wren47633422016-01-22 09:56:59 -05004082 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004083 }
4084
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04004085 private void doChannelWarningToast(CharSequence toastText) {
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04004086 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04004087 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04004088 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4089 if (warningEnabled) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04004090 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
Geoffrey Pitsch5bdddbd2017-05-26 10:50:05 -04004091 Toast.LENGTH_SHORT);
Geoffrey Pitschd34c1872017-05-04 16:02:15 -04004092 toast.show();
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004093 }
4094 }
4095
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004096 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
4097 // The system can post notifications on behalf of any package it wants
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004098 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004099 try {
4100 return getContext().getPackageManager()
4101 .getPackageUidAsUser(opPackageName, userId);
4102 } catch (NameNotFoundException e) {
4103 /* ignore */
4104 }
4105 }
4106 return callingUid;
4107 }
4108
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004109 /**
4110 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4111 *
4112 * Has side effects.
4113 */
4114 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04004115 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004116 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004117 final boolean isSystemNotification =
4118 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004119 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
4120
4121 // Limit the number of notifications that any given package except the android
4122 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
4123 if (!isSystemNotification && !isNotificationFromListener) {
4124 synchronized (mNotificationLock) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004125 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
4126 // Ephemeral apps have some special constraints for notifications.
4127 // They are not allowed to create new notifications however they are allowed to
4128 // update notifications created by the system (e.g. a foreground service
4129 // notification).
4130 throw new SecurityException("Instant app " + pkg
4131 + " cannot create notifications");
4132 }
4133
4134 // rate limit updates that aren't completed progress notifications
4135 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04004136 && !r.getNotification().hasCompletedProgress()
4137 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004138
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004139 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
4140 if (appEnqueueRate > mMaxPackageEnqueueRate) {
4141 mUsageStats.registerOverRateQuota(pkg);
4142 final long now = SystemClock.elapsedRealtime();
4143 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
4144 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04004145 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004146 mLastOverRateLogTime = now;
4147 }
4148 return false;
4149 }
4150 }
4151
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004152 // limit the number of outstanding notificationrecords an app can have
4153 int count = getNotificationCountLocked(pkg, userId, id, tag);
4154 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
4155 mUsageStats.registerOverCountQuota(pkg);
4156 Slog.e(TAG, "Package has already posted or enqueued " + count
4157 + " notifications. Not showing more. package=" + pkg);
4158 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004159 }
4160 }
4161 }
4162
4163 // snoozed apps
4164 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05004165 MetricsLogger.action(r.getLogMaker()
4166 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
4167 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004168 if (DBG) {
4169 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
4170 }
4171 mSnoozeHelper.update(userId, r);
4172 savePolicyFile();
4173 return false;
4174 }
4175
4176
4177 // blocked apps
4178 if (isBlocked(r, mUsageStats)) {
4179 return false;
4180 }
4181
4182 return true;
4183 }
4184
Andreas Gampea36dc622018-02-05 17:19:22 -08004185 @GuardedBy("mNotificationLock")
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04004186 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
4187 String excludedTag) {
4188 int count = 0;
4189 final int N = mNotificationList.size();
4190 for (int i = 0; i < N; i++) {
4191 final NotificationRecord existing = mNotificationList.get(i);
4192 if (existing.sbn.getPackageName().equals(pkg)
4193 && existing.sbn.getUserId() == userId) {
4194 if (existing.sbn.getId() == excludedId
4195 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
4196 continue;
4197 }
4198 count++;
4199 }
4200 }
4201 final int M = mEnqueuedNotifications.size();
4202 for (int i = 0; i < M; i++) {
4203 final NotificationRecord existing = mEnqueuedNotifications.get(i);
4204 if (existing.sbn.getPackageName().equals(pkg)
4205 && existing.sbn.getUserId() == userId) {
4206 count++;
4207 }
4208 }
4209 return count;
4210 }
4211
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004212 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
4213 final String pkg = r.sbn.getPackageName();
4214 final int callingUid = r.sbn.getUid();
4215
4216 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
4217 if (isPackageSuspended) {
4218 Slog.e(TAG, "Suppressing notification from package due to package "
4219 + "suspended by administrator.");
4220 usageStats.registerSuspendedByAdmin(r);
4221 return isPackageSuspended;
4222 }
Julia Reynolds4da79702017-06-01 11:06:10 -04004223 final boolean isBlocked =
Julia Reynolds005c8b92017-08-24 10:35:53 -04004224 mRankingHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
4225 || mRankingHelper.getImportance(pkg, callingUid)
4226 == NotificationManager.IMPORTANCE_NONE
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04004227 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004228 if (isBlocked) {
4229 Slog.e(TAG, "Suppressing notification from package by user request.");
4230 usageStats.registerBlocked(r);
4231 }
4232 return isBlocked;
4233 }
4234
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004235 protected class SnoozeNotificationRunnable implements Runnable {
4236 private final String mKey;
4237 private final long mDuration;
4238 private final String mSnoozeCriterionId;
4239
4240 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
4241 mKey = key;
4242 mDuration = duration;
4243 mSnoozeCriterionId = snoozeCriterionId;
4244 }
4245
4246 @Override
4247 public void run() {
4248 synchronized (mNotificationLock) {
4249 final NotificationRecord r = findNotificationByKeyLocked(mKey);
4250 if (r != null) {
4251 snoozeLocked(r);
4252 }
4253 }
4254 }
4255
Julia Reynolds88860ce2017-06-01 16:55:49 -04004256 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004257 void snoozeLocked(NotificationRecord r) {
4258 if (r.sbn.isGroup()) {
4259 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
4260 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
4261 if (r.getNotification().isGroupSummary()) {
4262 // snooze summary and all children
4263 for (int i = 0; i < groupNotifications.size(); i++) {
4264 snoozeNotificationLocked(groupNotifications.get(i));
4265 }
4266 } else {
4267 // if there is a valid summary for this group, and we are snoozing the only
4268 // child, also snooze the summary
4269 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
4270 if (groupNotifications.size() != 2) {
4271 snoozeNotificationLocked(r);
4272 } else {
4273 // snooze summary and the one child
4274 for (int i = 0; i < groupNotifications.size(); i++) {
4275 snoozeNotificationLocked(groupNotifications.get(i));
4276 }
4277 }
4278 } else {
4279 snoozeNotificationLocked(r);
4280 }
4281 }
4282 } else {
4283 // just snooze the one notification
4284 snoozeNotificationLocked(r);
4285 }
4286 }
4287
Julia Reynolds88860ce2017-06-01 16:55:49 -04004288 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004289 void snoozeNotificationLocked(NotificationRecord r) {
4290 MetricsLogger.action(r.getLogMaker()
4291 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4292 .setType(MetricsEvent.TYPE_CLOSE)
Chris Wren21a2e722017-10-02 17:44:53 -04004293 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
4294 mDuration)
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004295 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4296 mSnoozeCriterionId == null ? 0 : 1));
Julia Reynolds0839c022017-06-15 15:24:01 -04004297 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004298 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004299 updateLightsLocked();
4300 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004301 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004302 mSnoozeHelper.snooze(r);
4303 } else {
4304 mSnoozeHelper.snooze(r, mDuration);
4305 }
Julia Reynolds503ed942017-10-04 16:04:56 -04004306 r.recordSnoozed();
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004307 savePolicyFile();
4308 }
4309 }
4310
Julia Reynoldsbaff4002016-12-15 11:34:26 -05004311 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05004312 private final NotificationRecord r;
4313 private final int userId;
4314
4315 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
4316 this.userId = userId;
4317 this.r = r;
4318 };
4319
4320 @Override
4321 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004322 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05004323 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05004324 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05004325
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004326 final StatusBarNotification n = r.sbn;
4327 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
4328 NotificationRecord old = mNotificationsByKey.get(n.getKey());
4329 if (old != null) {
4330 // Retain ranking information from previous record
4331 r.copyRankingInformation(old);
4332 }
4333
4334 final int callingUid = n.getUid();
4335 final int callingPid = n.getInitialPid();
4336 final Notification notification = n.getNotification();
4337 final String pkg = n.getPackageName();
4338 final int id = n.getId();
4339 final String tag = n.getTag();
4340
4341 // Handle grouped notifications and bail out early if we
4342 // can to avoid extracting signals.
4343 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
4344
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004345 // if this is a group child, unsnooze parent summary
4346 if (n.isGroup() && notification.isGroupChild()) {
4347 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
4348 }
4349
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004350 // This conditional is a dirty hack to limit the logging done on
4351 // behalf of the download manager without affecting other apps.
4352 if (!pkg.equals("com.android.providers.downloads")
4353 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
4354 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05004355 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004356 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05004357 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004358 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
4359 pkg, id, tag, userId, notification.toString(),
4360 enqueueStatus);
4361 }
Chris Wren6676dab2016-12-21 18:26:27 -05004362
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004363 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05004364
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004365 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004366 if (mAssistants.isEnabled()) {
4367 mAssistants.onNotificationEnqueued(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004368 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004369 DELAY_FOR_ASSISTANT_TIME);
4370 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004371 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004372 }
4373 }
4374 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004375 }
4376
Beverly5a20a5e2018-03-06 15:02:44 -05004377 @GuardedBy("mNotificationLock")
4378 private boolean isPackageSuspendedLocked(NotificationRecord r) {
4379 final String pkg = r.sbn.getPackageName();
4380 final int callingUid = r.sbn.getUid();
4381
4382 return isPackageSuspendedForUser(pkg, callingUid);
4383 }
4384
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004385 protected class PostNotificationRunnable implements Runnable {
4386 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004387
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004388 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004389 this.key = key;
4390 }
4391
4392 @Override
4393 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004394 synchronized (mNotificationLock) {
4395 try {
4396 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004397 int N = mEnqueuedNotifications.size();
4398 for (int i = 0; i < N; i++) {
4399 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4400 if (Objects.equals(key, enqueued.getKey())) {
4401 r = enqueued;
4402 break;
Chris Wren6676dab2016-12-21 18:26:27 -05004403 }
Chris Wren6676dab2016-12-21 18:26:27 -05004404 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004405 if (r == null) {
4406 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
4407 return;
4408 }
Beverly5a20a5e2018-03-06 15:02:44 -05004409
4410 r.setHidden(isPackageSuspendedLocked(r));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004411 NotificationRecord old = mNotificationsByKey.get(key);
4412 final StatusBarNotification n = r.sbn;
4413 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05004414 int index = indexOfNotificationLocked(n.getKey());
4415 if (index < 0) {
4416 mNotificationList.add(r);
4417 mUsageStats.registerPostedByApp(r);
Julia Reynolds7217dc92018-03-07 12:12:09 -05004418 r.setInterruptive(true);
Chris Wren6676dab2016-12-21 18:26:27 -05004419 } else {
4420 old = mNotificationList.get(index);
4421 mNotificationList.set(index, r);
4422 mUsageStats.registerUpdatedByApp(r, old);
4423 // Make sure we don't lose the foreground service state.
4424 notification.flags |=
4425 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
Julia Reynoldse0d711f2017-09-01 08:50:47 -04004426 // revoke uri permissions for changed uris
4427 revokeUriPermissions(r, old);
Chris Wren6676dab2016-12-21 18:26:27 -05004428 r.isUpdate = true;
Julia Reynolds7217dc92018-03-07 12:12:09 -05004429 r.setInterruptive(isVisuallyInterruptive(old, r));
Chris Wren6676dab2016-12-21 18:26:27 -05004430 }
4431
4432 mNotificationsByKey.put(n.getKey(), r);
4433
4434 // Ensure if this is a foreground service that the proper additional
4435 // flags are set.
4436 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4437 notification.flags |= Notification.FLAG_ONGOING_EVENT
4438 | Notification.FLAG_NO_CLEAR;
4439 }
4440
4441 applyZenModeLocked(r);
4442 mRankingHelper.sort(mNotificationList);
4443
4444 if (notification.getSmallIcon() != null) {
4445 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Julia Reynoldse0d711f2017-09-01 08:50:47 -04004446 mListeners.notifyPostedLocked(r, oldSbn);
Julia Reynolds8aebf352017-06-26 11:35:33 -04004447 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
4448 mHandler.post(new Runnable() {
4449 @Override
4450 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04004451 mGroupHelper.onNotificationPosted(
4452 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04004453 }
4454 });
4455 }
Chris Wren6676dab2016-12-21 18:26:27 -05004456 } else {
4457 Slog.e(TAG, "Not posting notification without small icon: " + notification);
4458 if (old != null && !old.isCanceled) {
Beverly5a20a5e2018-03-06 15:02:44 -05004459 mListeners.notifyRemovedLocked(r,
Julia Reynolds503ed942017-10-04 16:04:56 -04004460 NotificationListenerService.REASON_ERROR, null);
Chris Wren6676dab2016-12-21 18:26:27 -05004461 mHandler.post(new Runnable() {
4462 @Override
4463 public void run() {
4464 mGroupHelper.onNotificationRemoved(n);
4465 }
4466 });
4467 }
4468 // ATTENTION: in a future release we will bail out here
4469 // so that we do not play sounds, show lights, etc. for invalid
4470 // notifications
4471 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
4472 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05004473 }
Chris Wren47633422016-01-22 09:56:59 -05004474
Beverly5a20a5e2018-03-06 15:02:44 -05004475 if (!r.isHidden()) {
4476 buzzBeepBlinkLocked(r);
4477 }
Julia Reynolds1fac86e2018-03-07 08:30:37 -05004478 maybeRecordInterruptionLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004479 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004480 int N = mEnqueuedNotifications.size();
4481 for (int i = 0; i < N; i++) {
4482 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4483 if (Objects.equals(key, enqueued.getKey())) {
4484 mEnqueuedNotifications.remove(i);
4485 break;
4486 }
4487 }
Chris Wren6676dab2016-12-21 18:26:27 -05004488 }
Chris Wren47633422016-01-22 09:56:59 -05004489 }
4490 }
4491 }
4492
Christoph Studer265c1052014-07-23 17:14:33 +02004493 /**
Julia Reynolds7217dc92018-03-07 12:12:09 -05004494 * If the notification differs enough visually, consider it a new interruptive notification.
4495 */
4496 @GuardedBy("mNotificationLock")
4497 @VisibleForTesting
4498 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
4499 Notification oldN = old.sbn.getNotification();
4500 Notification newN = r.sbn.getNotification();
4501 if (oldN.extras == null || newN.extras == null) {
4502 return false;
4503 }
4504 if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TITLE),
4505 newN.extras.get(Notification.EXTRA_TITLE))) {
4506 return true;
4507 }
4508 if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TEXT),
4509 newN.extras.get(Notification.EXTRA_TEXT))) {
4510 return true;
4511 }
4512 if (oldN.extras.containsKey(Notification.EXTRA_PROGRESS) && newN.hasCompletedProgress()) {
4513 return true;
4514 }
4515 // Actions
4516 if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
4517 return true;
4518 }
4519
4520 try {
4521 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
4522 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
4523
4524 // Style based comparisons
4525 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
4526 return true;
4527 }
4528
4529 // Remote views
4530 if (Notification.areRemoteViewsChanged(oldB, newB)) {
4531 return true;
4532 }
4533 } catch (Exception e) {
4534 Slog.w(TAG, "error recovering builder", e);
4535 }
4536 return false;
4537 }
4538
4539 /**
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05004540 * Keeps the last 5 packages that have notified, by user.
4541 */
4542 @GuardedBy("mNotificationLock")
4543 @VisibleForTesting
4544 protected void logRecentLocked(NotificationRecord r) {
4545 if (r.isUpdate) {
4546 return;
4547 }
4548 ArrayList<NotifyingApp> recentAppsForUser =
4549 mRecentApps.getOrDefault(r.getUser().getIdentifier(), new ArrayList<>(6));
4550 NotifyingApp na = new NotifyingApp()
4551 .setPackage(r.sbn.getPackageName())
4552 .setUid(r.sbn.getUid())
4553 .setLastNotified(r.sbn.getPostTime());
4554 // A new notification gets an app moved to the front of the list
4555 for (int i = recentAppsForUser.size() - 1; i >= 0; i--) {
4556 NotifyingApp naExisting = recentAppsForUser.get(i);
4557 if (na.getPackage().equals(naExisting.getPackage())
4558 && na.getUid() == naExisting.getUid()) {
4559 recentAppsForUser.remove(i);
4560 break;
4561 }
4562 }
4563 // time is always increasing, so always add to the front of the list
4564 recentAppsForUser.add(0, na);
4565 if (recentAppsForUser.size() > 5) {
4566 recentAppsForUser.remove(recentAppsForUser.size() -1);
4567 }
4568 mRecentApps.put(r.getUser().getIdentifier(), recentAppsForUser);
4569 }
4570
4571 /**
Christoph Studer265c1052014-07-23 17:14:33 +02004572 * Ensures that grouped notification receive their special treatment.
4573 *
4574 * <p>Cancels group children if the new notification causes a group to lose
4575 * its summary.</p>
4576 *
4577 * <p>Updates mSummaryByGroupKey.</p>
4578 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004579 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02004580 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
4581 int callingUid, int callingPid) {
4582 StatusBarNotification sbn = r.sbn;
4583 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07004584 if (n.isGroupSummary() && !sbn.isAppGroup()) {
4585 // notifications without a group shouldn't be a summary, otherwise autobundling can
4586 // lead to bugs
4587 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
4588 }
4589
Christoph Studer265c1052014-07-23 17:14:33 +02004590 String group = sbn.getGroupKey();
4591 boolean isSummary = n.isGroupSummary();
4592
4593 Notification oldN = old != null ? old.sbn.getNotification() : null;
4594 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
4595 boolean oldIsSummary = old != null && oldN.isGroupSummary();
4596
4597 if (oldIsSummary) {
4598 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
4599 if (removedSummary != old) {
4600 String removedKey =
4601 removedSummary != null ? removedSummary.getKey() : "<null>";
4602 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
4603 ", removed=" + removedKey);
4604 }
4605 }
4606 if (isSummary) {
4607 mSummaryByGroupKey.put(group, r);
4608 }
4609
4610 // Clear out group children of the old notification if the update
4611 // causes the group summary to go away. This happens when the old
4612 // notification was a summary and the new one isn't, or when the old
4613 // notification was a summary and its group key changed.
4614 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04004615 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
4616 null);
Christoph Studer265c1052014-07-23 17:14:33 +02004617 }
4618 }
4619
Chris Wren93bb8b82016-03-29 14:35:05 -04004620 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004621 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05004622 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04004623 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05004624 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4625 REQUEST_CODE_TIMEOUT,
4626 new Intent(ACTION_NOTIFICATION_TIMEOUT)
4627 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4628 .appendPath(record.getKey()).build())
4629 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4630 .putExtra(EXTRA_KEY, record.getKey()),
4631 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05004632 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04004633 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05004634 }
4635 }
4636
4637 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004638 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04004639 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04004640 boolean buzz = false;
4641 boolean beep = false;
4642 boolean blink = false;
4643
Chris Wrena3446562014-06-03 18:11:47 -04004644 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04004645 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04004646
4647 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04004648 final boolean aboveThreshold =
4649 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04004650
4651 // Remember if this notification already owns the notification channels.
4652 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4653 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04004654 // These are set inside the conditional if the notification is allowed to make noise.
4655 boolean hasValidVibrate = false;
4656 boolean hasValidSound = false;
Julia Reynolds94187562017-10-10 13:58:49 -04004657 boolean sentAccessibilityEvent = false;
4658 // If the notification will appear in the status bar, it should send an accessibility
4659 // event
4660 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4661 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4662 sentAccessibilityEvent = true;
4663 }
Chris Wrena3446562014-06-03 18:11:47 -04004664
Julia Reynolds76c096d2017-06-19 08:16:04 -04004665 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004666
Julia Reynolds76c096d2017-06-19 08:16:04 -04004667 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004668 Uri soundUri = record.getSound();
4669 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4670 long[] vibration = record.getVibration();
4671 // Demote sound to vibration if vibration missing & phone in vibration mode.
4672 if (vibration == null
4673 && hasValidSound
4674 && (mAudioManager.getRingerModeInternal()
Julia Reynolds85896572017-09-20 12:54:52 -04004675 == AudioManager.RINGER_MODE_VIBRATE)
4676 && mAudioManager.getStreamVolume(
4677 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004678 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04004679 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004680 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01004681
Julia Reynolds76c096d2017-06-19 08:16:04 -04004682 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
Julia Reynolds76c096d2017-06-19 08:16:04 -04004683 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004684 if (!sentAccessibilityEvent) {
4685 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4686 sentAccessibilityEvent = true;
4687 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004688 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04004689 if (hasValidSound) {
4690 mSoundNotificationKey = key;
4691 if (mInCall) {
4692 playInCallNotification();
4693 beep = true;
4694 } else {
4695 beep = playSound(record, soundUri);
4696 }
4697 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004698
Julia Reynolds7c96b582017-05-25 12:35:36 -04004699 final boolean ringerModeSilent =
4700 mAudioManager.getRingerModeInternal()
4701 == AudioManager.RINGER_MODE_SILENT;
4702 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
4703 mVibrateNotificationKey = key;
4704
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004705 buzz = playVibration(record, vibration, hasValidSound);
Julia Reynolds7c96b582017-05-25 12:35:36 -04004706 }
Chris Wrena3446562014-06-03 18:11:47 -04004707 }
4708 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004709 }
4710 // If a notification is updated to remove the actively playing sound or vibrate,
4711 // cancel that feedback now
4712 if (wasBeep && !hasValidSound) {
4713 clearSoundLocked();
4714 }
4715 if (wasBuzz && !hasValidVibrate) {
4716 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04004717 }
4718
4719 // light
4720 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04004721 boolean wasShowLights = mLights.remove(key);
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05004722 if (record.getLight() != null && aboveThreshold
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05004723 && ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) == 0)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04004724 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04004725 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04004726 if (mUseAttentionLight) {
4727 mAttentionLight.pulse();
4728 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004729 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04004730 } else if (wasShowLights) {
4731 updateLightsLocked();
4732 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004733 if (buzz || beep || blink) {
Julia Reynolds1fac86e2018-03-07 08:30:37 -05004734 record.setInterruptive(true);
Julia Reynolds445cfa82017-05-08 15:41:45 -04004735 MetricsLogger.action(record.getLogMaker()
4736 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4737 .setType(MetricsEvent.TYPE_OPEN)
4738 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4739 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04004740 }
Chris Wrena3446562014-06-03 18:11:47 -04004741 }
4742
Julia Reynolds88860ce2017-06-01 16:55:49 -04004743 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004744 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04004745 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004746 final Notification notification = record.getNotification();
4747 if(record.isUpdate
4748 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4749 return true;
4750 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004751
Julia Reynolds76c096d2017-06-19 08:16:04 -04004752 // muted by listener
4753 final String disableEffects = disableNotificationEffects(record);
4754 if (disableEffects != null) {
4755 ZenLog.traceDisableEffects(record, disableEffects);
4756 return true;
4757 }
4758
4759 // suppressed due to DND
4760 if (record.isIntercepted()) {
4761 return true;
4762 }
4763
4764 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004765 if (record.sbn.isGroup()) {
Julia Reynolds30203152017-05-26 13:36:31 -04004766 return notification.suppressAlertingDueToGrouping();
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004767 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004768
Julia Reynolds65b85cf2017-07-20 09:19:20 -04004769 // Suppressed for being too recently noisy
4770 final String pkg = record.sbn.getPackageName();
4771 if (mUsageStats.isAlertRateLimited(pkg)) {
4772 Slog.e(TAG, "Muting recently noisy " + record.getKey());
4773 return true;
4774 }
4775
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004776 return false;
4777 }
4778
Julia Reynolds0c299d42016-11-15 14:37:04 -05004779 private boolean playSound(final NotificationRecord record, Uri soundUri) {
4780 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
Jean-Michel Triviec2bb182018-03-23 18:04:00 -07004781 // play notifications if there is no user of exclusive audio focus
4782 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
4783 // VIBRATE ringer mode)
4784 if (!mAudioManager.isAudioFocusExclusive()
4785 && (mAudioManager.getStreamVolume(
4786 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05004787 final long identity = Binder.clearCallingIdentity();
4788 try {
4789 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4790 if (player != null) {
4791 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4792 + " with attributes " + record.getAudioAttributes());
4793 player.playAsync(soundUri, record.sbn.getUser(), looping,
4794 record.getAudioAttributes());
4795 return true;
4796 }
4797 } catch (RemoteException e) {
4798 } finally {
4799 Binder.restoreCallingIdentity(identity);
4800 }
4801 }
4802 return false;
4803 }
4804
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004805 private boolean playVibration(final NotificationRecord record, long[] vibration,
4806 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004807 // Escalate privileges so we can use the vibrator even if the
4808 // notifying app does not have the VIBRATE permission.
4809 long identity = Binder.clearCallingIdentity();
4810 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004811 final VibrationEffect effect;
4812 try {
4813 final boolean insistent =
4814 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4815 effect = VibrationEffect.createWaveform(
4816 vibration, insistent ? 0 : -1 /*repeatIndex*/);
4817 } catch (IllegalArgumentException e) {
4818 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4819 Arrays.toString(vibration));
4820 return false;
4821 }
4822 if (delayVibForSound) {
4823 new Thread(() -> {
4824 // delay the vibration by the same amount as the notification sound
4825 final int waitMs = mAudioManager.getFocusRampTimeMs(
4826 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
4827 record.getAudioAttributes());
4828 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
4829 try {
4830 Thread.sleep(waitMs);
4831 } catch (InterruptedException e) { }
4832 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4833 effect, record.getAudioAttributes());
4834 }).start();
4835 } else {
4836 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4837 effect, record.getAudioAttributes());
4838 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004839 return true;
4840 } finally{
4841 Binder.restoreCallingIdentity(identity);
4842 }
4843 }
4844
Julia Reynolds7c96b582017-05-25 12:35:36 -04004845 private boolean isNotificationForCurrentUser(NotificationRecord record) {
4846 final int currentUser;
4847 final long token = Binder.clearCallingIdentity();
4848 try {
4849 currentUser = ActivityManager.getCurrentUser();
4850 } finally {
4851 Binder.restoreCallingIdentity(token);
4852 }
4853 return (record.getUserId() == UserHandle.USER_ALL ||
4854 record.getUserId() == currentUser ||
4855 mUserProfiles.isCurrentProfile(record.getUserId()));
4856 }
4857
Beverly5d463b62017-07-26 14:13:40 -04004858 protected void playInCallNotification() {
Marta Białka39c992f2011-03-10 10:27:24 +01004859 new Thread() {
4860 @Override
4861 public void run() {
Beverly5d463b62017-07-26 14:13:40 -04004862 final long identity = Binder.clearCallingIdentity();
Marta Białka39c992f2011-03-10 10:27:24 +01004863 try {
Beverly5d463b62017-07-26 14:13:40 -04004864 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4865 if (player != null) {
4866 player.play(new Binder(), mInCallNotificationUri,
4867 mInCallNotificationAudioAttributes,
4868 mInCallNotificationVolume, false);
Marta Białka39c992f2011-03-10 10:27:24 +01004869 }
Beverly5d463b62017-07-26 14:13:40 -04004870 } catch (RemoteException e) {
4871 } finally {
4872 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01004873 }
4874 }
4875 }.start();
4876 }
4877
Julia Reynolds88860ce2017-06-01 16:55:49 -04004878 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004879 void showNextToastLocked() {
4880 ToastRecord record = mToastQueue.get(0);
4881 while (record != null) {
4882 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
4883 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004884 record.callback.show(record.token);
Robert Carr997427342018-02-28 18:06:10 -08004885 scheduleDurationReachedLocked(record);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004886 return;
4887 } catch (RemoteException e) {
4888 Slog.w(TAG, "Object died trying to show notification " + record.callback
4889 + " in package " + record.pkg);
4890 // remove it from the list and let the process die
4891 int index = mToastQueue.indexOf(record);
4892 if (index >= 0) {
4893 mToastQueue.remove(index);
4894 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004895 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004896 if (mToastQueue.size() > 0) {
4897 record = mToastQueue.get(0);
4898 } else {
4899 record = null;
4900 }
4901 }
4902 }
4903 }
4904
Julia Reynolds88860ce2017-06-01 16:55:49 -04004905 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004906 void cancelToastLocked(int index) {
4907 ToastRecord record = mToastQueue.get(index);
4908 try {
4909 record.callback.hide();
4910 } catch (RemoteException e) {
4911 Slog.w(TAG, "Object died trying to hide notification " + record.callback
4912 + " in package " + record.pkg);
4913 // don't worry about this, we're about to remove it from
4914 // the list anyway
4915 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004916
4917 ToastRecord lastToast = mToastQueue.remove(index);
Robert Carr997427342018-02-28 18:06:10 -08004918
4919 mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
4920 DEFAULT_DISPLAY);
4921 // We passed 'false' for 'removeWindows' so that the client has time to stop
4922 // rendering (as hide above is a one-way message), otherwise we could crash
4923 // a client which was actively using a surface made from the token. However
4924 // we need to schedule a timeout to make sure the token is eventually killed
4925 // one way or another.
4926 scheduleKillTokenTimeout(lastToast.token);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004927
4928 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004929 if (mToastQueue.size() > 0) {
4930 // Show the next one. If the callback fails, this will remove
4931 // it from the list, so don't assume that the list hasn't changed
4932 // after this point.
4933 showNextToastLocked();
4934 }
4935 }
4936
Robert Carr997427342018-02-28 18:06:10 -08004937 void finishTokenLocked(IBinder t) {
4938 mHandler.removeCallbacksAndMessages(t);
4939 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
4940 // remaining surfaces as either the client has called finishToken indicating
4941 // it has successfully removed the views, or the client has timed out
4942 // at which point anything goes.
4943 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */,
4944 DEFAULT_DISPLAY);
4945 }
4946
Julia Reynolds88860ce2017-06-01 16:55:49 -04004947 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08004948 private void scheduleDurationReachedLocked(ToastRecord r)
Adam Lesinski182f73f2013-12-05 16:48:06 -08004949 {
4950 mHandler.removeCallbacksAndMessages(r);
Robert Carr997427342018-02-28 18:06:10 -08004951 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004952 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
4953 mHandler.sendMessageDelayed(m, delay);
4954 }
4955
Robert Carr997427342018-02-28 18:06:10 -08004956 private void handleDurationReached(ToastRecord record)
Adam Lesinski182f73f2013-12-05 16:48:06 -08004957 {
4958 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
4959 synchronized (mToastQueue) {
4960 int index = indexOfToastLocked(record.pkg, record.callback);
4961 if (index >= 0) {
4962 cancelToastLocked(index);
4963 }
4964 }
4965 }
4966
Julia Reynolds88860ce2017-06-01 16:55:49 -04004967 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08004968 private void scheduleKillTokenTimeout(IBinder token)
4969 {
4970 mHandler.removeCallbacksAndMessages(token);
4971 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, token);
Robert Carr3406d462018-03-15 16:19:07 -07004972 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
Robert Carr997427342018-02-28 18:06:10 -08004973 }
4974
4975 private void handleKillTokenTimeout(IBinder token)
4976 {
4977 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + token);
4978 synchronized (mToastQueue) {
4979 finishTokenLocked(token);
4980 }
4981 }
4982
4983 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004984 int indexOfToastLocked(String pkg, ITransientNotification callback)
4985 {
4986 IBinder cbak = callback.asBinder();
4987 ArrayList<ToastRecord> list = mToastQueue;
4988 int len = list.size();
4989 for (int i=0; i<len; i++) {
4990 ToastRecord r = list.get(i);
Beverly4ee785b2017-08-11 12:49:56 -04004991 if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
4992 return i;
4993 }
4994 }
4995 return -1;
4996 }
4997
4998 @GuardedBy("mToastQueue")
4999 int indexOfToastPackageLocked(String pkg)
5000 {
5001 ArrayList<ToastRecord> list = mToastQueue;
5002 int len = list.size();
5003 for (int i=0; i<len; i++) {
5004 ToastRecord r = list.get(i);
5005 if (r.pkg.equals(pkg)) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08005006 return i;
5007 }
5008 }
5009 return -1;
5010 }
5011
Julia Reynolds88860ce2017-06-01 16:55:49 -04005012 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005013 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08005014 {
5015 int toastCount = 0; // toasts from this pid
5016 ArrayList<ToastRecord> list = mToastQueue;
5017 int N = list.size();
5018 for (int i=0; i<N; i++) {
5019 ToastRecord r = list.get(i);
5020 if (r.pid == pid) {
5021 toastCount++;
5022 }
5023 }
5024 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07005025 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08005026 } catch (RemoteException e) {
5027 // Shouldn't happen.
5028 }
5029 }
5030
Chris Wrenf9536642014-04-17 10:01:54 -04005031 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005032 if (!(message.obj instanceof RankingReconsideration)) return;
5033 RankingReconsideration recon = (RankingReconsideration) message.obj;
5034 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04005035 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005036 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04005037 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
5038 if (record == null) {
5039 return;
Chris Wrenf9536642014-04-17 10:01:54 -04005040 }
Chris Wren333a61c2014-05-28 16:40:57 -04005041 int indexBefore = findNotificationRecordIndexLocked(record);
5042 boolean interceptBefore = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005043 float contactAffinityBefore = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005044 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04005045 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04005046 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04005047 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04005048 int indexAfter = findNotificationRecordIndexLocked(record);
5049 boolean interceptAfter = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005050 float contactAffinityAfter = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005051 int visibilityAfter = record.getPackageVisibilityOverride();
5052 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
5053 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04005054 if (interceptBefore && !interceptAfter
5055 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
Chris Wrena3446562014-06-03 18:11:47 -04005056 buzzBeepBlinkLocked(record);
5057 }
Chris Wrenf9536642014-04-17 10:01:54 -04005058 }
Chris Wren333a61c2014-05-28 16:40:57 -04005059 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005060 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04005061 }
5062 }
5063
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005064 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04005065 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005066 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04005067 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005068 // Any field that can change via one of the extractors needs to be added here.
5069 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005070 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05005071 boolean[] showBadges = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005072 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
5073 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
5074 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
5075 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Julia Reynolds503ed942017-10-04 16:04:56 -04005076 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005077 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
Chris Wren54bbef42014-07-09 18:37:56 -04005078 for (int i = 0; i < N; i++) {
5079 final NotificationRecord r = mNotificationList.get(i);
5080 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005081 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05005082 showBadges[i] = r.canShowBadge();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005083 channelBefore.add(r.getChannel());
5084 groupKeyBefore.add(r.getGroupKey());
5085 overridePeopleBefore.add(r.getPeopleOverride());
5086 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Julia Reynolds503ed942017-10-04 16:04:56 -04005087 userSentimentBefore.add(r.getUserSentiment());
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005088 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
Chris Wren54bbef42014-07-09 18:37:56 -04005089 mRankingHelper.extractSignals(r);
5090 }
Chris Wren19a02b02015-12-22 10:34:22 -05005091 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04005092 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005093 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005094 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05005095 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005096 || showBadges[i] != r.canShowBadge()
5097 || !Objects.equals(channelBefore.get(i), r.getChannel())
5098 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
5099 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
Julia Reynolds503ed942017-10-04 16:04:56 -04005100 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05005101 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
5102 || !Objects.equals(suppressVisuallyBefore.get(i),
5103 r.getSuppressedVisualEffects())) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005104 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04005105 return;
5106 }
5107 }
5108 }
5109 }
5110
Julia Reynolds88860ce2017-06-01 16:55:49 -04005111 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005112 private void recordCallerLocked(NotificationRecord record) {
5113 if (mZenModeHelper.isCall(record)) {
5114 mZenModeHelper.recordCaller(record);
5115 }
5116 }
5117
Christoph Studerd5092bc2014-07-03 17:47:58 +02005118 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04005119 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005120 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02005121 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005122 if (record.isIntercepted()) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05005123 record.setSuppressedVisualEffects(
5124 mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
Julia Reynolds445cfa82017-05-08 15:41:45 -04005125 } else {
5126 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005127 }
Chris Wren333a61c2014-05-28 16:40:57 -04005128 }
5129
Julia Reynolds88860ce2017-06-01 16:55:49 -04005130 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04005131 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04005132 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04005133 }
5134
Chris Wrenf9536642014-04-17 10:01:54 -04005135 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005136 synchronized (mNotificationLock) {
Beverly5a20a5e2018-03-06 15:02:44 -05005137 mListeners.notifyRankingUpdateLocked(null);
Chris Wrenf9536642014-04-17 10:01:54 -04005138 }
5139 }
5140
John Spurlockd8afe3c2014-08-01 14:04:07 -04005141 private void scheduleListenerHintsChanged(int state) {
5142 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
5143 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04005144 }
5145
Christoph Studer85a384b2014-08-27 20:16:15 +02005146 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
5147 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
5148 mHandler.obtainMessage(
5149 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
5150 listenerInterruptionFilter,
5151 0).sendToTarget();
5152 }
5153
John Spurlockd8afe3c2014-08-01 14:04:07 -04005154 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005155 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005156 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005157 }
5158 }
5159
Christoph Studer85a384b2014-08-27 20:16:15 +02005160 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005161 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02005162 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
5163 }
5164 }
5165
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005166 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08005167 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005168 public WorkerHandler(Looper looper) {
5169 super(looper);
5170 }
5171
Adam Lesinski182f73f2013-12-05 16:48:06 -08005172 @Override
5173 public void handleMessage(Message msg)
5174 {
5175 switch (msg.what)
5176 {
Robert Carr997427342018-02-28 18:06:10 -08005177 case MESSAGE_DURATION_REACHED:
5178 handleDurationReached((ToastRecord)msg.obj);
5179 break;
5180 case MESSAGE_FINISH_TOKEN_TIMEOUT:
5181 handleKillTokenTimeout((IBinder)msg.obj);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005182 break;
John Spurlock056c5192014-04-20 21:52:01 -04005183 case MESSAGE_SAVE_POLICY_FILE:
5184 handleSavePolicyFile();
5185 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005186 case MESSAGE_SEND_RANKING_UPDATE:
5187 handleSendRankingUpdate();
5188 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04005189 case MESSAGE_LISTENER_HINTS_CHANGED:
5190 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04005191 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02005192 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
5193 handleListenerInterruptionFilterChanged(msg.arg1);
5194 break;
Chris Wrenf9536642014-04-17 10:01:54 -04005195 }
5196 }
5197
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005198 protected void scheduleSendRankingUpdate() {
5199 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
5200 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
5201 sendMessage(m);
5202 }
5203 }
5204
Chris Wrenf9536642014-04-17 10:01:54 -04005205 }
5206
Chris Wren51017d02015-12-15 15:34:46 -05005207 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04005208 {
Chris Wren51017d02015-12-15 15:34:46 -05005209 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04005210 super(looper);
5211 }
5212
5213 @Override
5214 public void handleMessage(Message msg) {
5215 switch (msg.what) {
5216 case MESSAGE_RECONSIDER_RANKING:
5217 handleRankingReconsideration(msg);
5218 break;
Chris Wren51017d02015-12-15 15:34:46 -05005219 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005220 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04005221 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08005222 }
5223 }
Chris Wren51017d02015-12-15 15:34:46 -05005224
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005225 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05005226 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05005227 Message msg = Message.obtain();
5228 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05005229 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05005230 }
5231
5232 public void requestReconsideration(RankingReconsideration recon) {
5233 Message m = Message.obtain(this,
5234 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
5235 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
5236 sendMessageDelayed(m, delay);
5237 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08005238 }
5239
Adam Lesinski182f73f2013-12-05 16:48:06 -08005240 // Notifications
5241 // ============================================================================
5242 static int clamp(int x, int low, int high) {
5243 return (x < low) ? low : ((x > high) ? high : x);
5244 }
5245
5246 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
Eugene Suslad4128ec2017-12-04 19:48:41 +00005247 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07005248 return;
5249 }
5250
5251 AccessibilityEvent event =
5252 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
5253 event.setPackageName(packageName);
5254 event.setClassName(Notification.class.getName());
5255 event.setParcelableData(notification);
5256 CharSequence tickerText = notification.tickerText;
5257 if (!TextUtils.isEmpty(tickerText)) {
5258 event.getText().add(tickerText);
5259 }
5260
Julia Reynolds94187562017-10-10 13:58:49 -04005261 mAccessibilityManager.sendAccessibilityEvent(event);
svetoslavganov75986cf2009-05-14 22:28:01 -07005262 }
5263
Julia Reynolds0839c022017-06-15 15:24:01 -04005264 /**
5265 * Removes all NotificationsRecords with the same key as the given notification record
5266 * from both lists. Do not call this method while iterating over either list.
5267 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005268 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04005269 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
5270 // Remove from both lists, either list could have a separate Record for what is
5271 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005272 boolean wasPosted = false;
5273 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04005274 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
5275 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005276 mNotificationList.remove(recordInList);
5277 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005278 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005279 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005280 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005281 != null) {
5282 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005283 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005284 return wasPosted;
5285 }
5286
5287 @GuardedBy("mNotificationLock")
5288 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04005289 boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04005290 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04005291
5292 // Record caller.
5293 recordCallerLocked(r);
5294
Julia Reynolds503ed942017-10-04 16:04:56 -04005295 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
5296 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
5297 }
5298
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005299 // Revoke permissions
5300 revokeUriPermissions(null, r);
5301
Joe Onorato46439ce2010-11-19 13:56:21 -08005302 // tell the app
5303 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005304 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08005305 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005306 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08005307 } catch (PendingIntent.CanceledException ex) {
5308 // do nothing - there's no relevant way to recover, and
5309 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04005310 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08005311 }
5312 }
5313 }
5314
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005315 // Only cancel these if this notification actually got to be posted.
5316 if (wasPosted) {
5317 // status bar
5318 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005319 if (reason != REASON_SNOOZED) {
5320 r.isCanceled = true;
5321 }
Beverly5a20a5e2018-03-06 15:02:44 -05005322 mListeners.notifyRemovedLocked(r, reason, r.getStats());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005323 mHandler.post(new Runnable() {
5324 @Override
5325 public void run() {
5326 mGroupHelper.onNotificationRemoved(r.sbn);
5327 }
5328 });
5329 }
5330
5331 // sound
5332 if (canceledKey.equals(mSoundNotificationKey)) {
5333 mSoundNotificationKey = null;
5334 final long identity = Binder.clearCallingIdentity();
5335 try {
5336 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5337 if (player != null) {
5338 player.stopAsync();
5339 }
5340 } catch (RemoteException e) {
5341 } finally {
5342 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04005343 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005344 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005345
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005346 // vibrate
5347 if (canceledKey.equals(mVibrateNotificationKey)) {
5348 mVibrateNotificationKey = null;
5349 long identity = Binder.clearCallingIdentity();
5350 try {
5351 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005352 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005353 finally {
5354 Binder.restoreCallingIdentity(identity);
5355 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005356 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005357
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005358 // light
5359 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005360 }
5361
Christoph Studer546bec82014-03-14 12:17:12 +01005362 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04005363 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01005364 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005365 case REASON_CANCEL:
5366 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005367 case REASON_LISTENER_CANCEL:
5368 case REASON_LISTENER_CANCEL_ALL:
5369 mUsageStats.registerDismissedByUser(r);
5370 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05005371 case REASON_APP_CANCEL:
5372 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005373 mUsageStats.registerRemovedByApp(r);
5374 break;
Christoph Studer546bec82014-03-14 12:17:12 +01005375 }
5376
Christoph Studer265c1052014-07-23 17:14:33 +02005377 String groupKey = r.getGroupKey();
5378 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005379 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02005380 mSummaryByGroupKey.remove(groupKey);
5381 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04005382 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
5383 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
5384 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04005385 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005386
Daniel Sandler23d7c702013-03-07 16:32:06 -05005387 // Save it for users of getHistoricalNotifications()
5388 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02005389
Chris Wren6650e572015-05-15 17:19:25 -04005390 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -05005391 MetricsLogger.action(r.getLogMaker(now)
5392 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
5393 .setType(MetricsEvent.TYPE_DISMISS)
5394 .setSubtype(reason));
Chris Wrene6ddb8a2015-05-27 15:21:00 -04005395 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04005396 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005397 }
5398
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005399 void revokeUriPermissions(NotificationRecord newRecord, NotificationRecord oldRecord) {
5400 Set<Uri> oldUris = oldRecord.getNotificationUris();
5401 Set<Uri> newUris = newRecord == null ? new HashSet<>() : newRecord.getNotificationUris();
5402 oldUris.removeAll(newUris);
5403
5404 long ident = Binder.clearCallingIdentity();
5405 try {
5406 for (Uri uri : oldUris) {
5407 if (uri != null) {
5408 int notiUserId = oldRecord.getUserId();
5409 int sourceUserId = notiUserId == USER_ALL ? USER_SYSTEM
5410 : ContentProvider.getUserIdFromUri(uri, notiUserId);
5411 uri = ContentProvider.getUriWithoutUserId(uri);
5412 mAm.revokeUriPermissionFromOwner(mPermissionOwner,
5413 uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId);
5414 }
5415 }
5416 } catch (RemoteException e) {
5417 Log.e(TAG, "Count not revoke uri permissions", e);
5418 } finally {
5419 Binder.restoreCallingIdentity(ident);
5420 }
5421 }
5422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005423 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07005424 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005425 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005426 */
John Spurlocke6a7d932014-03-13 12:29:00 -04005427 void cancelNotification(final int callingUid, final int callingPid,
5428 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005429 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04005430 final int userId, final int reason, final ManagedServiceInfo listener) {
Beverly5a20a5e2018-03-06 15:02:44 -05005431
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005432 // In enqueueNotificationInternal notifications are added by scheduling the
5433 // work on the worker handler. Hence, we also schedule the cancel on this
5434 // handler to avoid a scenario where an add notification call followed by a
5435 // remove notification call ends up in not removing the notification.
5436 mHandler.post(new Runnable() {
5437 @Override
5438 public void run() {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005439 String listenerName = listener == null ? null : listener.component.toShortString();
Chris Wrenbddb5bc2015-03-04 08:47:46 -08005440 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
5441 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005442
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005443 synchronized (mNotificationLock) {
5444 // Look for the notification, searching both the posted and enqueued lists.
5445 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
5446 if (r != null) {
5447 // The notification was found, check if it should be removed.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005448
Christoph Studer546bec82014-03-14 12:17:12 +01005449 // Ideally we'd do this in the caller of this method. However, that would
5450 // require the caller to also find the notification.
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005451 if (reason == REASON_CLICK) {
Christoph Studer546bec82014-03-14 12:17:12 +01005452 mUsageStats.registerClickedByUser(r);
5453 }
5454
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005455 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
5456 return;
5457 }
5458 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
5459 return;
5460 }
5461
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005462 // Cancel the notification.
Julia Reynolds0839c022017-06-15 15:24:01 -04005463 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04005464 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Christoph Studer265c1052014-07-23 17:14:33 +02005465 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005466 sendDelete, null);
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005467 updateLightsLocked();
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005468 } else {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005469 // No notification was found, assume that it is snoozed and cancel it.
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005470 if (reason != REASON_SNOOZED) {
5471 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
5472 if (wasSnoozed) {
5473 savePolicyFile();
5474 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005475 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005476 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005477 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005478 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005479 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005480 }
5481
5482 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07005483 * Determine whether the userId applies to the notification in question, either because
5484 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
5485 */
5486 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
5487 return
5488 // looking for USER_ALL notifications? match everything
5489 userId == UserHandle.USER_ALL
5490 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005491 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07005492 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005493 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07005494 }
5495
5496 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005497 * Determine whether the userId applies to the notification in question, either because
5498 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01005499 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005500 */
Kenny Guy2a764942014-04-02 13:29:20 +01005501 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00005502 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04005503 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005504 }
5505
5506 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05005507 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005508 * {@code mustHaveFlags}.
5509 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005510 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005511 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005512 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005513 mHandler.post(new Runnable() {
5514 @Override
5515 public void run() {
5516 String listenerName = listener == null ? null : listener.component.toShortString();
5517 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5518 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
5519 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005520
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005521 // Why does this parameter exist? Do we actually want to execute the above if doit
5522 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005523 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005524 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005525 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005526
5527 synchronized (mNotificationLock) {
5528 FlagChecker flagChecker = (int flags) -> {
5529 if ((flags & mustHaveFlags) != mustHaveFlags) {
5530 return false;
5531 }
5532 if ((flags & mustNotHaveFlags) != 0) {
5533 return false;
5534 }
5535 return true;
5536 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005537 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5538 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
5539 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005540 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005541 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5542 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
5543 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005544 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005545 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005546 }
5547 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005548 });
5549 }
5550
5551 private interface FlagChecker {
5552 // Returns false if these flags do not pass the defined flag test.
5553 public boolean apply(int flags);
5554 }
5555
Julia Reynolds88860ce2017-06-01 16:55:49 -04005556 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005557 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
5558 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
5559 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005560 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005561 ArrayList<NotificationRecord> canceledNotifications = null;
5562 for (int i = notificationList.size() - 1; i >= 0; --i) {
5563 NotificationRecord r = notificationList.get(i);
5564 if (includeCurrentProfiles) {
5565 if (!notificationMatchesCurrentProfiles(r, userId)) {
5566 continue;
5567 }
5568 } else if (!notificationMatchesUserId(r, userId)) {
5569 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005570 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005571 // Don't remove notifications to all, if there's no package name specified
5572 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
5573 continue;
5574 }
5575 if (!flagChecker.apply(r.getFlags())) {
5576 continue;
5577 }
5578 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
5579 continue;
5580 }
5581 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
5582 continue;
5583 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005584 if (canceledNotifications == null) {
5585 canceledNotifications = new ArrayList<>();
5586 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005587 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005588 mNotificationsByKey.remove(r.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005589 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04005590 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005591 }
5592 if (canceledNotifications != null) {
5593 final int M = canceledNotifications.size();
5594 for (int i = 0; i < M; i++) {
5595 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005596 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005597 }
5598 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005599 }
5600 }
5601
Julia Reynolds50989772017-02-23 14:32:16 -05005602 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005603 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05005604 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005605 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05005606 return;
5607 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05005608
Julia Reynolds79672302017-01-12 08:30:16 -05005609 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05005610 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
5611 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05005612 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005613 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005614 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005615 }
5616
5617 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
5618 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005619 if (DBG) {
5620 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
5621 }
Julia Reynolds79672302017-01-12 08:30:16 -05005622 mSnoozeHelper.repost(key);
5623 savePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005624 }
5625
Julia Reynolds88860ce2017-06-01 16:55:49 -04005626 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07005627 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005628 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005629 mHandler.post(new Runnable() {
5630 @Override
5631 public void run() {
5632 synchronized (mNotificationLock) {
5633 String listenerName =
5634 listener == null ? null : listener.component.toShortString();
5635 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5636 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01005637
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005638 FlagChecker flagChecker = (int flags) -> {
5639 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
5640 != 0) {
5641 return false;
5642 }
5643 return true;
5644 };
5645
5646 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5647 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
5648 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005649 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005650 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5651 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
5652 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04005653 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005654 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00005655 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005656 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005657 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005658 }
5659
Christoph Studere4ef156b2014-07-04 18:41:57 +02005660 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04005661 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02005662 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005663 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005664 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02005665 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005666 return;
5667 }
5668
5669 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02005670
5671 if (pkg == null) {
5672 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
5673 return;
5674 }
5675
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005676 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005677 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005678 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005679 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005680 }
5681
Julia Reynolds88860ce2017-06-01 16:55:49 -04005682 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005683 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
5684 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005685 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005686 final String pkg = parentNotification.sbn.getPackageName();
5687 final int userId = parentNotification.getUserId();
5688 final int reason = REASON_GROUP_SUMMARY_CANCELED;
5689 for (int i = notificationList.size() - 1; i >= 0; i--) {
5690 final NotificationRecord childR = notificationList.get(i);
5691 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04005692 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005693 childR.getGroupKey().equals(parentNotification.getGroupKey())
Beverly40239d92017-07-07 10:20:41 -04005694 && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
5695 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02005696 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
5697 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04005698 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005699 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04005700 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005701 }
5702 }
5703 }
5704
Julia Reynolds88860ce2017-06-01 16:55:49 -04005705 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005706 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005707 {
The Android Open Source Project10592532009-03-18 17:39:46 -07005708 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05005709 NotificationRecord ledNotification = null;
5710 while (ledNotification == null && !mLights.isEmpty()) {
5711 final String owner = mLights.get(mLights.size() - 1);
5712 ledNotification = mNotificationsByKey.get(owner);
5713 if (ledNotification == null) {
5714 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
5715 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005716 }
5717 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005718
Mike Lockwood63b5ad92011-08-30 09:55:30 -04005719 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05005720 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05005721 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07005722 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05005723 NotificationRecord.Light light = ledNotification.getLight();
5724 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05005725 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05005726 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
5727 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05005728 }
The Android Open Source Project10592532009-03-18 17:39:46 -07005729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005730 }
5731
Julia Reynolds88860ce2017-06-01 16:55:49 -04005732 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005733 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
5734 String groupKey, int userId) {
5735 List<NotificationRecord> records = new ArrayList<>();
5736 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
5737 records.addAll(
5738 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
5739 return records;
5740 }
5741
5742
Julia Reynolds88860ce2017-06-01 16:55:49 -04005743 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005744 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
5745 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
5746 List<NotificationRecord> records = new ArrayList<>();
5747 final int len = list.size();
5748 for (int i = 0; i < len; i++) {
5749 NotificationRecord r = list.get(i);
5750 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
5751 && r.sbn.getPackageName().equals(pkg)) {
5752 records.add(r);
5753 }
5754 }
5755 return records;
5756 }
5757
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005758 // Searches both enqueued and posted notifications by key.
5759 // TODO: need to combine a bunch of these getters with slightly different behavior.
5760 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04005761 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005762 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005763 NotificationRecord r;
5764 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
5765 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005766 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005767 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
5768 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005769 }
5770 return null;
5771 }
5772
Julia Reynolds88860ce2017-06-01 16:55:49 -04005773 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005774 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005775 NotificationRecord r;
5776 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
5777 return r;
5778 }
5779 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
5780 != null) {
5781 return r;
5782 }
5783 return null;
5784 }
5785
Julia Reynolds88860ce2017-06-01 16:55:49 -04005786 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005787 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005788 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005789 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005790 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005791 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01005792 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
5793 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005794 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005795 }
5796 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005797 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005798 }
5799
Julia Reynolds88860ce2017-06-01 16:55:49 -04005800 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005801 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04005802 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005803 final int N = list.size();
5804 for (int i = 0; i < N; i++) {
5805 if (key.equals(list.get(i).getKey())) {
5806 return list.get(i);
5807 }
5808 }
5809 return null;
5810 }
5811
Julia Reynolds88860ce2017-06-01 16:55:49 -04005812 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02005813 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02005814 final int N = mNotificationList.size();
5815 for (int i = 0; i < N; i++) {
5816 if (key.equals(mNotificationList.get(i).getKey())) {
5817 return i;
5818 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02005819 }
Christoph Studerc5115552014-06-12 20:22:31 +02005820 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02005821 }
5822
Beverly5a20a5e2018-03-06 15:02:44 -05005823 @VisibleForTesting
5824 protected void hideNotificationsForPackages(String[] pkgs) {
5825 synchronized (mNotificationLock) {
5826 List<String> pkgList = Arrays.asList(pkgs);
5827 List<NotificationRecord> changedNotifications = new ArrayList<>();
5828 int numNotifications = mNotificationList.size();
5829 for (int i = 0; i < numNotifications; i++) {
5830 NotificationRecord rec = mNotificationList.get(i);
5831 if (pkgList.contains(rec.sbn.getPackageName())) {
5832 rec.setHidden(true);
5833 changedNotifications.add(rec);
5834 }
5835 }
5836
5837 mListeners.notifyHiddenLocked(changedNotifications);
5838 }
5839 }
5840
5841 @VisibleForTesting
5842 protected void unhideNotificationsForPackages(String[] pkgs) {
5843 synchronized (mNotificationLock) {
5844 List<String> pkgList = Arrays.asList(pkgs);
5845 List<NotificationRecord> changedNotifications = new ArrayList<>();
5846 int numNotifications = mNotificationList.size();
5847 for (int i = 0; i < numNotifications; i++) {
5848 NotificationRecord rec = mNotificationList.get(i);
5849 if (pkgList.contains(rec.sbn.getPackageName())) {
5850 rec.setHidden(false);
5851 changedNotifications.add(rec);
5852 }
5853 }
5854
5855 mListeners.notifyUnhiddenLocked(changedNotifications);
5856 }
5857 }
5858
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005859 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005860 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005861 updateLightsLocked();
5862 }
5863 }
John Spurlocke677d712014-02-13 12:52:19 -05005864
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005865 protected boolean isCallingUidSystem() {
5866 final int uid = Binder.getCallingUid();
5867 return uid == Process.SYSTEM_UID;
5868 }
5869
5870 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04005871 final int appid = UserHandle.getAppId(uid);
5872 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
5873 }
John Spurlockb408e8e2014-04-23 21:12:45 -04005874
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005875 // TODO: Most calls should probably move to isCallerSystem.
5876 protected boolean isCallerSystemOrPhone() {
5877 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04005878 }
5879
Julia Reynoldsb852e562017-06-06 16:14:18 -04005880 private void checkCallerIsSystemOrShell() {
5881 if (Binder.getCallingUid() == Process.SHELL_UID) {
5882 return;
5883 }
5884 checkCallerIsSystem();
5885 }
5886
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005887 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005888 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04005889 return;
5890 }
5891 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
5892 }
5893
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005894 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005895 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04005896 return;
5897 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04005898 checkCallerIsSameApp(pkg);
5899 }
5900
Chad Brubaker6b68f102017-01-27 13:39:00 -08005901 private boolean isCallerInstantApp(String pkg) {
5902 // System is always allowed to act for ephemeral apps.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005903 if (isCallerSystemOrPhone()) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08005904 return false;
5905 }
5906
5907 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
5908
5909 try {
5910 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
5911 UserHandle.getCallingUserId());
5912 if (ai == null) {
5913 throw new SecurityException("Unknown package " + pkg);
5914 }
5915 return ai.isInstantApp();
5916 } catch (RemoteException re) {
5917 throw new SecurityException("Unknown package " + pkg, re);
5918 }
5919
5920 }
5921
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005922 private void checkCallerIsSameApp(String pkg) {
John Spurlock7340fc82014-04-24 18:50:12 -04005923 final int uid = Binder.getCallingUid();
5924 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005925 ApplicationInfo ai = mPackageManager.getApplicationInfo(
John Spurlock7340fc82014-04-24 18:50:12 -04005926 pkg, 0, UserHandle.getCallingUserId());
Dan Sandler09afc2e2014-07-18 14:29:20 -04005927 if (ai == null) {
5928 throw new SecurityException("Unknown package " + pkg);
5929 }
John Spurlock7340fc82014-04-24 18:50:12 -04005930 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005931 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04005932 + pkg + " which is owned by uid " + ai.uid);
5933 }
5934 } catch (RemoteException re) {
5935 throw new SecurityException("Unknown package " + pkg + "\n" + re);
5936 }
5937 }
5938
John Spurlock32fe4c62014-10-02 12:16:02 -04005939 private static String callStateToString(int state) {
5940 switch (state) {
5941 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
5942 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
5943 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
5944 default: return "CALL_STATE_UNKNOWN_" + state;
5945 }
5946 }
5947
5948 private void listenForCallState() {
5949 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
5950 @Override
5951 public void onCallStateChanged(int state, String incomingNumber) {
5952 if (mCallState == state) return;
5953 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
5954 mCallState = state;
5955 }
5956 }, PhoneStateListener.LISTEN_CALL_STATE);
5957 }
5958
Christoph Studer05ad4822014-05-16 14:16:03 +02005959 /**
5960 * Generates a NotificationRankingUpdate from 'sbns', considering only
5961 * notifications visible to the given listener.
5962 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005963 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005964 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04005965 final int N = mNotificationList.size();
5966 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02005967 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05005968 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04005969 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005970 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005971 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05005972 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05005973 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05005974 Bundle overridePeople = new Bundle();
5975 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05005976 Bundle showBadge = new Bundle();
Julia Reynolds503ed942017-10-04 16:04:56 -04005977 Bundle userSentiment = new Bundle();
Beverly5a20a5e2018-03-06 15:02:44 -05005978 Bundle hidden = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04005979 for (int i = 0; i < N; i++) {
5980 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02005981 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005982 continue;
5983 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005984 final String key = record.sbn.getKey();
5985 keys.add(key);
5986 importance.add(record.getImportance());
5987 if (record.getImportanceExplanation() != null) {
5988 explanation.putCharSequence(key, record.getImportanceExplanation());
5989 }
Chris Wren333a61c2014-05-28 16:40:57 -04005990 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05005991 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005992
Christoph Studer05ad4822014-05-16 14:16:03 +02005993 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005994 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005995 if (record.getPackageVisibilityOverride()
5996 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05005997 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005998 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04005999 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05006000 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05006001 overridePeople.putStringArrayList(key, record.getPeopleOverride());
6002 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05006003 showBadge.putBoolean(key, record.canShowBadge());
Julia Reynolds503ed942017-10-04 16:04:56 -04006004 userSentiment.putInt(key, record.getUserSentiment());
Beverly5a20a5e2018-03-06 15:02:44 -05006005 hidden.putBoolean(key, record.isHidden());
Christoph Studer05ad4822014-05-16 14:16:03 +02006006 }
Chris Wrenbdf33762015-12-04 15:50:51 -05006007 final int M = keys.size();
6008 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02006009 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05006010 int[] importanceAr = new int[M];
6011 for (int i = 0; i < M; i++) {
6012 importanceAr[i] = importance.get(i);
6013 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006014 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05006015 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Beverly5a20a5e2018-03-06 15:02:44 -05006016 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden);
Christoph Studer05ad4822014-05-16 14:16:03 +02006017 }
6018
Julia Reynoldsda781472017-04-12 09:41:16 -04006019 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006020 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04006021 mCompanionManager = getCompanionManager();
6022 }
6023 // Companion mgr doesn't exist on all device types
6024 if (mCompanionManager == null) {
6025 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006026 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006027 long identity = Binder.clearCallingIdentity();
6028 try {
6029 List<String> associations = mCompanionManager.getAssociations(
6030 info.component.getPackageName(), info.userid);
6031 if (!ArrayUtils.isEmpty(associations)) {
6032 return true;
6033 }
6034 } catch (SecurityException se) {
6035 // Not a privileged listener
6036 } catch (RemoteException re) {
6037 Slog.e(TAG, "Cannot reach companion device service", re);
6038 } catch (Exception e) {
6039 Slog.e(TAG, "Cannot verify listener " + info, e);
6040 } finally {
6041 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006042 }
Julia Reynoldsda781472017-04-12 09:41:16 -04006043 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006044 }
6045
Julia Reynolds727a7282017-04-13 10:54:01 -04006046 protected ICompanionDeviceManager getCompanionManager() {
6047 return ICompanionDeviceManager.Stub.asInterface(
6048 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
6049 }
6050
Christoph Studercef37cf2014-07-25 14:18:17 +02006051 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
6052 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
6053 return false;
6054 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07006055 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02006056 return true;
6057 }
6058
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00006059 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Beverly2be7a052018-03-27 11:37:58 -04006060 final long identity = Binder.clearCallingIdentity();
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006061 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006062 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05006063 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006064 } catch (RemoteException re) {
6065 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00006066 } catch (IllegalArgumentException ex) {
6067 // Package not found.
6068 return false;
Beverly2be7a052018-03-27 11:37:58 -04006069 } finally {
6070 Binder.restoreCallingIdentity(identity);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006071 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00006072 }
6073
Julia Reynoldse1816412017-10-24 10:39:11 -04006074 private boolean canUseManagedServices() {
6075 return !mActivityManager.isLowRamDevice()
6076 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
6077 }
6078
Chris Wren47633422016-01-22 09:56:59 -05006079 private class TrimCache {
6080 StatusBarNotification heavy;
6081 StatusBarNotification sbnClone;
6082 StatusBarNotification sbnCloneLight;
6083
6084 TrimCache(StatusBarNotification sbn) {
6085 heavy = sbn;
6086 }
6087
6088 StatusBarNotification ForListener(ManagedServiceInfo info) {
6089 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
6090 if (sbnCloneLight == null) {
6091 sbnCloneLight = heavy.cloneLight();
6092 }
6093 return sbnCloneLight;
6094 } else {
6095 if (sbnClone == null) {
6096 sbnClone = heavy.clone();
6097 }
6098 return sbnClone;
6099 }
6100 }
6101 }
6102
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006103 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006104 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05006105
Julia Reynolds7380d872018-01-12 10:28:26 -05006106 public NotificationAssistants(Context context, Object lock, UserProfiles up,
6107 IPackageManager pm) {
6108 super(context, lock, up, pm);
Chris Wren51017d02015-12-15 15:34:46 -05006109 }
6110
6111 @Override
6112 protected Config getConfig() {
6113 Config c = new Config();
Julia Reynolds503ed942017-10-04 16:04:56 -04006114 c.caption = "notification assistant";
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006115 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006116 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006117 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
6118 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05006119 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006120 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05006121 return c;
6122 }
6123
6124 @Override
6125 protected IInterface asInterface(IBinder binder) {
6126 return INotificationListener.Stub.asInterface(binder);
6127 }
6128
6129 @Override
6130 protected boolean checkType(IInterface service) {
6131 return service instanceof INotificationListener;
6132 }
6133
6134 @Override
6135 protected void onServiceAdded(ManagedServiceInfo info) {
6136 mListeners.registerGuestService(info);
6137 }
6138
6139 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006140 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05006141 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
6142 mListeners.unregisterService(removed.service, removed.userid);
6143 }
Chris Wren47633422016-01-22 09:56:59 -05006144
Julia Reynoldsef934fd2018-02-01 14:39:17 -05006145 @Override
6146 public void onUserUnlocked(int user) {
6147 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
6148 rebindServices(true);
6149 }
6150
Chris Wren47633422016-01-22 09:56:59 -05006151 public void onNotificationEnqueued(final NotificationRecord r) {
6152 final StatusBarNotification sbn = r.sbn;
6153 TrimCache trimCache = new TrimCache(sbn);
6154
Chris Wren47633422016-01-22 09:56:59 -05006155 // There should be only one, but it's a list, so while we enforce
6156 // singularity elsewhere, we keep it general here, to avoid surprises.
Julia Reynolds00314d92017-04-14 10:01:24 -04006157 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
Chris Wren47633422016-01-22 09:56:59 -05006158 boolean sbnVisible = isVisibleToListener(sbn, info);
6159 if (!sbnVisible) {
6160 continue;
6161 }
6162
Chris Wren47633422016-01-22 09:56:59 -05006163 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05006164 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05006165 @Override
6166 public void run() {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006167 notifyEnqueued(info, sbnToPost);
Chris Wren47633422016-01-22 09:56:59 -05006168 }
6169 });
6170 }
6171 }
6172
6173 private void notifyEnqueued(final ManagedServiceInfo info,
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006174 final StatusBarNotification sbn) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006175 final INotificationListener assistant = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05006176 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6177 try {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05006178 assistant.onNotificationEnqueued(sbnHolder);
Chris Wren47633422016-01-22 09:56:59 -05006179 } catch (RemoteException ex) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05006180 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Chris Wren47633422016-01-22 09:56:59 -05006181 }
6182 }
6183
Julia Reynolds79672302017-01-12 08:30:16 -05006184 /**
6185 * asynchronously notify the assistant that a notification has been snoozed until a
6186 * context
6187 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006188 @GuardedBy("mNotificationLock")
Julia Reynolds79672302017-01-12 08:30:16 -05006189 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
6190 final String snoozeCriterionId) {
6191 TrimCache trimCache = new TrimCache(sbn);
Julia Reynolds00314d92017-04-14 10:01:24 -04006192 for (final ManagedServiceInfo info : getServices()) {
Julia Reynolds503ed942017-10-04 16:04:56 -04006193 boolean sbnVisible = isVisibleToListener(sbn, info);
6194 if (!sbnVisible) {
6195 continue;
6196 }
Julia Reynolds79672302017-01-12 08:30:16 -05006197 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
6198 mHandler.post(new Runnable() {
6199 @Override
6200 public void run() {
6201 final INotificationListener assistant =
6202 (INotificationListener) info.service;
6203 StatusBarNotificationHolder sbnHolder
6204 = new StatusBarNotificationHolder(sbnToPost);
6205 try {
6206 assistant.onNotificationSnoozedUntilContext(
6207 sbnHolder, snoozeCriterionId);
6208 } catch (RemoteException ex) {
6209 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
6210 }
6211 }
6212 });
6213 }
6214 }
6215
Chris Wren47633422016-01-22 09:56:59 -05006216 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04006217 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05006218 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006219
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04006220 protected void ensureAssistant() {
6221 final List<UserInfo> activeUsers = mUm.getUsers(true);
6222 for (UserInfo userInfo : activeUsers) {
6223 int userId = userInfo.getUserHandle().getIdentifier();
6224 if (getAllowedPackages(userId).isEmpty()) {
6225 Slog.d(TAG, "Approving default notification assistant for user " + userId);
6226 readDefaultAssistant(userId);
6227 }
Julia Reynolds7380d872018-01-12 10:28:26 -05006228 }
6229 }
Chris Wren51017d02015-12-15 15:34:46 -05006230 }
6231
John Spurlock7340fc82014-04-24 18:50:12 -04006232 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006233 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04006234
Christoph Studerb82bc782014-08-20 14:29:43 +02006235 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
6236
Julia Reynoldsb852e562017-06-06 16:14:18 -04006237 public NotificationListeners(IPackageManager pm) {
6238 super(getContext(), mNotificationLock, mUserProfiles, pm);
6239
John Spurlock7340fc82014-04-24 18:50:12 -04006240 }
6241
6242 @Override
6243 protected Config getConfig() {
6244 Config c = new Config();
6245 c.caption = "notification listener";
6246 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04006247 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04006248 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
6249 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
6250 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
6251 c.clientLabel = R.string.notification_listener_binding_label;
6252 return c;
6253 }
6254
6255 @Override
6256 protected IInterface asInterface(IBinder binder) {
6257 return INotificationListener.Stub.asInterface(binder);
6258 }
6259
6260 @Override
Chris Wren51017d02015-12-15 15:34:46 -05006261 protected boolean checkType(IInterface service) {
6262 return service instanceof INotificationListener;
6263 }
6264
6265 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04006266 public void onServiceAdded(ManagedServiceInfo info) {
6267 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04006268 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006269 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04006270 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006271 }
John Spurlock7340fc82014-04-24 18:50:12 -04006272 try {
Chris Wren333a61c2014-05-28 16:40:57 -04006273 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04006274 } catch (RemoteException e) {
6275 // we tried
6276 }
6277 }
6278
John Spurlock1fa865f2014-07-21 14:56:39 -04006279 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04006280 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04006281 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07006282 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006283 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01006284 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04006285 }
Christoph Studerb82bc782014-08-20 14:29:43 +02006286 mLightTrimListeners.remove(removed);
6287 }
6288
Julia Reynolds88860ce2017-06-01 16:55:49 -04006289 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02006290 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
6291 if (trim == TRIM_LIGHT) {
6292 mLightTrimListeners.add(info);
6293 } else {
6294 mLightTrimListeners.remove(info);
6295 }
6296 }
6297
6298 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
6299 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04006300 }
6301
John Spurlock7340fc82014-04-24 18:50:12 -04006302 /**
6303 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02006304 *
6305 * <p>
6306 * Also takes care of removing a notification that has been visible to a listener before,
6307 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04006308 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006309 @GuardedBy("mNotificationLock")
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006310 public void notifyPostedLocked(NotificationRecord r, StatusBarNotification oldSbn) {
Beverly5a20a5e2018-03-06 15:02:44 -05006311 notifyPostedLocked(r, oldSbn, true);
6312 }
6313
6314 /**
6315 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
6316 * targetting <= O_MR1
6317 */
6318 @GuardedBy("mNotificationLock")
6319 private void notifyPostedLocked(NotificationRecord r, StatusBarNotification oldSbn,
6320 boolean notifyAllListeners) {
Christoph Studerb82bc782014-08-20 14:29:43 +02006321 // Lazily initialized snapshots of the notification.
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006322 StatusBarNotification sbn = r.sbn;
Chris Wren47633422016-01-22 09:56:59 -05006323 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02006324
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006325 Set<Uri> uris = r.getNotificationUris();
6326
Julia Reynolds00314d92017-04-14 10:01:24 -04006327 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02006328 boolean sbnVisible = isVisibleToListener(sbn, info);
6329 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
6330 // This notification hasn't been and still isn't visible -> ignore.
6331 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006332 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04006333 }
Beverly5a20a5e2018-03-06 15:02:44 -05006334
6335 // If the notification is hidden, don't notifyPosted listeners targeting < P.
6336 // Instead, those listeners will receive notifyPosted when the notification is
6337 // unhidden.
6338 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
6339 continue;
6340 }
6341
6342 // If we shouldn't notify all listeners, this means the hidden state of
6343 // a notification was changed. Don't notifyPosted listeners targeting >= P.
6344 // Instead, those listeners will receive notifyRankingUpdate.
6345 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6346 continue;
6347 }
6348
Chris Wren333a61c2014-05-28 16:40:57 -04006349 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02006350
6351 // This notification became invisible -> remove the old one.
6352 if (oldSbnVisible && !sbnVisible) {
6353 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
6354 mHandler.post(new Runnable() {
6355 @Override
6356 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04006357 notifyRemoved(
6358 info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02006359 }
6360 });
Christoph Studer05ad4822014-05-16 14:16:03 +02006361 continue;
6362 }
Christoph Studercef37cf2014-07-25 14:18:17 +02006363
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006364 grantUriPermissions(uris, sbn.getUserId(), info.component.getPackageName(),
6365 info.userid);
6366
Chris Wren47633422016-01-22 09:56:59 -05006367 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006368 mHandler.post(new Runnable() {
6369 @Override
6370 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02006371 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02006372 }
6373 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006374 }
6375 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006376
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006377 private void grantUriPermissions(Set<Uri> uris, int notiUserId, String listenerPkg,
6378 int listenerUserId) {
6379 long ident = Binder.clearCallingIdentity();
6380 try {
6381 for (Uri uri : uris) {
6382 if (uri != null) {
6383 int sourceUserId = notiUserId == USER_ALL ? USER_SYSTEM
6384 : ContentProvider.getUserIdFromUri(uri, notiUserId);
6385 uri = ContentProvider.getUriWithoutUserId(uri);
6386 mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(),
6387 listenerPkg,
6388 uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId,
6389 listenerUserId == USER_ALL ? USER_SYSTEM : listenerUserId);
6390 }
6391 }
6392 } catch (RemoteException e) {
6393 Log.e(TAG, "Count not grant uri permission to " + listenerPkg, e);
6394 } finally {
6395 Binder.restoreCallingIdentity(ident);
6396 }
6397 }
6398
John Spurlock7340fc82014-04-24 18:50:12 -04006399 /**
6400 * asynchronously notify all listeners about a removed notification
6401 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006402 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05006403 public void notifyRemovedLocked(NotificationRecord r, int reason,
Julia Reynolds503ed942017-10-04 16:04:56 -04006404 NotificationStats notificationStats) {
Beverly5a20a5e2018-03-06 15:02:44 -05006405 final StatusBarNotification sbn = r.sbn;
John Spurlock7340fc82014-04-24 18:50:12 -04006406 // make a copy in case changes are made to the underlying Notification object
6407 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
6408 // notification
6409 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04006410 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02006411 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006412 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04006413 }
Beverly5a20a5e2018-03-06 15:02:44 -05006414
6415 // don't notifyRemoved for listeners targeting < P
6416 // if not for reason package suspended
6417 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
6418 && info.targetSdkVersion < Build.VERSION_CODES.P) {
6419 continue;
6420 }
6421
6422 // don't notifyRemoved for listeners targeting >= P
6423 // if the reason is package suspended
6424 if (reason == REASON_PACKAGE_SUSPENDED
6425 && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6426 continue;
6427 }
6428
Julia Reynolds503ed942017-10-04 16:04:56 -04006429 // Only assistants can get stats
6430 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
6431 ? notificationStats : null;
Chris Wren333a61c2014-05-28 16:40:57 -04006432 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02006433 mHandler.post(new Runnable() {
6434 @Override
6435 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04006436 notifyRemoved(info, sbnLight, update, stats, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02006437 }
6438 });
Chris Wrenf9536642014-04-17 10:01:54 -04006439 }
6440 }
6441
6442 /**
Beverly5a20a5e2018-03-06 15:02:44 -05006443 * Asynchronously notify all listeners about a reordering of notifications
6444 * unless changedHiddenNotifications is populated.
6445 * If changedHiddenNotifications is populated, there was a change in the hidden state
6446 * of the notifications. In this case, we only send updates to listeners that
6447 * target >= P.
Chris Wrenf9536642014-04-17 10:01:54 -04006448 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006449 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05006450 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
6451 boolean isHiddenRankingUpdate = changedHiddenNotifications != null
6452 && changedHiddenNotifications.size() > 0;
6453
Julia Reynolds00314d92017-04-14 10:01:24 -04006454 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006455 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6456 continue;
6457 }
Beverly5a20a5e2018-03-06 15:02:44 -05006458
6459 boolean notifyThisListener = false;
6460 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
6461 Build.VERSION_CODES.P) {
6462 for (NotificationRecord rec : changedHiddenNotifications) {
6463 if (isVisibleToListener(rec.sbn, serviceInfo)) {
6464 notifyThisListener = true;
6465 break;
6466 }
John Spurlock7340fc82014-04-24 18:50:12 -04006467 }
Beverly5a20a5e2018-03-06 15:02:44 -05006468 }
6469
6470 if (notifyThisListener || !isHiddenRankingUpdate) {
6471 final NotificationRankingUpdate update = makeRankingUpdateLocked(
6472 serviceInfo);
6473
6474 mHandler.post(new Runnable() {
6475 @Override
6476 public void run() {
6477 notifyRankingUpdate(serviceInfo, update);
6478 }
6479 });
6480 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006481 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006482 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006483
Julia Reynolds88860ce2017-06-01 16:55:49 -04006484 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04006485 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006486 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04006487 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6488 continue;
6489 }
6490 mHandler.post(new Runnable() {
6491 @Override
6492 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006493 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006494 }
6495 });
6496 }
6497 }
6498
Beverly5a20a5e2018-03-06 15:02:44 -05006499 /**
6500 * asynchronously notify relevant listeners their notification is hidden
6501 * NotificationListenerServices that target P+:
6502 * NotificationListenerService#notifyRankingUpdateLocked()
6503 * NotificationListenerServices that target <= P:
6504 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
6505 */
6506 @GuardedBy("mNotificationLock")
6507 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
6508 if (changedNotifications == null || changedNotifications.size() == 0) {
6509 return;
6510 }
6511
6512 notifyRankingUpdateLocked(changedNotifications);
6513
6514 // for listeners that target < P, notifyRemoveLocked
6515 int numChangedNotifications = changedNotifications.size();
6516 for (int i = 0; i < numChangedNotifications; i++) {
6517 NotificationRecord rec = changedNotifications.get(i);
6518 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
6519 }
6520 }
6521
6522 /**
6523 * asynchronously notify relevant listeners their notification is unhidden
6524 * NotificationListenerServices that target P+:
6525 * NotificationListenerService#notifyRankingUpdateLocked()
6526 * NotificationListenerServices that target <= P:
6527 * NotificationListeners#notifyPostedLocked()
6528 */
6529 @GuardedBy("mNotificationLock")
6530 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
6531 if (changedNotifications == null || changedNotifications.size() == 0) {
6532 return;
6533 }
6534
6535 notifyRankingUpdateLocked(changedNotifications);
6536
6537 // for listeners that target < P, notifyPostedLocked
6538 int numChangedNotifications = changedNotifications.size();
6539 for (int i = 0; i < numChangedNotifications; i++) {
6540 NotificationRecord rec = changedNotifications.get(i);
6541 mListeners.notifyPostedLocked(rec, rec.sbn, false);
6542 }
6543 }
6544
Christoph Studer85a384b2014-08-27 20:16:15 +02006545 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006546 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02006547 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6548 continue;
6549 }
6550 mHandler.post(new Runnable() {
6551 @Override
6552 public void run() {
6553 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
6554 }
6555 });
6556 }
6557 }
6558
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006559 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006560 final NotificationChannel channel, final int modificationType) {
6561 if (channel == null) {
6562 return;
6563 }
6564 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04006565 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006566 continue;
6567 }
Julia Reynolds018aa622017-04-20 11:31:30 -04006568
Eugene Suslaa25d17f2017-08-24 11:28:08 -07006569 BackgroundThread.getHandler().post(() -> {
6570 if (hasCompanionDevice(serviceInfo)) {
6571 notifyNotificationChannelChanged(
6572 serviceInfo, pkg, user, channel, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04006573 }
6574 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006575 }
6576 }
6577
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006578 protected void notifyNotificationChannelGroupChanged(
6579 final String pkg, final UserHandle user, final NotificationChannelGroup group,
6580 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006581 if (group == null) {
6582 return;
6583 }
6584 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04006585 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006586 continue;
6587 }
Julia Reynolds018aa622017-04-20 11:31:30 -04006588
Eugene Suslaa25d17f2017-08-24 11:28:08 -07006589 BackgroundThread.getHandler().post(() -> {
6590 if (hasCompanionDevice(serviceInfo)) {
6591 notifyNotificationChannelGroupChanged(
6592 serviceInfo, pkg, user, group, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04006593 }
6594 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006595 }
6596 }
6597
Christoph Studercef37cf2014-07-25 14:18:17 +02006598 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02006599 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04006600 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006601 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04006602 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07006603 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04006604 } catch (RemoteException ex) {
6605 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
6606 }
6607 }
6608
Christoph Studercef37cf2014-07-25 14:18:17 +02006609 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds503ed942017-10-04 16:04:56 -04006610 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04006611 if (!info.enabledAndUserMatches(sbn.getUserId())) {
6612 return;
6613 }
Christoph Studer05ad4822014-05-16 14:16:03 +02006614 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006615 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04006616 try {
Julia Reynolds503ed942017-10-04 16:04:56 -04006617 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04006618 } catch (RemoteException ex) {
6619 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04006620 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006621 }
Chris Wrenf9536642014-04-17 10:01:54 -04006622
Christoph Studer05ad4822014-05-16 14:16:03 +02006623 private void notifyRankingUpdate(ManagedServiceInfo info,
6624 NotificationRankingUpdate rankingUpdate) {
6625 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04006626 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02006627 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04006628 } catch (RemoteException ex) {
6629 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
6630 }
6631 }
John Spurlock1fa865f2014-07-21 14:56:39 -04006632
John Spurlockd8afe3c2014-08-01 14:04:07 -04006633 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04006634 final INotificationListener listener = (INotificationListener) info.service;
6635 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006636 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006637 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006638 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04006639 }
6640 }
Justin Koh38156c52014-06-04 13:57:49 -07006641
Christoph Studer85a384b2014-08-27 20:16:15 +02006642 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
6643 int interruptionFilter) {
6644 final INotificationListener listener = (INotificationListener) info.service;
6645 try {
6646 listener.onInterruptionFilterChanged(interruptionFilter);
6647 } catch (RemoteException ex) {
6648 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
6649 }
6650 }
6651
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006652 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006653 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006654 final int modificationType) {
6655 final INotificationListener listener = (INotificationListener) info.service;
6656 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006657 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006658 } catch (RemoteException ex) {
6659 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
6660 }
6661 }
6662
6663 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006664 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006665 final int modificationType) {
6666 final INotificationListener listener = (INotificationListener) info.service;
6667 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006668 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006669 } catch (RemoteException ex) {
6670 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
6671 }
6672 }
6673
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006674 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07006675 if (packageName == null) {
6676 return false;
6677 }
6678 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006679 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006680 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07006681 if (packageName.equals(serviceInfo.component.getPackageName())) {
6682 return true;
6683 }
6684 }
6685 }
6686 return false;
6687 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006688 }
John Spurlock25e2d242014-06-27 13:58:23 -04006689
6690 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04006691 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04006692 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04006693 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04006694 public long since;
6695 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04006696 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05006697 public boolean proto = false;
Vishnu Naire3e4d252018-03-01 11:26:57 -08006698 public boolean criticalPriority = false;
6699 public boolean normalPriority = false;
John Spurlock25e2d242014-06-27 13:58:23 -04006700
Kweku Adams887f09c2017-11-13 17:12:20 -08006701 @NonNull
John Spurlock25e2d242014-06-27 13:58:23 -04006702 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04006703 final DumpFilter filter = new DumpFilter();
6704 for (int ai = 0; ai < args.length; ai++) {
6705 final String a = args[ai];
Kweku Adams62b42242017-09-25 12:54:02 -07006706 if ("--proto".equals(a)) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05006707 filter.proto = true;
Kweku Adams62b42242017-09-25 12:54:02 -07006708 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
Dan Sandlera1770312015-07-10 13:59:29 -04006709 filter.redact = false;
6710 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
6711 if (ai < args.length-1) {
6712 ai++;
6713 filter.pkgFilter = args[ai].trim().toLowerCase();
6714 if (filter.pkgFilter.isEmpty()) {
6715 filter.pkgFilter = null;
6716 } else {
6717 filter.filtered = true;
6718 }
6719 }
6720 } else if ("--zen".equals(a) || "zen".equals(a)) {
6721 filter.filtered = true;
6722 filter.zen = true;
6723 } else if ("--stats".equals(a)) {
6724 filter.stats = true;
6725 if (ai < args.length-1) {
6726 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01006727 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04006728 } else {
6729 filter.since = 0;
6730 }
Vishnu Naire3e4d252018-03-01 11:26:57 -08006731 } else if (PRIORITY_ARG.equals(a)) {
6732 // Bugreport will call the service twice with priority arguments, first to dump
6733 // critical sections and then non critical ones. Set approriate filters
6734 // to generate the desired data.
6735 if (ai < args.length - 1) {
6736 ai++;
6737 switch (args[ai]) {
6738 case PRIORITY_ARG_CRITICAL:
6739 filter.criticalPriority = true;
6740 break;
6741 case PRIORITY_ARG_NORMAL:
6742 filter.normalPriority = true;
6743 break;
6744 }
6745 }
Dan Sandlera1770312015-07-10 13:59:29 -04006746 }
John Spurlock25e2d242014-06-27 13:58:23 -04006747 }
Dan Sandlera1770312015-07-10 13:59:29 -04006748 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04006749 }
6750
6751 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04006752 if (!filtered) return true;
6753 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04006754 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04006755 }
6756
6757 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04006758 if (!filtered) return true;
6759 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04006760 }
6761
6762 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04006763 if (!filtered) return true;
6764 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04006765 }
6766
6767 @Override
6768 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04006769 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04006770 }
6771 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07006772
Beverly5a20a5e2018-03-06 15:02:44 -05006773 @VisibleForTesting
6774 protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
6775 // only use for testing: mimic receive broadcast that package is (un)suspended
6776 // but does not actually (un)suspend the package
6777 final Bundle extras = new Bundle();
6778 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
6779 new String[]{pkg});
6780
6781 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
6782 : Intent.ACTION_PACKAGES_UNSUSPENDED;
6783 final Intent intent = new Intent(action);
6784 intent.putExtras(extras);
6785
6786 mPackageIntentReceiver.onReceive(getContext(), intent);
6787 }
6788
Griff Hazen84a00ea2014-09-02 17:10:47 -07006789 /**
6790 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
6791 * binder without sending large amounts of data over a oneway transaction.
6792 */
6793 private static final class StatusBarNotificationHolder
6794 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07006795 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006796
6797 public StatusBarNotificationHolder(StatusBarNotification value) {
6798 mValue = value;
6799 }
6800
Griff Hazene9aac5f2014-09-05 20:04:09 -07006801 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07006802 @Override
6803 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07006804 StatusBarNotification value = mValue;
6805 mValue = null;
6806 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006807 }
6808 }
John Spurlock7c74f782015-06-04 13:01:42 -04006809
Julia Reynoldsb852e562017-06-06 16:14:18 -04006810 private class ShellCmd extends ShellCommand {
6811 public static final String USAGE = "help\n"
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09006812 + "allow_listener COMPONENT [user_id]\n"
6813 + "disallow_listener COMPONENT [user_id]\n"
Julia Reynolds7380d872018-01-12 10:28:26 -05006814 + "allow_assistant COMPONENT\n"
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006815 + "remove_assistant COMPONENT\n"
Julia Reynoldsb852e562017-06-06 16:14:18 -04006816 + "allow_dnd PACKAGE\n"
Beverly5a20a5e2018-03-06 15:02:44 -05006817 + "disallow_dnd PACKAGE\n"
6818 + "suspend_package PACKAGE\n"
6819 + "unsuspend_package PACKAGE";
John Spurlock7c74f782015-06-04 13:01:42 -04006820
Julia Reynoldsb852e562017-06-06 16:14:18 -04006821 @Override
6822 public int onCommand(String cmd) {
Felipe Leme68d80412017-07-14 11:18:08 -07006823 if (cmd == null) {
6824 return handleDefaultCommands(cmd);
6825 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006826 final PrintWriter pw = getOutPrintWriter();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04006827 try {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006828 switch (cmd) {
6829 case "allow_dnd": {
6830 getBinderService().setNotificationPolicyAccessGranted(
6831 getNextArgRequired(), true);
John Spurlock7c74f782015-06-04 13:01:42 -04006832 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04006833 break;
6834
6835 case "disallow_dnd": {
6836 getBinderService().setNotificationPolicyAccessGranted(
6837 getNextArgRequired(), false);
6838 }
6839 break;
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006840 case "allow_listener": {
6841 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6842 if (cn == null) {
6843 pw.println("Invalid listener - must be a ComponentName");
6844 return -1;
6845 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09006846 String userId = getNextArg();
6847 if (userId == null) {
6848 getBinderService().setNotificationListenerAccessGranted(cn, true);
6849 } else {
6850 getBinderService().setNotificationListenerAccessGrantedForUser(
6851 cn, Integer.parseInt(userId), true);
6852 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006853 }
6854 break;
6855 case "disallow_listener": {
6856 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6857 if (cn == null) {
6858 pw.println("Invalid listener - must be a ComponentName");
6859 return -1;
6860 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09006861 String userId = getNextArg();
6862 if (userId == null) {
6863 getBinderService().setNotificationListenerAccessGranted(cn, false);
6864 } else {
6865 getBinderService().setNotificationListenerAccessGrantedForUser(
6866 cn, Integer.parseInt(userId), false);
6867 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006868 }
6869 break;
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006870 case "allow_assistant": {
6871 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6872 if (cn == null) {
6873 pw.println("Invalid assistant - must be a ComponentName");
6874 return -1;
6875 }
6876 getBinderService().setNotificationAssistantAccessGranted(cn, true);
6877 }
6878 break;
6879 case "disallow_assistant": {
6880 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6881 if (cn == null) {
6882 pw.println("Invalid assistant - must be a ComponentName");
6883 return -1;
6884 }
6885 getBinderService().setNotificationAssistantAccessGranted(cn, false);
6886 }
6887 break;
Beverly5a20a5e2018-03-06 15:02:44 -05006888 case "suspend_package": {
6889 // only use for testing
6890 simulatePackageSuspendBroadcast(true, getNextArgRequired());
6891 }
6892 break;
6893 case "unsuspend_package": {
6894 // only use for testing
6895 simulatePackageSuspendBroadcast(false, getNextArgRequired());
6896 }
6897 break;
Julia Reynoldsb852e562017-06-06 16:14:18 -04006898 default:
6899 return handleDefaultCommands(cmd);
John Spurlock7c74f782015-06-04 13:01:42 -04006900 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006901 } catch (Exception e) {
6902 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
Julia Reynoldsb852e562017-06-06 16:14:18 -04006903 Slog.e(TAG, "Error running shell command", e);
John Spurlock7c74f782015-06-04 13:01:42 -04006904 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04006905 return 0;
John Spurlock7c74f782015-06-04 13:01:42 -04006906 }
6907
Julia Reynoldsb852e562017-06-06 16:14:18 -04006908 @Override
6909 public void onHelp() {
6910 getOutPrintWriter().println(USAGE);
John Spurlock7c74f782015-06-04 13:01:42 -04006911 }
6912 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006913}