1 package com.android.systemui.statusbar.policy
2 
3 import android.graphics.Region
4 import com.android.systemui.Dumpable
5 import com.android.systemui.dagger.SysUISingleton
6 import com.android.systemui.statusbar.notification.collection.NotificationEntry
7 import dagger.Binds
8 import dagger.Module
9 import java.io.PrintWriter
10 import java.util.stream.Stream
11 import javax.inject.Inject
12 
13 /**
14  * A manager which handles heads up notifications which is a special mode where they simply peek
15  * from the top of the screen.
16  */
17 interface HeadsUpManager : Dumpable {
18     /** The stream of all current notifications managed by this manager. */
19     val allEntries: Stream<NotificationEntry>
20 
21     /** Add a listener to receive callbacks onHeadsUpGoingAway. */
addHeadsUpPhoneListenernull22     fun addHeadsUpPhoneListener(listener: OnHeadsUpPhoneListenerChange)
23 
24     /** Adds an OnHeadUpChangedListener to observe events. */
25     fun addListener(listener: OnHeadsUpChangedListener)
26 
27     fun addSwipedOutNotification(key: String)
28 
29     /**
30      * Whether or not the alert can be removed currently. If it hasn't been on screen long enough it
31      * should not be removed unless forced
32      *
33      * @param key the key to check if removable
34      * @return true if the alert entry can be removed
35      */
36     fun canRemoveImmediately(key: String): Boolean
37 
38     /**
39      * Compare two entries and decide how they should be ranked.
40      *
41      * @return -1 if the first argument should be ranked higher than the second, 1 if the second one
42      *   should be ranked higher and 0 if they are equal.
43      */
44     fun compare(a: NotificationEntry?, b: NotificationEntry?): Int
45     /**
46      * Extends the lifetime of the currently showing pulsing notification so that the pulse lasts
47      * longer.
48      */
49     fun extendHeadsUp()
50 
51     /** Returns when a HUN entry should be removed in milliseconds from now. */
52     fun getEarliestRemovalTime(key: String?): Long
53 
54     /** Returns the top Heads Up Notification, which appears to show at first. */
55     fun getTopEntry(): NotificationEntry?
56 
57     /**
58      * Gets the touchable region needed for heads up notifications. Returns null if no touchable
59      * region is required (ie: no heads up notification currently exists).
60      */
61     fun getTouchableRegion(): Region?
62 
63     /**
64      * Whether or not there are any entries managed by HeadsUpManager.
65      *
66      * @return true if there is a heads up entry, false otherwise
67      */
68     fun hasNotifications(): Boolean = false
69 
70     /** Returns whether there are any pinned Heads Up Notifications or not. */
71     fun hasPinnedHeadsUp(): Boolean
72 
73     /** Returns whether or not the given notification is managed by this manager. */
74     fun isHeadsUpEntry(key: String): Boolean
75 
76     /** @see setHeadsUpAnimatingAway */
77     fun isHeadsUpAnimatingAwayValue(): Boolean
78 
79     /** Returns if the given notification is snoozed or not. */
80     fun isSnoozed(packageName: String): Boolean
81 
82     /** Returns whether the entry is (pinned and expanded) or (has an active remote input). */
83     fun isSticky(key: String?): Boolean
84 
85     fun isTrackingHeadsUp(): Boolean
86 
87     fun onExpandingFinished()
88 
89     /** Removes the OnHeadUpChangedListener from the observer list. */
90     fun removeListener(listener: OnHeadsUpChangedListener)
91 
92     /**
93      * Try to remove the notification. May not succeed if the notification has not been shown long
94      * enough and needs to be kept around.
95      *
96      * @param key the key of the notification to remove
97      * @param releaseImmediately force a remove regardless of earliest removal time
98      * @return true if notification is removed, false otherwise
99      */
100     fun removeNotification(key: String, releaseImmediately: Boolean): Boolean
101 
102     /**
103      * Try to remove the notification. May not succeed if the notification has not been shown long
104      * enough and needs to be kept around.
105      *
106      * @param key the key of the notification to remove
107      * @param releaseImmediately force a remove regardless of earliest removal time
108      * @param animate if true, animate the removal
109      * @return true if notification is removed, false otherwise
110      */
111     fun removeNotification(key: String, releaseImmediately: Boolean, animate: Boolean): Boolean
112 
113     /** Clears all managed notifications. */
114     fun releaseAllImmediately()
115 
116     fun setAnimationStateHandler(handler: AnimationStateHandler)
117 
118     /**
119      * Set an entry to be expanded and therefore stick in the heads up area if it's pinned until
120      * it's collapsed again.
121      */
122     fun setExpanded(entry: NotificationEntry, expanded: Boolean)
123 
124     /**
125      * Sets whether an entry's guts are exposed and therefore it should stick in the heads up area
126      * if it's pinned until it's hidden again.
127      */
128     fun setGutsShown(entry: NotificationEntry, gutsShown: Boolean)
129 
130     /**
131      * Set that we are exiting the headsUp pinned mode, but some notifications might still be
132      * animating out. This is used to keep the touchable regions in a reasonable state.
133      */
134     fun setHeadsUpAnimatingAway(headsUpAnimatingAway: Boolean)
135 
136     /**
137      * Notifies that a remote input textbox in notification gets active or inactive.
138      *
139      * @param entry The entry of the target notification.
140      * @param remoteInputActive True to notify active, False to notify inactive.
141      */
142     fun setRemoteInputActive(entry: NotificationEntry, remoteInputActive: Boolean)
143 
144     fun setTrackingHeadsUp(tracking: Boolean)
145 
146     /** Sets the current user. */
147     fun setUser(user: Int)
148 
149     /**
150      * Notes that the user took an action on an entry that might indirectly cause the system or the
151      * app to remove the notification.
152      *
153      * @param entry the entry that might be indirectly removed by the user's action
154      * @see
155      *   com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator.mActionPressListener
156      * @see .canRemoveImmediately
157      */
158     fun setUserActionMayIndirectlyRemove(entry: NotificationEntry)
159 
160     /**
161      * Decides whether a click is invalid for a notification, i.e. it has not been shown long enough
162      * that a user might have consciously clicked on it.
163      *
164      * @param key the key of the touched notification
165      * @return whether the touch is invalid and should be discarded
166      */
167     fun shouldSwallowClick(key: String): Boolean
168 
169     /**
170      * Called when posting a new notification that should alert the user and appear on screen. Adds
171      * the notification to be managed.
172      *
173      * @param entry entry to show
174      */
175     fun showNotification(entry: NotificationEntry)
176 
177     fun snooze()
178 
179     /**
180      * Unpins all pinned Heads Up Notifications.
181      *
182      * @param userUnPinned The unpinned action is trigger by user real operation.
183      */
184     fun unpinAll(userUnPinned: Boolean)
185 
186     fun updateNotification(key: String, shouldHeadsUpAgain: Boolean)
187 }
188 
189 /** Sets the animation state of the HeadsUpManager. */
190 interface AnimationStateHandler {
191     fun setHeadsUpGoingAwayAnimationsAllowed(allowed: Boolean)
192 }
193 
194 /** Listener to register for HeadsUpNotification Phone changes. */
195 interface OnHeadsUpPhoneListenerChange {
196     /**
197      * Called when a heads up notification is 'going away' or no longer 'going away'. See
198      * [HeadsUpManager.setHeadsUpAnimatingAway].
199      */
200     // TODO(b/325936094) delete this callback, and listen to the flow instead
onHeadsUpAnimatingAwayStateChangednull201     fun onHeadsUpAnimatingAwayStateChanged(headsUpAnimatingAway: Boolean)
202 }
203 
204 /* No op impl of HeadsUpManager. */
205 class HeadsUpManagerEmptyImpl @Inject constructor() : HeadsUpManager {
206     override val allEntries = Stream.empty<NotificationEntry>()
207     override fun addHeadsUpPhoneListener(listener: OnHeadsUpPhoneListenerChange) {}
208     override fun addListener(listener: OnHeadsUpChangedListener) {}
209     override fun addSwipedOutNotification(key: String) {}
210     override fun canRemoveImmediately(key: String) = false
211     override fun compare(a: NotificationEntry?, b: NotificationEntry?) = 0
212     override fun dump(pw: PrintWriter, args: Array<out String>) {}
213     override fun extendHeadsUp() {}
214     override fun getEarliestRemovalTime(key: String?) = 0L
215     override fun getTouchableRegion(): Region? = null
216     override fun getTopEntry() = null
217     override fun hasPinnedHeadsUp() = false
218     override fun isHeadsUpEntry(key: String) = false
219     override fun isHeadsUpAnimatingAwayValue() = false
220     override fun isSnoozed(packageName: String) = false
221     override fun isSticky(key: String?) = false
222     override fun isTrackingHeadsUp() = false
223     override fun onExpandingFinished() {}
224     override fun releaseAllImmediately() {}
225     override fun removeListener(listener: OnHeadsUpChangedListener) {}
226     override fun removeNotification(key: String, releaseImmediately: Boolean) = false
227     override fun removeNotification(key: String, releaseImmediately: Boolean, animate: Boolean) =
228         false
229     override fun setAnimationStateHandler(handler: AnimationStateHandler) {}
230     override fun setExpanded(entry: NotificationEntry, expanded: Boolean) {}
231     override fun setGutsShown(entry: NotificationEntry, gutsShown: Boolean) {}
232     override fun setHeadsUpAnimatingAway(headsUpAnimatingAway: Boolean) {}
233     override fun setRemoteInputActive(entry: NotificationEntry, remoteInputActive: Boolean) {}
234     override fun setTrackingHeadsUp(tracking: Boolean) {}
235     override fun setUser(user: Int) {}
236     override fun setUserActionMayIndirectlyRemove(entry: NotificationEntry) {}
237     override fun shouldSwallowClick(key: String): Boolean = false
238     override fun showNotification(entry: NotificationEntry) {}
239     override fun snooze() {}
240     override fun unpinAll(userUnPinned: Boolean) {}
241     override fun updateNotification(key: String, alert: Boolean) {}
242 }
243 
244 @Module
245 interface HeadsUpEmptyImplModule {
bindsHeadsUpManagernull246     @Binds @SysUISingleton fun bindsHeadsUpManager(noOpHum: HeadsUpManagerEmptyImpl): HeadsUpManager
247 }
248