Loading packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/AncModule.kt +5 −14 Original line number Diff line number Diff line Loading @@ -17,15 +17,12 @@ package com.android.systemui.volume.panel.component.anc import com.android.systemui.volume.panel.component.anc.domain.AncAvailabilityCriteria import com.android.systemui.volume.panel.component.anc.ui.composable.AncPopup import com.android.systemui.volume.panel.component.anc.ui.viewmodel.AncViewModel import com.android.systemui.volume.panel.component.button.ui.composable.ButtonComponent import com.android.systemui.volume.panel.component.anc.ui.composable.AncButtonComponent import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent import dagger.Binds import dagger.Module import dagger.Provides import dagger.multibindings.IntoMap import dagger.multibindings.StringKey Loading @@ -40,14 +37,8 @@ interface AncModule { criteria: AncAvailabilityCriteria ): ComponentAvailabilityCriteria companion object { @Provides @Binds @IntoMap @StringKey(VolumePanelComponents.ANC) fun provideVolumePanelUiComponent( viewModel: AncViewModel, popup: AncPopup, ): VolumePanelUiComponent = ButtonComponent(viewModel.button, popup::show) } fun bindVolumePanelUiComponent(component: AncButtonComponent): VolumePanelUiComponent } packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt 0 → 100644 +84 −0 Original line number Diff line number Diff line /* * 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.volume.panel.component.anc.ui.composable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.android.systemui.res.R import com.android.systemui.volume.panel.component.anc.ui.viewmodel.AncViewModel import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope import javax.inject.Inject class AncButtonComponent @Inject constructor( private val viewModel: AncViewModel, private val ancPopup: AncPopup, ) : ComposeVolumePanelUiComponent { @Composable override fun VolumePanelComposeScope.Content(modifier: Modifier) { val slice by viewModel.buttonSlice.collectAsState() val label = stringResource(R.string.volume_panel_noise_control_title) Column( modifier = modifier, verticalArrangement = Arrangement.spacedBy(12.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { SliceAndroidView( modifier = Modifier.height(64.dp) .fillMaxWidth() .semantics { role = Role.Button contentDescription = label } .clip(RoundedCornerShape(28.dp)), slice = slice, onWidthChanged = viewModel::onButtonSliceWidthChanged, onClick = { ancPopup.show(null) } ) Text( modifier = Modifier.clearAndSetSemantics {}, text = label, style = MaterialTheme.typography.labelMedium, maxLines = 1, overflow = TextOverflow.Ellipsis, ) } } } packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt +7 −43 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ package com.android.systemui.volume.panel.component.anc.ui.composable import android.content.Context import android.view.ContextThemeWrapper import android.view.View import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.MaterialTheme Loading @@ -30,9 +27,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.viewinterop.AndroidView import androidx.slice.Slice import androidx.slice.widget.SliceView import com.android.systemui.animation.Expandable import com.android.systemui.res.R import com.android.systemui.statusbar.phone.SystemUIDialog Loading @@ -49,7 +44,7 @@ constructor( ) { /** Shows a popup with the [expandable] animation. */ fun show(expandable: Expandable) { fun show(expandable: Expandable?) { volumePanelPopup.show(expandable, { Title() }, { Content(it) }) } Loading @@ -66,49 +61,18 @@ constructor( @Composable private fun Content(dialog: SystemUIDialog) { val slice: Slice? by viewModel.slice.collectAsState() val isAvailable by viewModel.isAvailable.collectAsState(true) if (slice == null) { if (!isAvailable) { SideEffect { dialog.dismiss() } return } AndroidView<SliceView>( val slice by viewModel.popupSlice.collectAsState() SliceAndroidView( modifier = Modifier.fillMaxWidth(), factory = { context: Context -> SliceView(ContextThemeWrapper(context, R.style.Widget_SliceView_VolumePanel)) .apply { mode = SliceView.MODE_LARGE isScrollable = false importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO setShowTitleItems(true) addOnLayoutChangeListener( OnWidthChangedLayoutListener(viewModel::changeSliceWidth) slice = slice, onWidthChanged = viewModel::onPopupSliceWidthChanged ) } }, update = { sliceView: SliceView -> sliceView.slice = slice } ) } private class OnWidthChangedLayoutListener(private val widthChanged: (Int) -> Unit) : View.OnLayoutChangeListener { override fun onLayoutChange( v: View?, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int ) { val newWidth = right - left val oldWidth = oldRight - oldLeft if (oldWidth != newWidth) { widthChanged(newWidth) } } } } packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt 0 → 100644 +107 −0 Original line number Diff line number Diff line /* * 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.volume.panel.component.anc.ui.composable import android.annotation.SuppressLint import android.content.Context import android.view.ContextThemeWrapper import android.view.MotionEvent import android.view.View import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.viewinterop.AndroidView import androidx.slice.Slice import androidx.slice.widget.SliceView import com.android.systemui.res.R @Composable fun SliceAndroidView( slice: Slice?, modifier: Modifier = Modifier, onWidthChanged: ((Int) -> Unit)? = null, onClick: (() -> Unit)? = null, ) { AndroidView( modifier = modifier, factory = { context: Context -> ClickableSliceView( ContextThemeWrapper(context, R.style.Widget_SliceView_VolumePanel), onClick, ) .apply { mode = SliceView.MODE_LARGE isScrollable = false importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO setShowTitleItems(true) if (onWidthChanged != null) { addOnLayoutChangeListener(OnWidthChangedLayoutListener(onWidthChanged)) } if (onClick != null) { setOnClickListener { onClick() } } } }, update = { sliceView: SliceView -> sliceView.slice = slice } ) } class OnWidthChangedLayoutListener(private val widthChanged: (Int) -> Unit) : View.OnLayoutChangeListener { override fun onLayoutChange( v: View?, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int ) { val newWidth = right - left val oldWidth = oldRight - oldLeft if (oldWidth != newWidth) { widthChanged(newWidth) } } } /** * [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, private val onClick: (() -> Unit)?, ) : SliceView(context) { init { if (onClick != null) { setOnClickListener {} } } override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { return onClick != null || super.onInterceptTouchEvent(ev) } override fun onClick(v: View?) { onClick?.let { it() } ?: super.onClick(v) } } packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt +2 −2 Original line number Diff line number Diff line Loading @@ -59,7 +59,7 @@ constructor( * @param content is the popup body */ fun show( expandable: Expandable, expandable: Expandable?, title: @Composable (SystemUIDialog) -> Unit, content: @Composable (SystemUIDialog) -> Unit, ) { Loading @@ -70,7 +70,7 @@ constructor( ) { PopupComposable(it, title, content) } val controller = expandable.dialogTransitionController() val controller = expandable?.dialogTransitionController() if (controller == null) { dialog.show() } else { Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/AncModule.kt +5 −14 Original line number Diff line number Diff line Loading @@ -17,15 +17,12 @@ package com.android.systemui.volume.panel.component.anc import com.android.systemui.volume.panel.component.anc.domain.AncAvailabilityCriteria import com.android.systemui.volume.panel.component.anc.ui.composable.AncPopup import com.android.systemui.volume.panel.component.anc.ui.viewmodel.AncViewModel import com.android.systemui.volume.panel.component.button.ui.composable.ButtonComponent import com.android.systemui.volume.panel.component.anc.ui.composable.AncButtonComponent import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent import dagger.Binds import dagger.Module import dagger.Provides import dagger.multibindings.IntoMap import dagger.multibindings.StringKey Loading @@ -40,14 +37,8 @@ interface AncModule { criteria: AncAvailabilityCriteria ): ComponentAvailabilityCriteria companion object { @Provides @Binds @IntoMap @StringKey(VolumePanelComponents.ANC) fun provideVolumePanelUiComponent( viewModel: AncViewModel, popup: AncPopup, ): VolumePanelUiComponent = ButtonComponent(viewModel.button, popup::show) } fun bindVolumePanelUiComponent(component: AncButtonComponent): VolumePanelUiComponent }
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt 0 → 100644 +84 −0 Original line number Diff line number Diff line /* * 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.volume.panel.component.anc.ui.composable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.android.systemui.res.R import com.android.systemui.volume.panel.component.anc.ui.viewmodel.AncViewModel import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope import javax.inject.Inject class AncButtonComponent @Inject constructor( private val viewModel: AncViewModel, private val ancPopup: AncPopup, ) : ComposeVolumePanelUiComponent { @Composable override fun VolumePanelComposeScope.Content(modifier: Modifier) { val slice by viewModel.buttonSlice.collectAsState() val label = stringResource(R.string.volume_panel_noise_control_title) Column( modifier = modifier, verticalArrangement = Arrangement.spacedBy(12.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { SliceAndroidView( modifier = Modifier.height(64.dp) .fillMaxWidth() .semantics { role = Role.Button contentDescription = label } .clip(RoundedCornerShape(28.dp)), slice = slice, onWidthChanged = viewModel::onButtonSliceWidthChanged, onClick = { ancPopup.show(null) } ) Text( modifier = Modifier.clearAndSetSemantics {}, text = label, style = MaterialTheme.typography.labelMedium, maxLines = 1, overflow = TextOverflow.Ellipsis, ) } } }
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt +7 −43 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ package com.android.systemui.volume.panel.component.anc.ui.composable import android.content.Context import android.view.ContextThemeWrapper import android.view.View import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.MaterialTheme Loading @@ -30,9 +27,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.viewinterop.AndroidView import androidx.slice.Slice import androidx.slice.widget.SliceView import com.android.systemui.animation.Expandable import com.android.systemui.res.R import com.android.systemui.statusbar.phone.SystemUIDialog Loading @@ -49,7 +44,7 @@ constructor( ) { /** Shows a popup with the [expandable] animation. */ fun show(expandable: Expandable) { fun show(expandable: Expandable?) { volumePanelPopup.show(expandable, { Title() }, { Content(it) }) } Loading @@ -66,49 +61,18 @@ constructor( @Composable private fun Content(dialog: SystemUIDialog) { val slice: Slice? by viewModel.slice.collectAsState() val isAvailable by viewModel.isAvailable.collectAsState(true) if (slice == null) { if (!isAvailable) { SideEffect { dialog.dismiss() } return } AndroidView<SliceView>( val slice by viewModel.popupSlice.collectAsState() SliceAndroidView( modifier = Modifier.fillMaxWidth(), factory = { context: Context -> SliceView(ContextThemeWrapper(context, R.style.Widget_SliceView_VolumePanel)) .apply { mode = SliceView.MODE_LARGE isScrollable = false importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO setShowTitleItems(true) addOnLayoutChangeListener( OnWidthChangedLayoutListener(viewModel::changeSliceWidth) slice = slice, onWidthChanged = viewModel::onPopupSliceWidthChanged ) } }, update = { sliceView: SliceView -> sliceView.slice = slice } ) } private class OnWidthChangedLayoutListener(private val widthChanged: (Int) -> Unit) : View.OnLayoutChangeListener { override fun onLayoutChange( v: View?, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int ) { val newWidth = right - left val oldWidth = oldRight - oldLeft if (oldWidth != newWidth) { widthChanged(newWidth) } } } }
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt 0 → 100644 +107 −0 Original line number Diff line number Diff line /* * 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.volume.panel.component.anc.ui.composable import android.annotation.SuppressLint import android.content.Context import android.view.ContextThemeWrapper import android.view.MotionEvent import android.view.View import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.viewinterop.AndroidView import androidx.slice.Slice import androidx.slice.widget.SliceView import com.android.systemui.res.R @Composable fun SliceAndroidView( slice: Slice?, modifier: Modifier = Modifier, onWidthChanged: ((Int) -> Unit)? = null, onClick: (() -> Unit)? = null, ) { AndroidView( modifier = modifier, factory = { context: Context -> ClickableSliceView( ContextThemeWrapper(context, R.style.Widget_SliceView_VolumePanel), onClick, ) .apply { mode = SliceView.MODE_LARGE isScrollable = false importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO setShowTitleItems(true) if (onWidthChanged != null) { addOnLayoutChangeListener(OnWidthChangedLayoutListener(onWidthChanged)) } if (onClick != null) { setOnClickListener { onClick() } } } }, update = { sliceView: SliceView -> sliceView.slice = slice } ) } class OnWidthChangedLayoutListener(private val widthChanged: (Int) -> Unit) : View.OnLayoutChangeListener { override fun onLayoutChange( v: View?, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int ) { val newWidth = right - left val oldWidth = oldRight - oldLeft if (oldWidth != newWidth) { widthChanged(newWidth) } } } /** * [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, private val onClick: (() -> Unit)?, ) : SliceView(context) { init { if (onClick != null) { setOnClickListener {} } } override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { return onClick != null || super.onInterceptTouchEvent(ev) } override fun onClick(v: View?) { onClick?.let { it() } ?: super.onClick(v) } }
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt +2 −2 Original line number Diff line number Diff line Loading @@ -59,7 +59,7 @@ constructor( * @param content is the popup body */ fun show( expandable: Expandable, expandable: Expandable?, title: @Composable (SystemUIDialog) -> Unit, content: @Composable (SystemUIDialog) -> Unit, ) { Loading @@ -70,7 +70,7 @@ constructor( ) { PopupComposable(it, title, content) } val controller = expandable.dialogTransitionController() val controller = expandable?.dialogTransitionController() if (controller == null) { dialog.show() } else { Loading