1 package com.android.systemui.statusbar
2 
3 import android.app.Notification
4 import android.os.RemoteException
5 import android.util.Log
6 import com.android.internal.statusbar.IStatusBarService
7 import com.android.internal.statusbar.NotificationVisibility
8 import com.android.systemui.dagger.SysUISingleton
9 import com.android.systemui.dagger.qualifiers.Main
10 import com.android.systemui.dagger.qualifiers.UiBackground
11 import com.android.systemui.util.Assert
12 import java.util.concurrent.Executor
13 import javax.inject.Inject
14 
15 /**
16  * Class to shim calls to IStatusBarManager#onNotificationClick/#onNotificationActionClick that
17  * allow an in-process notification to go out (e.g., for tracking interactions) as well as
18  * sending the messages along to system server.
19  *
20  * NOTE: this class eats exceptions from system server, as no current client of these APIs cares
21  * about errors
22  */
23 @SysUISingleton
24 public class NotificationClickNotifier @Inject constructor(
25     val barService: IStatusBarService,
26     @Main val mainExecutor: Executor,
27     @UiBackground val backgroundExecutor: Executor
28 ) {
29     val listeners = mutableListOf<NotificationInteractionListener>()
30 
31     fun addNotificationInteractionListener(listener: NotificationInteractionListener) {
32         Assert.isMainThread()
33         listeners.add(listener)
34     }
35 
36     fun removeNotificationInteractionListener(listener: NotificationInteractionListener) {
37         Assert.isMainThread()
38         listeners.remove(listener)
39     }
40 
41     private fun notifyListenersAboutInteraction(key: String) {
42         for (l in listeners) {
43             l.onNotificationInteraction(key)
44         }
45     }
46 
47     fun onNotificationActionClick(
48         key: String,
49         actionIndex: Int,
50         action: Notification.Action,
51         visibility: NotificationVisibility,
52         generatedByAssistant: Boolean
53     ) {
54         backgroundExecutor.execute {
55             try {
56                 barService.onNotificationActionClick(
57                         key, actionIndex, action, visibility, generatedByAssistant)
58             } catch (e: RemoteException) {
59                 // nothing
60             }
61         }
62         mainExecutor.execute {
63             notifyListenersAboutInteraction(key)
64         }
65     }
66 
67     fun onNotificationClick(
68         key: String,
69         visibility: NotificationVisibility
70     ) {
71         try {
72             barService.onNotificationClick(key, visibility)
73         } catch (e: RemoteException) {
74             // nothing
75         }
76 
77         mainExecutor.execute {
78             notifyListenersAboutInteraction(key)
79         }
80     }
81 }
82 
83 /**
84  * Interface for listeners to get notified when a notification is interacted with via a click or
85  * interaction with remote input or actions
86  */
87 interface NotificationInteractionListener {
88     fun onNotificationInteraction(key: String)
89 }
90 
91 private const val TAG = "NotificationClickNotifier"
92