Loading packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt +34 −25 Original line number Diff line number Diff line Loading @@ -19,10 +19,13 @@ package com.android.systemui.volume.panel.component.anc.ui.composable import android.view.Gravity import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.ButtonColors import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable Loading @@ -32,15 +35,15 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.LiveRegionMode import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.liveRegion import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle Loading @@ -66,13 +69,6 @@ constructor( with(LocalDensity.current) { LocalConfiguration.current.screenWidthDp.dp.toPx() } var gravity by remember { mutableIntStateOf(Gravity.CENTER_HORIZONTAL) } val isClickable = viewModel.isClickable(slice) val onClick = if (isClickable) { { with(ancPopup) { show(null, gravity) } } } else { null } Column( modifier = modifier.onGloballyPositioned { Loading @@ -80,21 +76,34 @@ constructor( }, verticalArrangement = Arrangement.spacedBy(12.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { Box( modifier = Modifier.height(64.dp), ) { SliceAndroidView( modifier = Modifier.height(64.dp) .fillMaxWidth() .semantics { role = Role.Button contentDescription = label } .clip(RoundedCornerShape(28.dp)), modifier = modifier.fillMaxSize(), slice = slice, isEnabled = onClick != null, onWidthChanged = viewModel::onButtonSliceWidthChanged, onClick = onClick, enableAccessibility = false, ) Button( modifier = modifier.fillMaxSize().padding(8.dp).semantics { liveRegion = LiveRegionMode.Polite contentDescription = label }, enabled = isClickable, onClick = { with(ancPopup) { show(null, gravity) } }, colors = ButtonColors( contentColor = Color.Transparent, containerColor = Color.Transparent, disabledContentColor = Color.Transparent, disabledContainerColor = Color.Transparent, ) ) {} } Text( modifier = Modifier.clearAndSetSemantics {}.basicMarquee(), text = label, Loading packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt +41 −27 Original line number Diff line number Diff line Loading @@ -16,11 +16,12 @@ package com.android.systemui.volume.panel.component.anc.ui.composable import android.annotation.SuppressLint import android.content.Context import android.os.Bundle import android.view.ContextThemeWrapper import android.view.MotionEvent import android.view.View import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityNodeInfo import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.viewinterop.AndroidView Loading @@ -32,14 +33,13 @@ import com.android.systemui.res.R fun SliceAndroidView( slice: Slice?, modifier: Modifier = Modifier, isEnabled: Boolean = true, onWidthChanged: ((Int) -> Unit)? = null, onClick: (() -> Unit)? = null, enableAccessibility: Boolean = true, ) { AndroidView( modifier = modifier, factory = { context: Context -> ClickableSliceView( ComposeSliceView( ContextThemeWrapper(context, R.style.Widget_SliceView_VolumePanel), ) .apply { Loading @@ -47,17 +47,18 @@ fun SliceAndroidView( isScrollable = false importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO setShowTitleItems(true) if (onWidthChanged != null) { addOnLayoutChangeListener(OnWidthChangedLayoutListener(onWidthChanged)) } } }, update = { sliceView: ClickableSliceView -> update = { sliceView: ComposeSliceView -> sliceView.slice = slice sliceView.onClick = onClick sliceView.isEnabled = isEnabled sliceView.isClickable = isEnabled } sliceView.layoutListener = onWidthChanged?.let(::OnWidthChangedLayoutListener) sliceView.enableAccessibility = enableAccessibility }, onRelease = { sliceView: ComposeSliceView -> sliceView.layoutListener = null sliceView.slice = null sliceView.enableAccessibility = true }, ) } Loading @@ -83,26 +84,39 @@ class OnWidthChangedLayoutListener(private val widthChanged: (Int) -> Unit) : } } /** * [SliceView] that prioritises [onClick] when its clicked instead of passing the event to the slice * first. */ @SuppressLint("ViewConstructor") // only used in this class private class ClickableSliceView(context: Context) : SliceView(context) { private class ComposeSliceView(context: Context) : SliceView(context) { var onClick: (() -> Unit)? = null var enableAccessibility: Boolean = true var layoutListener: OnLayoutChangeListener? = null set(value) { field?.let { removeOnLayoutChangeListener(it) } field = value field?.let { addOnLayoutChangeListener(it) } } init { if (onClick != null) { setOnClickListener {} override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo?) { if (enableAccessibility) { super.onInitializeAccessibilityNodeInfo(info) } } override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { return (isSliceViewClickable && onClick != null) || super.onInterceptTouchEvent(ev) override fun onInitializeAccessibilityEvent(event: AccessibilityEvent?) { if (enableAccessibility) { super.onInitializeAccessibilityEvent(event) } } override fun onClick(v: View?) { onClick?.takeIf { isSliceViewClickable }?.let { it() } ?: super.onClick(v) override fun performAccessibilityAction(action: Int, arguments: Bundle?): Boolean { return if (enableAccessibility) { super.performAccessibilityAction(action, arguments) } else { false } } override fun addChildrenForAccessibility(outChildren: ArrayList<View>?) { if (enableAccessibility) { super.addChildrenForAccessibility(outChildren) } } } Loading
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt +34 −25 Original line number Diff line number Diff line Loading @@ -19,10 +19,13 @@ package com.android.systemui.volume.panel.component.anc.ui.composable import android.view.Gravity import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.ButtonColors import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable Loading @@ -32,15 +35,15 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.LiveRegionMode import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.liveRegion import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle Loading @@ -66,13 +69,6 @@ constructor( with(LocalDensity.current) { LocalConfiguration.current.screenWidthDp.dp.toPx() } var gravity by remember { mutableIntStateOf(Gravity.CENTER_HORIZONTAL) } val isClickable = viewModel.isClickable(slice) val onClick = if (isClickable) { { with(ancPopup) { show(null, gravity) } } } else { null } Column( modifier = modifier.onGloballyPositioned { Loading @@ -80,21 +76,34 @@ constructor( }, verticalArrangement = Arrangement.spacedBy(12.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { Box( modifier = Modifier.height(64.dp), ) { SliceAndroidView( modifier = Modifier.height(64.dp) .fillMaxWidth() .semantics { role = Role.Button contentDescription = label } .clip(RoundedCornerShape(28.dp)), modifier = modifier.fillMaxSize(), slice = slice, isEnabled = onClick != null, onWidthChanged = viewModel::onButtonSliceWidthChanged, onClick = onClick, enableAccessibility = false, ) Button( modifier = modifier.fillMaxSize().padding(8.dp).semantics { liveRegion = LiveRegionMode.Polite contentDescription = label }, enabled = isClickable, onClick = { with(ancPopup) { show(null, gravity) } }, colors = ButtonColors( contentColor = Color.Transparent, containerColor = Color.Transparent, disabledContentColor = Color.Transparent, disabledContainerColor = Color.Transparent, ) ) {} } Text( modifier = Modifier.clearAndSetSemantics {}.basicMarquee(), text = label, Loading
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt +41 −27 Original line number Diff line number Diff line Loading @@ -16,11 +16,12 @@ package com.android.systemui.volume.panel.component.anc.ui.composable import android.annotation.SuppressLint import android.content.Context import android.os.Bundle import android.view.ContextThemeWrapper import android.view.MotionEvent import android.view.View import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityNodeInfo import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.viewinterop.AndroidView Loading @@ -32,14 +33,13 @@ import com.android.systemui.res.R fun SliceAndroidView( slice: Slice?, modifier: Modifier = Modifier, isEnabled: Boolean = true, onWidthChanged: ((Int) -> Unit)? = null, onClick: (() -> Unit)? = null, enableAccessibility: Boolean = true, ) { AndroidView( modifier = modifier, factory = { context: Context -> ClickableSliceView( ComposeSliceView( ContextThemeWrapper(context, R.style.Widget_SliceView_VolumePanel), ) .apply { Loading @@ -47,17 +47,18 @@ fun SliceAndroidView( isScrollable = false importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO setShowTitleItems(true) if (onWidthChanged != null) { addOnLayoutChangeListener(OnWidthChangedLayoutListener(onWidthChanged)) } } }, update = { sliceView: ClickableSliceView -> update = { sliceView: ComposeSliceView -> sliceView.slice = slice sliceView.onClick = onClick sliceView.isEnabled = isEnabled sliceView.isClickable = isEnabled } sliceView.layoutListener = onWidthChanged?.let(::OnWidthChangedLayoutListener) sliceView.enableAccessibility = enableAccessibility }, onRelease = { sliceView: ComposeSliceView -> sliceView.layoutListener = null sliceView.slice = null sliceView.enableAccessibility = true }, ) } Loading @@ -83,26 +84,39 @@ class OnWidthChangedLayoutListener(private val widthChanged: (Int) -> Unit) : } } /** * [SliceView] that prioritises [onClick] when its clicked instead of passing the event to the slice * first. */ @SuppressLint("ViewConstructor") // only used in this class private class ClickableSliceView(context: Context) : SliceView(context) { private class ComposeSliceView(context: Context) : SliceView(context) { var onClick: (() -> Unit)? = null var enableAccessibility: Boolean = true var layoutListener: OnLayoutChangeListener? = null set(value) { field?.let { removeOnLayoutChangeListener(it) } field = value field?.let { addOnLayoutChangeListener(it) } } init { if (onClick != null) { setOnClickListener {} override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo?) { if (enableAccessibility) { super.onInitializeAccessibilityNodeInfo(info) } } override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { return (isSliceViewClickable && onClick != null) || super.onInterceptTouchEvent(ev) override fun onInitializeAccessibilityEvent(event: AccessibilityEvent?) { if (enableAccessibility) { super.onInitializeAccessibilityEvent(event) } } override fun onClick(v: View?) { onClick?.takeIf { isSliceViewClickable }?.let { it() } ?: super.onClick(v) override fun performAccessibilityAction(action: Int, arguments: Bundle?): Boolean { return if (enableAccessibility) { super.performAccessibilityAction(action, arguments) } else { false } } override fun addChildrenForAccessibility(outChildren: ArrayList<View>?) { if (enableAccessibility) { super.addChildrenForAccessibility(outChildren) } } }