Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20964d78 authored by Anton Potapov's avatar Anton Potapov Committed by Android (Google) Code Review
Browse files

Merge "Incorporate ANC slice into the Volume Panel button" into main

parents e451c8ce 126b8fc8
Loading
Loading
Loading
Loading
+5 −14
Original line number Diff line number Diff line
@@ -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

@@ -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
}
+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,
            )
        }
    }
}
+7 −43
Original line number Diff line number Diff line
@@ -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
@@ -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
@@ -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) })
    }

@@ -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)
            }
        }
    }
}
+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)
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -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,
    ) {
@@ -70,7 +70,7 @@ constructor(
            ) {
                PopupComposable(it, title, content)
            }
        val controller = expandable.dialogTransitionController()
        val controller = expandable?.dialogTransitionController()
        if (controller == null) {
            dialog.show()
        } else {
Loading