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.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, ) { /** * 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() .filter { it.isVisible } .toList() if (notificationParent != null && childrenContainer != null) { // We are inside a notification group 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?, )