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

Commit 217c1f4a authored by Anton Potapov's avatar Anton Potapov
Browse files

Add slider input events interactor.

This interactor provides touches and button presses that affect the
Slider of the corresponding `@VolumeDialogSliderScope`

Flag: com.android.systemui.volume_redesign
Test: manual on foldable
Test: atest VolumeDialogSliderInputEventsInteractorTest
Bug: 369995895
Change-Id: Ia4339b8d1f0f1a470a07a3b541355d8ddfab6b55
parent 0d027067
Loading
Loading
Loading
Loading
+92 −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.dialog.sliders.domain.interactor

import android.app.ActivityManager
import android.testing.TestableLooper
import android.view.MotionEvent
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.fakeVolumeDialogController
import com.android.systemui.testKosmos
import com.android.systemui.volume.Events
import com.android.systemui.volume.dialog.domain.interactor.volumeDialogVisibilityInteractor
import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.runner.RunWith

private val volumeDialogTimeout = 3.seconds

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class VolumeDialogSliderInputEventsInteractorTest : SysuiTestCase() {

    private val kosmos = testKosmos()

    private lateinit var underTest: VolumeDialogSliderInputEventsInteractor

    @Before
    fun setup() {
        underTest = kosmos.volumeDialogSliderInputEventsInteractor
    }

    @Test
    fun inputEvents_resetDialogVisibilityTimeout() =
        with(kosmos) {
            testScope.runTest {
                runCurrent()
                val dialogVisibility by
                    collectLastValue(volumeDialogVisibilityInteractor.dialogVisibility)
                fakeVolumeDialogController.onShowRequested(
                    Events.SHOW_REASON_VOLUME_CHANGED,
                    false,
                    ActivityManager.LOCK_TASK_MODE_LOCKED,
                )
                runCurrent()
                advanceTimeBy(volumeDialogTimeout / 2)
                assertThat(dialogVisibility)
                    .isInstanceOf(VolumeDialogVisibilityModel.Visible::class.java)

                underTest.onTouchEvent(
                    MotionEvent.obtain(
                        /* downTime = */ 0,
                        /* eventTime = */ 0,
                        /* action = */ 0,
                        /* x = */ 0f,
                        /* y = */ 0f,
                        /* metaState = */ 0,
                    )
                )
                advanceTimeBy(volumeDialogTimeout / 2)

                assertThat(dialogVisibility)
                    .isInstanceOf(VolumeDialogVisibilityModel.Visible::class.java)
            }
        }
}
+3 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.volume.dialog.sliders.dagger

import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType
import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSliderTouchesViewBinder
import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSliderViewBinder
import dagger.BindsInstance
import dagger.Subcomponent
@@ -31,6 +32,8 @@ interface VolumeDialogSliderComponent {

    fun sliderViewBinder(): VolumeDialogSliderViewBinder

    fun sliderTouchesViewBinder(): VolumeDialogSliderTouchesViewBinder

    @Subcomponent.Factory
    interface Factory {

+37 −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.dialog.sliders.data.repository

import android.annotation.SuppressLint
import android.view.MotionEvent
import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filterNotNull

@VolumeDialogSliderScope
class VolumeDialogSliderTouchEventsRepository @Inject constructor() {

    @SuppressLint("SharedFlowCreation")
    private val mutableSliderTouchEvents: MutableStateFlow<MotionEvent?> = MutableStateFlow(null)
    val sliderTouchEvent: Flow<MotionEvent> = mutableSliderTouchEvents.filterNotNull()

    fun update(event: MotionEvent) {
        mutableSliderTouchEvents.tryEmit(MotionEvent.obtain(event))
    }
}
+61 −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.dialog.sliders.domain.interactor

import android.view.MotionEvent
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogCallbacksInteractor
import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
import com.android.systemui.volume.dialog.domain.model.VolumeDialogEventModel
import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
import com.android.systemui.volume.dialog.sliders.data.repository.VolumeDialogSliderTouchEventsRepository
import com.android.systemui.volume.dialog.sliders.shared.model.SliderInputEvent
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach

@VolumeDialogSliderScope
class VolumeDialogSliderInputEventsInteractor
@Inject
constructor(
    @VolumeDialog coroutineScope: CoroutineScope,
    volumeDialogCallbacksInteractor: VolumeDialogCallbacksInteractor,
    private val visibilityInteractor: VolumeDialogVisibilityInteractor,
    private val repository: VolumeDialogSliderTouchEventsRepository,
) {

    val event: Flow<SliderInputEvent> =
        merge(
            repository.sliderTouchEvent.map { SliderInputEvent.Touch(it) },
            volumeDialogCallbacksInteractor.event
                .filterIsInstance(VolumeDialogEventModel.VolumeChangedFromKey::class)
                .map { SliderInputEvent.Button },
        )

    init {
        event.onEach { visibilityInteractor.resetDismissTimeout() }.launchIn(coroutineScope)
    }

    fun onTouchEvent(newEvent: MotionEvent) {
        repository.update(newEvent)
    }
}
+27 −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.dialog.sliders.shared.model

import android.view.MotionEvent

/** Models input event happened on the Volume Slider */
sealed interface SliderInputEvent {

    data class Touch(val event: MotionEvent) : SliderInputEvent

    data object Button : SliderInputEvent
}
Loading