• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.car.notification;
18 
19 import android.os.RemoteException;
20 import android.util.ArraySet;
21 import android.util.Log;
22 
23 import com.android.car.notification.AlertEntry;
24 import com.android.car.notification.NotificationDataManager;
25 import com.android.internal.statusbar.IStatusBarService;
26 import com.android.internal.statusbar.NotificationVisibility;
27 import com.android.systemui.car.users.CarSystemUIUserUtil;
28 import com.android.systemui.dagger.SysUISingleton;
29 import com.android.systemui.dagger.qualifiers.UiBackground;
30 
31 import java.util.List;
32 import java.util.Set;
33 import java.util.concurrent.Executor;
34 
35 import javax.inject.Inject;
36 
37 /**
38  * Handles notification logging, in particular, logging which notifications are visible and which
39  * are not.
40  */
41 @SysUISingleton
42 public class NotificationVisibilityLogger {
43 
44     private static final String TAG = "NotificationVisibilityLogger";
45 
46     private final ArraySet<NotificationVisibility> mCurrentlyVisible = new ArraySet<>();
47     private final ArraySet<NotificationVisibility> mNewlyVisible = new ArraySet<>();
48     private final ArraySet<NotificationVisibility> mPreviouslyVisible = new ArraySet<>();
49     private final ArraySet<NotificationVisibility> mTmpCurrentlyVisible = new ArraySet<>();
50 
51     private final IStatusBarService mBarService;
52     private final Executor mUiBgExecutor;
53     private final NotificationDataManager mNotificationDataManager;
54 
55     private boolean mIsVisible;
56 
57     private final Runnable mVisibilityReporter = new Runnable() {
58 
59         @Override
60         public void run() {
61             if (mIsVisible) {
62                 List<AlertEntry> notifications =
63                         mNotificationDataManager.getVisibleNotifications();
64                 int count = notifications.size();
65                 for (AlertEntry alertEntry : notifications) {
66                     NotificationVisibility visObj = NotificationVisibility.obtain(
67                             alertEntry.getKey(),
68                             /* rank= */ -1,
69                             count,
70                             mIsVisible,
71                             NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA);
72                     mTmpCurrentlyVisible.add(visObj);
73                     if (!mCurrentlyVisible.contains(visObj)) {
74                         mNewlyVisible.add(visObj);
75                     }
76                 }
77             }
78             mPreviouslyVisible.addAll(mCurrentlyVisible);
79             mPreviouslyVisible.removeAll(mTmpCurrentlyVisible);
80             onNotificationVisibilityChanged(mNewlyVisible, mPreviouslyVisible);
81 
82             recycleAllVisibilityObjects(mCurrentlyVisible);
83             mCurrentlyVisible.addAll(mTmpCurrentlyVisible);
84 
85             recycleAllVisibilityObjects(mPreviouslyVisible);
86             recycleAllVisibilityObjects(mNewlyVisible);
87             recycleAllVisibilityObjects(mTmpCurrentlyVisible);
88         }
89     };
90 
91     @Inject
NotificationVisibilityLogger( @iBackground Executor uiBgExecutor, IStatusBarService barService, NotificationDataManager notificationDataManager)92     public NotificationVisibilityLogger(
93             @UiBackground Executor uiBgExecutor,
94             IStatusBarService barService,
95             NotificationDataManager notificationDataManager) {
96         mUiBgExecutor = uiBgExecutor;
97         mBarService = barService;
98         mNotificationDataManager = notificationDataManager;
99     }
100 
101     /** Triggers a visibility report update to be sent to StatusBarService. */
log(boolean isVisible)102     public void log(boolean isVisible) {
103         mIsVisible = isVisible;
104         mUiBgExecutor.execute(mVisibilityReporter);
105     }
106 
107     /** Stops logging, clearing all visibility objects. */
stop()108     public void stop() {
109         recycleAllVisibilityObjects(mCurrentlyVisible);
110     }
111 
112     /**
113      * Notify StatusBarService of change in notifications' visibility.
114      */
onNotificationVisibilityChanged( Set<NotificationVisibility> newlyVisible, Set<NotificationVisibility> noLongerVisible)115     private void onNotificationVisibilityChanged(
116             Set<NotificationVisibility> newlyVisible, Set<NotificationVisibility> noLongerVisible) {
117         if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
118             return;
119         }
120 
121         if (CarSystemUIUserUtil.isSecondaryMUMDSystemUI()) {
122             // TODO: b/341604160 - Supports visible background users properly.
123             Log.d(TAG, "Status bar manager is disabled for visible background users");
124             return;
125         }
126 
127         try {
128             mBarService.onNotificationVisibilityChanged(
129                     cloneVisibilitiesAsArr(newlyVisible), cloneVisibilitiesAsArr(noLongerVisible));
130         } catch (RemoteException e) {
131             // Won't fail unless the world has ended.
132             Log.e(TAG, "Failed to notify StatusBarService of notification visibility change");
133         }
134     }
135 
136     /**
137      * Clears array and recycles NotificationVisibility objects for reuse.
138      */
recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array)139     private static void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
140         for (int i = 0; i < array.size(); i++) {
141             array.valueAt(i).recycle();
142         }
143         array.clear();
144     }
145 
146     /**
147      * Converts Set of NotificationVisibility objects to primitive array.
148      */
cloneVisibilitiesAsArr(Set<NotificationVisibility> c)149     private static NotificationVisibility[] cloneVisibilitiesAsArr(Set<NotificationVisibility> c) {
150         NotificationVisibility[] array = new NotificationVisibility[c.size()];
151         int i = 0;
152         for (NotificationVisibility nv : c) {
153             if (nv != null) {
154                 array[i] = nv.clone();
155             }
156             i++;
157         }
158         return array;
159     }
160 }
161