/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.statusbar.notification.stack import android.util.IndentingPrintWriter import com.android.systemui.statusbar.notification.stack.shared.model.AccessibilityScrollEvent import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrollState import com.android.systemui.util.printSection import com.android.systemui.util.println import java.util.function.Consumer /** * This is a state holder object used by [NSSL][NotificationStackScrollLayout] to contain states * provided by the `NotificationScrollViewBinder` to the `NotificationScrollView`. * * Unlike AmbientState, no class other than NSSL should ever have access to this class in any way. * These fields are effectively NSSL's private fields. */ class ScrollViewFields { /** Used to produce the clipping path */ @JvmField var clippingShape: ShadeScrimShape? = null /** Used to produce the negative clipping path */ @JvmField var negativeClippingShape: ShadeScrimShape? = null /** Scroll state of the notification shade. */ @JvmField var scrollState: ShadeScrollState = ShadeScrollState() /** * Height in view pixels at which the Notification Stack would like to be laid out, including * Notification rows, the Shelf, the Footer, or the EmptyView. */ @JvmField var intrinsicStackHeight: Int = 0 /** * Whether the NSSL is interactive for touch-handling. When false, neither NSSL or its * descendants handle touches. NSSL will dispatch TouchEvents to the scene container framework. * This is achieved by NSSL intercepting TouchEvents and returning false in onTouchEvent(). * * When mIsInteractive is false, NSSL and its child are not focusable or selectable by * accessibility. */ @JvmField var interactive = true /** * When internal NSSL expansion requires the stack to be scrolled (e.g. to keep an expanding * notification in view), that scroll amount can be sent here and it will be handled by the * placeholder. */ var syntheticScrollConsumer: Consumer? = null /** * When the NSSL navigates through the notifications with TalkBack, it can send scroll events * here, to be able to browse through the whole list of notifications in the shade. */ var accessibilityScrollEventConsumer: Consumer? = null /** * When a gesture is consumed internally by NSSL but needs to be handled by other elements (such * as the notif scrim), we can notify the placeholder through here. */ var currentGestureExpandingNotificationConsumer: Consumer? = null /** * When a gesture is on open notification guts, which means scene container should not close the * guts off of this gesture, we can notify the placeholder through here. */ var currentGestureInGutsConsumer: Consumer? = null /** * When a notification begins remote input, its bottom Y bound is sent to the placeholder * through here in order to adjust to accommodate the IME. */ var remoteInputRowBottomBoundConsumer: Consumer? = null /** send the [syntheticScroll] to the [syntheticScrollConsumer], if present. */ fun sendSyntheticScroll(syntheticScroll: Float) = syntheticScrollConsumer?.accept(syntheticScroll) /** send [isExpanding] to the [currentGestureExpandingNotificationConsumer], if present. */ fun sendCurrentGestureExpandingNotification(isExpanding: Boolean) = currentGestureExpandingNotificationConsumer?.accept(isExpanding) /** send [isCurrentGestureInGuts] to the [currentGestureInGutsConsumer], if present. */ fun sendCurrentGestureInGuts(isCurrentGestureInGuts: Boolean) = currentGestureInGutsConsumer?.accept(isCurrentGestureInGuts) /** send [bottomY] to the [remoteInputRowBottomBoundConsumer], if present. */ fun sendRemoteInputRowBottomBound(bottomY: Float?) = remoteInputRowBottomBoundConsumer?.accept(bottomY) /** send an [AccessibilityScrollEvent] to the [accessibilityScrollEventConsumer] if present */ fun sendAccessibilityScrollEvent(event: AccessibilityScrollEvent) { accessibilityScrollEventConsumer?.accept(event) } fun dump(pw: IndentingPrintWriter) { pw.printSection("StackViewStates") { pw.println("scrimClippingShape", clippingShape) pw.println("negativeClippingShape", negativeClippingShape) pw.println("scrollState", scrollState) pw.println("intrinsicStackHeight", intrinsicStackHeight) pw.println("interactive", interactive) } } }