1 /*
2  * Copyright (C) 2019 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.statusbar.notification;
18 
19 import static com.android.internal.util.Preconditions.checkNotNull;
20 
21 import android.os.UserHandle;
22 import android.service.notification.StatusBarNotification;
23 import android.util.ArraySet;
24 
25 import com.android.internal.statusbar.NotificationVisibility;
26 import com.android.systemui.ForegroundServiceController;
27 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
28 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
29 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
30 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
31 
32 /**
33  * Root controller for the list of notifications in the shade.
34  *
35  * TODO: Much of the code in NotificationPresenter should eventually move in here. It will proxy
36  * domain-specific behavior (ARC, etc) to subcontrollers.
37  */
38 public class NotificationListController {
39     private final NotificationEntryManager mEntryManager;
40     private final NotificationListContainer mListContainer;
41     private final ForegroundServiceController mForegroundServiceController;
42     private final DeviceProvisionedController mDeviceProvisionedController;
43 
NotificationListController( NotificationEntryManager entryManager, NotificationListContainer listContainer, ForegroundServiceController foregroundServiceController, DeviceProvisionedController deviceProvisionedController)44     public NotificationListController(
45             NotificationEntryManager entryManager,
46             NotificationListContainer listContainer,
47             ForegroundServiceController foregroundServiceController,
48             DeviceProvisionedController deviceProvisionedController) {
49         mEntryManager = checkNotNull(entryManager);
50         mListContainer = checkNotNull(listContainer);
51         mForegroundServiceController = checkNotNull(foregroundServiceController);
52         mDeviceProvisionedController = checkNotNull(deviceProvisionedController);
53     }
54 
55     /**
56      * Causes the controller to register listeners on its dependencies. This method must be called
57      * before the controller is ready to perform its duties.
58      */
bind()59     public void bind() {
60         mEntryManager.addNotificationEntryListener(mEntryListener);
61         mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
62     }
63 
64     @SuppressWarnings("FieldCanBeLocal")
65     private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
66         @Override
67         public void onEntryRemoved(
68                 NotificationEntry entry,
69                 NotificationVisibility visibility,
70                 boolean removedByUser) {
71             mListContainer.cleanUpViewStateForEntry(entry);
72         }
73 
74         @Override
75         public void onBeforeNotificationAdded(NotificationEntry entry) {
76             tagForeground(entry.notification);
77         }
78     };
79 
80     private final DeviceProvisionedListener mDeviceProvisionedListener =
81             new DeviceProvisionedListener() {
82                 @Override
83                 public void onDeviceProvisionedChanged() {
84                     mEntryManager.updateNotifications();
85                 }
86             };
87 
88     // TODO: This method is horrifically inefficient
tagForeground(StatusBarNotification notification)89     private void tagForeground(StatusBarNotification notification) {
90         ArraySet<Integer> activeOps =
91                 mForegroundServiceController.getAppOps(
92                         notification.getUserId(), notification.getPackageName());
93         if (activeOps != null) {
94             int len = activeOps.size();
95             for (int i = 0; i < len; i++) {
96                 updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(),
97                         notification.getPackageName(), true);
98             }
99         }
100     }
101 
102     /** When an app op changes, propagate that change to notifications. */
updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon)103     public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) {
104         String foregroundKey =
105                 mForegroundServiceController.getStandardLayoutKey(UserHandle.getUserId(uid), pkg);
106         if (foregroundKey != null) {
107             mEntryManager
108                     .getNotificationData().updateAppOp(appOp, uid, pkg, foregroundKey, showIcon);
109             mEntryManager.updateNotifications();
110         }
111     }
112 }
113