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 package com.android.car.notification; 17 18 import android.service.notification.StatusBarNotification; 19 import android.util.Log; 20 21 import com.android.car.assist.client.CarAssistUtils; 22 23 import java.util.Collections; 24 import java.util.HashMap; 25 import java.util.HashSet; 26 import java.util.List; 27 import java.util.Map; 28 import java.util.Set; 29 30 /** 31 * Keeps track of the additional state of notifications. This class is not thread safe and should 32 * only be called from the main thread. 33 */ 34 public class NotificationDataManager { 35 private static String TAG = "NotificationDataManager"; 36 37 /** 38 * Map that contains the key of all message notifications, mapped to whether or not the key's 39 * notification should be muted. 40 * 41 * Muted notifications should show an "Unmute" button on their notification and should not 42 * trigger the HUN when new notifications arrive with the same key. Unmuted should show a "Mute" 43 * button on their notification and should trigger the HUN. Both should update the notification 44 * in the Notification Center. 45 */ 46 private final Map<String, Boolean> mMessageNotificationToMuteStateMap = new HashMap<>(); 47 48 /** 49 * Map that contains the key of all unseen notifications. 50 */ 51 private final Map<String, Boolean> mUnseenNotificationMap = new HashMap<>(); 52 53 private OnUnseenCountUpdateListener mOnUnseenCountUpdateListener; 54 55 /** 56 * Interface for listeners that want to register for receiving updates to the notification 57 * unseen count. 58 */ 59 public interface OnUnseenCountUpdateListener { 60 /** 61 * Called when unseen notification count is changed. 62 */ onUnseenCountUpdate()63 void onUnseenCountUpdate(); 64 } 65 NotificationDataManager()66 public NotificationDataManager() { 67 clearAll(); 68 } 69 70 /** 71 * Sets listener for unseen notification count change event. 72 * @param listener UnseenCountUpdateListener 73 */ setOnUnseenCountUpdateListener(OnUnseenCountUpdateListener listener)74 public void setOnUnseenCountUpdateListener(OnUnseenCountUpdateListener listener) { 75 mOnUnseenCountUpdateListener = listener; 76 } 77 addNewMessageNotification(StatusBarNotification notification)78 void addNewMessageNotification(StatusBarNotification notification) { 79 if (CarAssistUtils.isCarCompatibleMessagingNotification(notification)) { 80 mMessageNotificationToMuteStateMap 81 .putIfAbsent(notification.getKey(), /* muteState= */ 82 false); 83 84 if (mUnseenNotificationMap.containsKey(notification.getKey())) { 85 mUnseenNotificationMap.put(notification.getKey(), true); 86 87 if (mOnUnseenCountUpdateListener != null) { 88 mOnUnseenCountUpdateListener.onUnseenCountUpdate(); 89 } 90 } 91 } 92 } 93 untrackUnseenNotification(StatusBarNotification notification)94 void untrackUnseenNotification(StatusBarNotification notification) { 95 if (mUnseenNotificationMap.containsKey(notification.getKey())) { 96 mUnseenNotificationMap.remove(notification.getKey()); 97 if (mOnUnseenCountUpdateListener != null) { 98 mOnUnseenCountUpdateListener.onUnseenCountUpdate(); 99 } 100 } 101 } 102 updateUnseenNotification(List<NotificationGroup> notificationGroups)103 void updateUnseenNotification(List<NotificationGroup> notificationGroups) { 104 Set<String> currentNotificationKeys = new HashSet<>(); 105 106 Collections.addAll(currentNotificationKeys, 107 mUnseenNotificationMap.keySet().toArray(new String[0])); 108 109 for (NotificationGroup group : notificationGroups) { 110 for (StatusBarNotification sbn : group.getChildNotifications()) { 111 // add new notifications 112 mUnseenNotificationMap.putIfAbsent(sbn.getKey(), true); 113 114 // sbn exists in both sets. 115 currentNotificationKeys.remove(sbn.getKey()); 116 } 117 } 118 119 // These keys were removed from notificationGroups. Remove from mUnseenNotificationMap. 120 for (String notificationKey : currentNotificationKeys) { 121 mUnseenNotificationMap.remove(notificationKey); 122 } 123 124 if (mOnUnseenCountUpdateListener != null) { 125 mOnUnseenCountUpdateListener.onUnseenCountUpdate(); 126 } 127 } 128 129 /** 130 * Returns the mute state of the notification, or false if notification does not have a mute 131 * state. Only message notifications can be muted. 132 **/ isMessageNotificationMuted(StatusBarNotification notification)133 public boolean isMessageNotificationMuted(StatusBarNotification notification) { 134 if (!mMessageNotificationToMuteStateMap.containsKey(notification.getKey())) { 135 addNewMessageNotification(notification); 136 } 137 return mMessageNotificationToMuteStateMap.getOrDefault(notification.getKey(), false); 138 } 139 140 /** 141 * If {@param sbn} is a messaging notification, this function will toggle its mute state. This 142 * state determines whether or not a HUN will be shown on future updates to the notification. 143 * It also determines the title of the notification's "Mute" button. 144 **/ toggleMute(StatusBarNotification sbn)145 public void toggleMute(StatusBarNotification sbn) { 146 if (CarAssistUtils.isCarCompatibleMessagingNotification(sbn)) { 147 String sbnKey = sbn.getKey(); 148 Boolean currentMute = mMessageNotificationToMuteStateMap.get(sbnKey); 149 if (currentMute != null) { 150 mMessageNotificationToMuteStateMap.put(sbnKey, !currentMute); 151 } else { 152 Log.e(TAG, "Msg notification was not initially added to the mute state map: " 153 + sbn.getKey()); 154 } 155 } 156 } 157 158 /** 159 * Clear unseen and mute notification state information. 160 */ clearAll()161 public void clearAll() { 162 mMessageNotificationToMuteStateMap.clear(); 163 mUnseenNotificationMap.clear(); 164 165 if (mOnUnseenCountUpdateListener != null) { 166 mOnUnseenCountUpdateListener.onUnseenCountUpdate(); 167 } 168 } 169 setNotificationAsSeen(StatusBarNotification sbn)170 void setNotificationAsSeen(StatusBarNotification sbn) { 171 if (mUnseenNotificationMap.containsKey(sbn.getKey())) { 172 mUnseenNotificationMap.put(sbn.getKey(), false); 173 } 174 175 if (mOnUnseenCountUpdateListener != null) { 176 mOnUnseenCountUpdateListener.onUnseenCountUpdate(); 177 } 178 } 179 180 /** 181 * Returns unseen notification count. 182 */ getUnseenNotificationCount()183 public int getUnseenNotificationCount() { 184 int unseenCount = 0; 185 for (Boolean value : mUnseenNotificationMap.values()) { 186 if (value) { 187 unseenCount++; 188 } 189 } 190 return unseenCount; 191 } 192 } 193