blob: ef1f4e0afeded26f9c801fa2942ce9d0b72f8314 [file] [log] [blame]
Gus Prevaseb4e2e12018-12-28 14:57:59 -05001/*
2 * Copyright (C) 2018 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
17package com.android.systemui;
18
19import android.app.Notification;
20import android.app.NotificationManager;
21import android.content.Context;
22import android.os.Bundle;
23import android.service.notification.StatusBarNotification;
Beverly201cdd52019-10-18 14:30:46 -040024import android.util.ArraySet;
Gus Prevaseb4e2e12018-12-28 14:57:59 -050025import android.util.Log;
26
27import com.android.internal.statusbar.NotificationVisibility;
Gus Prevaseb4e2e12018-12-28 14:57:59 -050028import com.android.systemui.statusbar.notification.NotificationEntryListener;
29import com.android.systemui.statusbar.notification.NotificationEntryManager;
Ned Burns8172d3a2020-01-10 00:24:17 -050030import com.android.systemui.statusbar.notification.collection.NotifPipeline;
Ned Burnsf81c4c42019-01-07 14:10:43 -050031import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Ned Burns012048d2020-01-08 19:57:30 -050032import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
Evan Lairdccf5c5e2020-02-06 14:01:28 -050033import com.android.systemui.util.time.SystemClock;
Gus Prevaseb4e2e12018-12-28 14:57:59 -050034
35import javax.inject.Inject;
36import javax.inject.Singleton;
37
38/** Updates foreground service notification state in response to notification data events. */
39@Singleton
40public class ForegroundServiceNotificationListener {
41
42 private static final String TAG = "FgServiceController";
43 private static final boolean DBG = false;
44
45 private final Context mContext;
46 private final ForegroundServiceController mForegroundServiceController;
Beverly201cdd52019-10-18 14:30:46 -040047 private final NotificationEntryManager mEntryManager;
Gus Prevaseb4e2e12018-12-28 14:57:59 -050048
49 @Inject
50 public ForegroundServiceNotificationListener(Context context,
51 ForegroundServiceController foregroundServiceController,
Beverly8c80e0c2019-12-03 11:25:39 -050052 NotificationEntryManager notificationEntryManager,
Evan Lairdccf5c5e2020-02-06 14:01:28 -050053 NotifPipeline notifPipeline,
54 SystemClock systemClock) {
Gus Prevaseb4e2e12018-12-28 14:57:59 -050055 mContext = context;
56 mForegroundServiceController = foregroundServiceController;
Beverlyc29b9692019-12-04 15:05:52 -050057
58 // TODO: (b/145659174) remove mEntryManager when moving to NewNotifPipeline. Replaced by
59 // ForegroundCoordinator
Beverly201cdd52019-10-18 14:30:46 -040060 mEntryManager = notificationEntryManager;
61 mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
Gus Prevaseb4e2e12018-12-28 14:57:59 -050062 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -050063 public void onPendingEntryAdded(NotificationEntry entry) {
Beverly201cdd52019-10-18 14:30:46 -040064 addNotification(entry, entry.getImportance());
Gus Prevaseb4e2e12018-12-28 14:57:59 -050065 }
66
67 @Override
Beverly201cdd52019-10-18 14:30:46 -040068 public void onPreEntryUpdated(NotificationEntry entry) {
69 updateNotification(entry, entry.getImportance());
Gus Prevaseb4e2e12018-12-28 14:57:59 -050070 }
71
72 @Override
73 public void onEntryRemoved(
Ned Burnsf81c4c42019-01-07 14:10:43 -050074 NotificationEntry entry,
Gus Prevaseb4e2e12018-12-28 14:57:59 -050075 NotificationVisibility visibility,
Julia Reynolds138111f2020-02-26 11:17:39 -050076 boolean removedByUser,
77 int reason) {
Ned Burns00b4b2d2019-10-17 22:09:27 -040078 removeNotification(entry.getSbn());
Gus Prevaseb4e2e12018-12-28 14:57:59 -050079 }
80 });
Evan Lairdccf5c5e2020-02-06 14:01:28 -050081 mEntryManager.addNotificationLifetimeExtender(
82 new ForegroundServiceLifetimeExtender(systemClock));
Beverly8c80e0c2019-12-03 11:25:39 -050083
Ned Burns8172d3a2020-01-10 00:24:17 -050084 notifPipeline.addCollectionListener(new NotifCollectionListener() {
Beverly8c80e0c2019-12-03 11:25:39 -050085 @Override
86 public void onEntryAdded(NotificationEntry entry) {
87 addNotification(entry, entry.getImportance());
88 }
89
90 @Override
91 public void onEntryUpdated(NotificationEntry entry) {
92 updateNotification(entry, entry.getImportance());
93 }
94
95 @Override
Ned Burns4258d702020-01-08 19:58:57 -050096 public void onEntryRemoved(NotificationEntry entry, int reason) {
Beverly8c80e0c2019-12-03 11:25:39 -050097 removeNotification(entry.getSbn());
98 }
99 });
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500100 }
101
102 /**
Beverly201cdd52019-10-18 14:30:46 -0400103 * @param entry notification that was just posted
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500104 */
Beverly201cdd52019-10-18 14:30:46 -0400105 private void addNotification(NotificationEntry entry, int importance) {
106 updateNotification(entry, importance);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500107 }
108
109 /**
110 * @param sbn notification that was just removed
111 */
112 private void removeNotification(StatusBarNotification sbn) {
113 mForegroundServiceController.updateUserState(
114 sbn.getUserId(),
115 new ForegroundServiceController.UserStateUpdateCallback() {
116 @Override
117 public boolean updateUserState(ForegroundServicesUserState userState) {
118 if (mForegroundServiceController.isDisclosureNotification(sbn)) {
119 // if you remove the dungeon entirely, we take that to mean there are
120 // no running services
121 userState.setRunningServices(null, 0);
122 return true;
123 } else {
124 // this is safe to call on any notification, not just
125 // FLAG_FOREGROUND_SERVICE
126 return userState.removeNotification(sbn.getPackageName(), sbn.getKey());
127 }
128 }
129
130 @Override
131 public void userStateNotFound(int userId) {
132 if (DBG) {
133 Log.w(TAG, String.format(
134 "user %d with no known notifications got removeNotification "
135 + "for %s",
136 sbn.getUserId(), sbn));
137 }
138 }
139 },
140 false /* don't create */);
141 }
142
143 /**
Beverly201cdd52019-10-18 14:30:46 -0400144 * @param entry notification that was just changed in some way
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500145 */
Beverly201cdd52019-10-18 14:30:46 -0400146 private void updateNotification(NotificationEntry entry, int newImportance) {
147 final StatusBarNotification sbn = entry.getSbn();
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500148 mForegroundServiceController.updateUserState(
149 sbn.getUserId(),
150 userState -> {
151 if (mForegroundServiceController.isDisclosureNotification(sbn)) {
152 final Bundle extras = sbn.getNotification().extras;
153 if (extras != null) {
154 final String[] svcs = extras.getStringArray(
155 Notification.EXTRA_FOREGROUND_APPS);
156 userState.setRunningServices(svcs, sbn.getNotification().when);
157 }
158 } else {
159 userState.removeNotification(sbn.getPackageName(), sbn.getKey());
160 if (0 != (sbn.getNotification().flags
161 & Notification.FLAG_FOREGROUND_SERVICE)) {
162 if (newImportance > NotificationManager.IMPORTANCE_MIN) {
163 userState.addImportantNotification(sbn.getPackageName(),
164 sbn.getKey());
165 }
166 final Notification.Builder builder =
167 Notification.Builder.recoverBuilder(
168 mContext, sbn.getNotification());
169 if (builder.usesStandardHeader()) {
170 userState.addStandardLayoutNotification(
171 sbn.getPackageName(), sbn.getKey());
172 }
173 }
174 }
Beverly201cdd52019-10-18 14:30:46 -0400175 tagForeground(entry);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500176 return true;
177 },
178 true /* create if not found */);
179 }
Beverly201cdd52019-10-18 14:30:46 -0400180
Beverlyc29b9692019-12-04 15:05:52 -0500181 // TODO: (b/145659174) remove when moving to NewNotifPipeline. Replaced by
182 // ForegroundCoordinator
Beverly201cdd52019-10-18 14:30:46 -0400183 private void tagForeground(NotificationEntry entry) {
184 final StatusBarNotification sbn = entry.getSbn();
185 ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps(
186 sbn.getUserId(),
187 sbn.getPackageName());
188 if (activeOps != null) {
189 synchronized (entry.mActiveAppOps) {
190 entry.mActiveAppOps.clear();
191 entry.mActiveAppOps.addAll(activeOps);
192 }
193 }
194 }
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500195}