1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
package com.android.systemui.statusbar.notification.stack
import androidx.core.view.children
import androidx.core.view.isVisible
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.notification.Roundable
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import javax.inject.Inject
/**
* Utility class that helps us find the targets of an animation, often used to find the notification
* ([Roundable]) above and below the current one (see [findRoundableTargets]).
*/
@SysUISingleton
class NotificationTargetsHelper
@Inject
constructor(
featureFlags: FeatureFlags,
) {
private val useRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)
/**
* This method looks for views that can be rounded (and implement [Roundable]) during a
* notification swipe.
*
* @return The [Roundable] targets above/below the [viewSwiped] (if available). The
* [RoundableTargets.before] and [RoundableTargets.after] parameters can be `null` if there is
* no above/below notification or the notification is not part of the same section.
*/
fun findRoundableTargets(
viewSwiped: ExpandableNotificationRow,
stackScrollLayout: NotificationStackScrollLayout,
sectionsManager: NotificationSectionsManager,
): RoundableTargets {
val viewBefore: Roundable?
val viewAfter: Roundable?
val notificationParent = viewSwiped.notificationParent
val childrenContainer = notificationParent?.childrenContainer
val visibleStackChildren =
stackScrollLayout.children
.filterIsInstance<ExpandableView>()
.filter { it.isVisible }
.toList()
if (notificationParent != null && childrenContainer != null) {
// We are inside a notification group
if (!useRoundnessSourceTypes) {
return RoundableTargets(null, null, null)
}
val visibleGroupChildren = childrenContainer.attachedChildren.filter { it.isVisible }
val indexOfParentSwipedView = visibleGroupChildren.indexOf(viewSwiped)
viewBefore =
visibleGroupChildren.getOrNull(indexOfParentSwipedView - 1)
?: childrenContainer.notificationHeaderWrapper
viewAfter =
visibleGroupChildren.getOrNull(indexOfParentSwipedView + 1)
?: visibleStackChildren.indexOf(notificationParent).let {
visibleStackChildren.getOrNull(it + 1)
}
} else {
// Assumption: we are inside the NotificationStackScrollLayout
val indexOfSwipedView = visibleStackChildren.indexOf(viewSwiped)
viewBefore =
visibleStackChildren.getOrNull(indexOfSwipedView - 1)?.takeIf {
!sectionsManager.beginsSection(viewSwiped, it)
}
viewAfter =
visibleStackChildren.getOrNull(indexOfSwipedView + 1)?.takeIf {
!sectionsManager.beginsSection(it, viewSwiped)
}
}
return RoundableTargets(
before = viewBefore,
swiped = viewSwiped,
after = viewAfter,
)
}
}
/**
* This object contains targets above/below the [swiped] (if available). The [before] and [after]
* parameters can be `null` if there is no above/below notification or the notification is not part
* of the same section.
*/
data class RoundableTargets(
val before: Roundable?,
val swiped: ExpandableNotificationRow?,
val after: Roundable?,
)
|