• 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.systemui.dagger.SysUISingleton;
27 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
28 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
29 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
30 
31 import javax.inject.Inject;
32 
33 /** Updates foreground service notification state in response to notification data events. */
34 @SysUISingleton
35 public class ForegroundServiceNotificationListener {
36 
37     private static final String TAG = "FgServiceController";
38     private static final boolean DBG = false;
39 
40     private final Context mContext;
41     private final ForegroundServiceController mForegroundServiceController;
42     private final NotifPipeline mNotifPipeline;
43 
44     @Inject
ForegroundServiceNotificationListener(Context context, ForegroundServiceController foregroundServiceController, NotifPipeline notifPipeline)45     public ForegroundServiceNotificationListener(Context context,
46             ForegroundServiceController foregroundServiceController,
47             NotifPipeline notifPipeline) {
48         mContext = context;
49         mForegroundServiceController = foregroundServiceController;
50         mNotifPipeline = notifPipeline;
51     }
52 
53     /** Initializes this listener by connecting it to the notification pipeline. */
init()54     public void init() {
55         mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
56             @Override
57             public void onEntryAdded(NotificationEntry entry) {
58                 addNotification(entry, entry.getImportance());
59             }
60 
61             @Override
62             public void onEntryUpdated(NotificationEntry entry) {
63                 updateNotification(entry, entry.getImportance());
64             }
65 
66             @Override
67             public void onEntryRemoved(NotificationEntry entry, int reason) {
68                 removeNotification(entry.getSbn());
69             }
70         });
71     }
72 
73     /**
74      * @param entry notification that was just posted
75      */
addNotification(NotificationEntry entry, int importance)76     private void addNotification(NotificationEntry entry, int importance) {
77         updateNotification(entry, importance);
78     }
79 
80     /**
81      * @param sbn notification that was just removed
82      */
removeNotification(StatusBarNotification sbn)83     private void removeNotification(StatusBarNotification sbn) {
84         mForegroundServiceController.updateUserState(
85                 sbn.getUserId(),
86                 new ForegroundServiceController.UserStateUpdateCallback() {
87                     @Override
88                     public boolean updateUserState(ForegroundServicesUserState userState) {
89                         if (mForegroundServiceController.isDisclosureNotification(sbn)) {
90                             // if you remove the dungeon entirely, we take that to mean there are
91                             // no running services
92                             userState.setRunningServices(null, 0);
93                             return true;
94                         } else {
95                             // this is safe to call on any notification, not just
96                             // FLAG_FOREGROUND_SERVICE
97                             return userState.removeNotification(sbn.getPackageName(), sbn.getKey());
98                         }
99                     }
100 
101                     @Override
102                     public void userStateNotFound(int userId) {
103                         if (DBG) {
104                             Log.w(TAG, String.format(
105                                     "user %d with no known notifications got removeNotification "
106                                             + "for %s",
107                                     sbn.getUserId(), sbn));
108                         }
109                     }
110                 },
111                 false /* don't create */);
112     }
113 
114     /**
115      * @param entry notification that was just changed in some way
116      */
updateNotification(NotificationEntry entry, int newImportance)117     private void updateNotification(NotificationEntry entry, int newImportance) {
118         final StatusBarNotification sbn = entry.getSbn();
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                         }
138                         final Notification.Builder builder =
139                                 Notification.Builder.recoverBuilder(
140                                         mContext, sbn.getNotification());
141                         if (builder.usesStandardHeader()) {
142                             userState.addStandardLayoutNotification(
143                                     sbn.getPackageName(), sbn.getKey());
144                         }
145                     }
146                     return true;
147                 },
148                 true /* create if not found */);
149     }
150 }
151