1 /*
2  * Copyright (C) 2020 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.logging;
18 
19 import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
20 import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE;
21 import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_HEADS_UP;
22 import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
23 import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE;
24 import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PRIORITY_PEOPLE;
25 import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
26 
27 import android.annotation.Nullable;
28 import android.service.notification.StatusBarNotification;
29 
30 import com.android.internal.logging.UiEvent;
31 import com.android.internal.logging.UiEventLogger;
32 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
33 import com.android.systemui.statusbar.notification.logging.nano.Notifications;
34 import com.android.systemui.statusbar.notification.stack.PriorityBucket;
35 
36 import java.util.List;
37 
38 /**
39  * Statsd logging for notification panel.
40  */
41 public interface NotificationPanelLogger {
42 
43     /**
44      * Log a NOTIFICATION_PANEL_REPORTED statsd event.
45      */
logPanelShown(boolean isLockscreen, Notifications.NotificationList proto)46     void logPanelShown(boolean isLockscreen, Notifications.NotificationList proto);
47 
48     /**
49      * Log a NOTIFICATION_PANEL_REPORTED statsd event.
50      * @param visibleNotifications as provided by NotificationEntryManager.getVisibleNotifications()
51      */
logPanelShown(boolean isLockscreen, @Nullable List<NotificationEntry> visibleNotifications)52     void logPanelShown(boolean isLockscreen,
53             @Nullable List<NotificationEntry> visibleNotifications);
54 
55     /**
56      * Log a NOTIFICATION_PANEL_REPORTED statsd event, with
57      * {@link NotificationPanelEvent#NOTIFICATION_DRAG} as the eventID.
58      *
59      * @param draggedNotification the notification that is being dragged
60      */
logNotificationDrag(NotificationEntry draggedNotification)61     void logNotificationDrag(NotificationEntry draggedNotification);
62 
63     enum NotificationPanelEvent implements UiEventLogger.UiEventEnum {
64         @UiEvent(doc = "Notification panel shown from status bar.")
65         NOTIFICATION_PANEL_OPEN_STATUS_BAR(200),
66         @UiEvent(doc = "Notification panel shown from lockscreen.")
67         NOTIFICATION_PANEL_OPEN_LOCKSCREEN(201),
68         @UiEvent(doc = "Notification was dragged")
69         NOTIFICATION_DRAG(1226);
70 
71         private final int mId;
NotificationPanelEvent(int id)72         NotificationPanelEvent(int id) {
73             mId = id;
74         }
getId()75         @Override public int getId() {
76             return mId;
77         }
78 
fromLockscreen(boolean isLockscreen)79         public static NotificationPanelEvent fromLockscreen(boolean isLockscreen) {
80             return isLockscreen ? NOTIFICATION_PANEL_OPEN_LOCKSCREEN :
81                     NOTIFICATION_PANEL_OPEN_STATUS_BAR;
82         }
83     }
84 
85     /**
86      * Composes a NotificationsList proto from the list of visible notifications.
87      * @param visibleNotifications as provided by NotificationEntryManager.getVisibleNotifications()
88      * @return NotificationList proto suitable for SysUiStatsLog.write(NOTIFICATION_PANEL_REPORTED)
89      */
toNotificationProto( @ullable List<NotificationEntry> visibleNotifications)90     static Notifications.NotificationList toNotificationProto(
91             @Nullable List<NotificationEntry> visibleNotifications) {
92         Notifications.NotificationList notificationList = new Notifications.NotificationList();
93         if (visibleNotifications == null) {
94             return notificationList;
95         }
96         final Notifications.Notification[] proto_array =
97                 new Notifications.Notification[visibleNotifications.size()];
98         int i = 0;
99         for (NotificationEntry ne : visibleNotifications) {
100             final StatusBarNotification n = ne.getSbn();
101             if (n != null) {
102                 final Notifications.Notification proto = new Notifications.Notification();
103                 proto.uid = n.getUid();
104                 proto.packageName = n.getPackageName();
105                 if (n.getInstanceId() != null) {
106                     proto.instanceId = n.getInstanceId().getId();
107                 }
108                 // TODO set np.groupInstanceId
109                 if (n.getNotification() != null) {
110                     proto.isGroupSummary = n.getNotification().isGroupSummary();
111                 }
112                 proto.section = toNotificationSection(ne.getBucket());
113                 proto_array[i] = proto;
114             }
115             ++i;
116         }
117         notificationList.notifications = proto_array;
118         return notificationList;
119     }
120 
121     /**
122      * Maps PriorityBucket enum to Notification.SECTION constant. The two lists should generally
123      * use matching names, but the values may differ, because PriorityBucket order changes from
124      * time to time, while logs need to have stable meanings.
125      * @param bucket PriorityBucket constant
126      * @return Notification.SECTION constant
127      */
toNotificationSection(@riorityBucket int bucket)128     static int toNotificationSection(@PriorityBucket int bucket) {
129         switch(bucket) {
130             case BUCKET_MEDIA_CONTROLS : return Notifications.Notification.SECTION_MEDIA_CONTROLS;
131             case BUCKET_HEADS_UP: return Notifications.Notification.SECTION_HEADS_UP;
132             case BUCKET_FOREGROUND_SERVICE:
133                 return Notifications.Notification.SECTION_FOREGROUND_SERVICE;
134             case BUCKET_PEOPLE, BUCKET_PRIORITY_PEOPLE:
135                 return Notifications.Notification.SECTION_PEOPLE;
136             case BUCKET_ALERTING: return Notifications.Notification.SECTION_ALERTING;
137             case BUCKET_SILENT: return Notifications.Notification.SECTION_SILENT;
138         }
139         return Notifications.Notification.SECTION_UNKNOWN;
140     }
141 
142 }
143