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

Commit 3cfc4ecc authored by Michael Mikhail's avatar Michael Mikhail
Browse files

Add domain layer for volume dialog ringer

Flag: com.android.systemui.volume_redesign
Bug: 369993851
Test: atest SystemUiRoboTests:VolumeDialogRingerInteractorTest
Change-Id: I8f984494603751df64230f8b11d437b0a41f95fa
parent b1f38863
Loading
Loading
Loading
Loading
+99 −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.ringer.domain

import android.media.AudioManager.RINGER_MODE_NORMAL
import android.media.AudioManager.RINGER_MODE_SILENT
import android.media.AudioManager.RINGER_MODE_VIBRATE
import android.media.AudioManager.STREAM_RING
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.volume.shared.model.RingerMode
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.fakeVolumeDialogController
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

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

    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val controller = kosmos.fakeVolumeDialogController

    private lateinit var underTest: VolumeDialogRingerInteractor

    @Before
    fun setUp() {
        underTest = kosmos.volumeDialogRingerInteractor
        controller.setStreamVolume(STREAM_RING, 50)
    }

    @Test
    fun setRingerMode_normal() =
        testScope.runTest {
            runCurrent()
            val ringerModel by collectLastValue(underTest.ringerModel)

            underTest.setRingerMode(RingerMode(RINGER_MODE_NORMAL))
            controller.getState()
            runCurrent()

            assertThat(ringerModel).isNotNull()
            assertThat(ringerModel?.currentRingerMode).isEqualTo(RingerMode(RINGER_MODE_NORMAL))
        }

    @Test
    fun setRingerMode_silent() =
        testScope.runTest {
            runCurrent()
            val ringerModel by collectLastValue(underTest.ringerModel)

            underTest.setRingerMode(RingerMode(RINGER_MODE_SILENT))
            controller.getState()
            runCurrent()

            assertThat(ringerModel).isNotNull()
            assertThat(ringerModel?.currentRingerMode).isEqualTo(RingerMode(RINGER_MODE_SILENT))
        }

    @Test
    fun setRingerMode_vibrate() =
        testScope.runTest {
            runCurrent()
            val ringerModel by collectLastValue(underTest.ringerModel)

            underTest.setRingerMode(RingerMode(RINGER_MODE_VIBRATE))
            controller.getState()
            runCurrent()

            assertThat(ringerModel).isNotNull()
            assertThat(ringerModel?.currentRingerMode).isEqualTo(RingerMode(RINGER_MODE_VIBRATE))
        }
}
+88 −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.ringer.domain

import android.media.AudioManager
import android.media.AudioManager.RINGER_MODE_NORMAL
import android.media.AudioManager.RINGER_MODE_SILENT
import android.media.AudioManager.RINGER_MODE_VIBRATE
import android.provider.Settings
import com.android.settingslib.volume.shared.model.RingerMode
import com.android.systemui.plugins.VolumeDialogController
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogStateInteractor
import com.android.systemui.volume.dialog.ringer.data.VolumeDialogRingerRepository
import com.android.systemui.volume.dialog.ringer.shared.model.VolumeDialogRingerModel
import com.android.systemui.volume.dialog.shared.model.VolumeDialogStateModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.onEach

/** Exposes [VolumeDialogRingerModel]. */
@VolumeDialog
class VolumeDialogRingerInteractor
@Inject
constructor(
    @VolumeDialog private val coroutineScope: CoroutineScope,
    volumeDialogStateInteractor: VolumeDialogStateInteractor,
    private val controller: VolumeDialogController,
    private val repository: VolumeDialogRingerRepository,
) {

    val ringerModel: Flow<VolumeDialogRingerModel> = repository.ringerModel

    init {
        volumeDialogStateInteractor.volumeDialogState
            .mapNotNull { state -> toRingerModel(state) }
            .onEach { ringerModel -> repository.updateRingerModel { ringerModel } }
            .launchIn(coroutineScope)
    }

    private fun toRingerModel(state: VolumeDialogStateModel): VolumeDialogRingerModel? {
        return state.streamModels[AudioManager.STREAM_RING]?.let {
            VolumeDialogRingerModel(
                availableModes =
                    mutableListOf(RingerMode(RINGER_MODE_NORMAL), RingerMode(RINGER_MODE_SILENT))
                        .also { list ->
                            if (controller.hasVibrator()) {
                                list.add(RingerMode(RINGER_MODE_VIBRATE))
                            }
                        },
                currentRingerMode = RingerMode(state.ringerModeInternal),
                isEnabled =
                    !(state.zenMode == Settings.Global.ZEN_MODE_ALARMS ||
                        state.zenMode == Settings.Global.ZEN_MODE_NO_INTERRUPTIONS ||
                        (state.zenMode == Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS &&
                            state.disallowRinger)),
                isMuted = it.level == 0 || it.muted,
                level = it.level,
                levelMax = it.levelMax,
            )
        }
    }

    fun setRingerMode(ringerMode: RingerMode) {
        controller.setRingerMode(ringerMode.value, false)
    }

    fun scheduleTouchFeedback() {
        controller.scheduleTouchFeedback()
    }
}
+33 −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.ringer.domain

import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.plugins.volumeDialogController
import com.android.systemui.volume.dialog.domain.interactor.volumeDialogStateInteractor
import com.android.systemui.volume.dialog.ringer.data.volumeDialogRingerRepository

val Kosmos.volumeDialogRingerInteractor by
    Kosmos.Fixture {
        VolumeDialogRingerInteractor(
            coroutineScope = applicationCoroutineScope,
            volumeDialogStateInteractor = volumeDialogStateInteractor,
            controller = volumeDialogController,
            repository = volumeDialogRingerRepository,
        )
    }