• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.systemui;
18 
19 import android.app.Notification;
20 import android.app.NotificationManager;
21 import android.content.Context;
22 import android.os.Bundle;
23 import android.service.notification.StatusBarNotification;
24 import android.util.Log;
25 
26 import com.android.internal.statusbar.NotificationVisibility;
27 import com.android.systemui.statusbar.notification.NotificationEntryListener;
28 import com.android.systemui.statusbar.notification.NotificationEntryManager;
29 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
30 
31 import javax.inject.Inject;
32 import javax.inject.Singleton;
33 
34 /** Updates foreground service notification state in response to notification data events. */
35 @Singleton
36 public class ForegroundServiceNotificationListener {
37 
38     private static final String TAG = "FgServiceController";
39     private static final boolean DBG = false;
40 
41     private final Context mContext;
42     private final ForegroundServiceController mForegroundServiceController;
43 
44     @Inject
ForegroundServiceNotificationListener(Context context, ForegroundServiceController foregroundServiceController, NotificationEntryManager notificationEntryManager)45     public ForegroundServiceNotificationListener(Context context,
46             ForegroundServiceController foregroundServiceController,
47             NotificationEntryManager notificationEntryManager) {
48         mContext = context;
49         mForegroundServiceController = foregroundServiceController;
50         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
51             @Override
52             public void onPendingEntryAdded(NotificationEntry entry) {
53                 addNotification(entry.notification, entry.importance);
54             }
55 
56             @Override
57             public void onPostEntryUpdated(NotificationEntry entry) {
58                 updateNotification(entry.notification, entry.importance);
59             }
60 
61             @Override
62             public void onEntryRemoved(
63                     NotificationEntry entry,
64                     NotificationVisibility visibility,
65                     boolean removedByUser) {
66                 removeNotification(entry.notification);
67             }
68         });
69 
70         notificationEntryManager.addNotificationLifetimeExtender(
71                 new ForegroundServiceLifetimeExtender());
72     }
73 
74     /**
75      * @param sbn notification that was just posted
76      */
addNotification(StatusBarNotification sbn, int importance)77     private void addNotification(StatusBarNotification sbn, int importance) {
78         updateNotification(sbn, importance);
79     }
80 
81     /**
82      * @param sbn notification that was just removed
83      */
removeNotification(StatusBarNotification sbn)84     private void removeNotification(StatusBarNotification sbn) {
85         mForegroundServiceController.updateUserState(
86                 sbn.getUserId(),
87                 new ForegroundServiceController.UserStateUpdateCallback() {
88                     @Override
89                     public boolean updateUserState(ForegroundServicesUserState userState) {
90                         if (mForegroundServiceController.isDisclosureNotification(sbn)) {
91                             // if you remove the dungeon entirely, we take that to mean there are
92                             // no running services
93                             userState.setRunningServices(null, 0);
94                             return true;
95                         } else {
96                             // this is safe to call on any notification, not just
97                             // FLAG_FOREGROUND_SERVICE
98                             return userState.removeNotification(sbn.getPackageName(), sbn.getKey());
99                         }
100                     }
101 
102                     @Override
103                     public void userStateNotFound(int userId) {
104                         if (DBG) {
105                             Log.w(TAG, String.format(
106                                     "user %d with no known notifications got removeNotification "
107                                             + "for %s",
108                                     sbn.getUserId(), sbn));
109                         }
110                     }
111                 },
112                 false /* don't create */);
113     }
114 
115     /**
116      * @param sbn notification that was just changed in some way
117      */
updateNotification(StatusBarNotification sbn, int newImportance)118     private void updateNotification(StatusBarNotification sbn, int newImportance) {
119         mForegroundServiceController.updateUserState(
120                 sbn.getUserId(),
121                 userState -> {
122                     if (mForegroundServiceController.isDisclosureNotification(sbn)) {
123                         final Bundle extras = sbn.getNotification().extras;
124                         if (extras != null) {
125                             final String[] svcs = extras.getStringArray(
126                                     Notification.EXTRA_FOREGROUND_APPS);
127                             userState.setRunningServices(svcs, sbn.getNotification().when);
128                         }
129                     } else {
130                         userState.removeNotification(sbn.getPackageName(), sbn.getKey());
131                         if (0 != (sbn.getNotification().flags
132                                 & Notification.FLAG_FOREGROUND_SERVICE)) {
133                             if (newImportance > NotificationManager.IMPORTANCE_MIN) {
134                                 userState.addImportantNotification(sbn.getPackageName(),
135                                         sbn.getKey());
136                             }
137                             final Notification.Builder builder =
138                                     Notification.Builder.recoverBuilder(
139                                             mContext, sbn.getNotification());
140                             if (builder.usesStandardHeader()) {
141                                 userState.addStandardLayoutNotification(
142                                         sbn.getPackageName(), sbn.getKey());
143                             }
144                         }
145                     }
146                     return true;
147                 },
148                 true /* create if not found */);
149     }
150 }
151