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

Commit d1f363cc authored by Anton Potapov's avatar Anton Potapov
Browse files

Add Spatial audio repository

Flag: aconfig new_volume_panel DISABLED
Fixes: 323165738
Test: atest SpatializerRepositoryTest
Change-Id: I405dbd85077534849d6a694ebf9779e480396f76
parent 61b0f8fa
Loading
Loading
Loading
Loading
+69 −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.settingslib.media.data.repository

import android.media.AudioDeviceAttributes
import android.media.Spatializer
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.withContext

interface SpatializerRepository {

    /**
     * Returns true when Spatial audio feature is supported for the [audioDeviceAttributes] and
     * false the otherwise.
     */
    suspend fun isAvailableForDevice(audioDeviceAttributes: AudioDeviceAttributes): Boolean

    /** Returns a list [AudioDeviceAttributes] that are compatible with spatial audio. */
    suspend fun getCompatibleDevices(): Collection<AudioDeviceAttributes>

    /** Adds a [audioDeviceAttributes] to [getCompatibleDevices] list. */
    suspend fun addCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes)

    /** Removes a [audioDeviceAttributes] to [getCompatibleDevices] list. */
    suspend fun removeCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes)
}

class SpatializerRepositoryImpl(
    private val spatializer: Spatializer,
    private val backgroundContext: CoroutineContext,
) : SpatializerRepository {

    override suspend fun isAvailableForDevice(
        audioDeviceAttributes: AudioDeviceAttributes
    ): Boolean {
        return withContext(backgroundContext) {
            spatializer.isAvailableForDevice(audioDeviceAttributes)
        }
    }

    override suspend fun getCompatibleDevices(): Collection<AudioDeviceAttributes> =
        withContext(backgroundContext) { spatializer.compatibleAudioDevices }

    override suspend fun addCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) {
        withContext(backgroundContext) {
            spatializer.addCompatibleAudioDevice(audioDeviceAttributes)
        }
    }

    override suspend fun removeCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) {
        withContext(backgroundContext) {
            spatializer.removeCompatibleAudioDevice(audioDeviceAttributes)
        }
    }
}
+39 −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.settingslib.media.domain.interactor

import android.media.AudioDeviceAttributes
import com.android.settingslib.media.data.repository.SpatializerRepository

class SpatializerInteractor(private val repository: SpatializerRepository) {

    suspend fun isAvailable(audioDeviceAttributes: AudioDeviceAttributes): Boolean =
        repository.isAvailableForDevice(audioDeviceAttributes)

    /** Checks if spatial audio is enabled for the [audioDeviceAttributes]. */
    suspend fun isEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean =
        repository.getCompatibleDevices().contains(audioDeviceAttributes)

    /** Enblaes or disables spatial audio for [audioDeviceAttributes]. */
    suspend fun setEnabled(audioDeviceAttributes: AudioDeviceAttributes, isEnabled: Boolean) {
        if (isEnabled) {
            repository.addCompatibleDevice(audioDeviceAttributes)
        } else {
            repository.removeCompatibleDevice(audioDeviceAttributes)
        }
    }
}
+45 −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.settingslib.media.domain.interactor

import android.media.AudioDeviceAttributes
import com.android.settingslib.media.data.repository.SpatializerRepository

class FakeSpatializerRepository : SpatializerRepository {

    private val availabilityByDevice: MutableMap<AudioDeviceAttributes, Boolean> = mutableMapOf()
    private val compatibleDevices: MutableList<AudioDeviceAttributes> = mutableListOf()

    override suspend fun isAvailableForDevice(
        audioDeviceAttributes: AudioDeviceAttributes
    ): Boolean = availabilityByDevice.getOrDefault(audioDeviceAttributes, false)

    override suspend fun getCompatibleDevices(): Collection<AudioDeviceAttributes> =
        compatibleDevices

    override suspend fun addCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) {
        compatibleDevices.add(audioDeviceAttributes)
    }

    override suspend fun removeCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) {
        compatibleDevices.remove(audioDeviceAttributes)
    }

    fun setIsAvailable(audioDeviceAttributes: AudioDeviceAttributes, isAvailable: Boolean) {
        availabilityByDevice[audioDeviceAttributes] = isAvailable
    }
}
+56 −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.settingslib.media.domain.interactor

import android.media.AudioDeviceAttributes
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class SpatializerInteractorTest {

    private val testScope = TestScope()
    private val underTest = SpatializerInteractor(FakeSpatializerRepository())

    @Test
    fun setEnabledFalse_isEnabled_false() {
        testScope.runTest {
            underTest.setEnabled(deviceAttributes, false)

            assertThat(underTest.isEnabled(deviceAttributes)).isFalse()
        }
    }

    @Test
    fun setEnabledTrue_isEnabled_true() {
        testScope.runTest {
            underTest.setEnabled(deviceAttributes, true)

            assertThat(underTest.isEnabled(deviceAttributes)).isTrue()
        }
    }

    private companion object {
        val deviceAttributes = AudioDeviceAttributes(0, 0, "test_device")
    }
}
+14 −0
Original line number Diff line number Diff line
@@ -18,6 +18,9 @@ package com.android.systemui.volume.dagger

import android.content.Context
import android.media.AudioManager
import com.android.settingslib.media.data.repository.SpatializerRepository
import com.android.settingslib.media.data.repository.SpatializerRepositoryImpl
import com.android.settingslib.media.domain.interactor.SpatializerInteractor
import com.android.settingslib.volume.data.repository.AudioRepository
import com.android.settingslib.volume.data.repository.AudioRepositoryImpl
import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
@@ -46,5 +49,16 @@ interface AudioModule {
        @Provides
        fun provideAudioModeInteractor(repository: AudioRepository): AudioModeInteractor =
            AudioModeInteractor(repository)

        @Provides
        fun provdieSpatializerRepository(
            audioManager: AudioManager,
            @Background backgroundContext: CoroutineContext,
        ): SpatializerRepository =
            SpatializerRepositoryImpl(audioManager.spatializer, backgroundContext)

        @Provides
        fun provideSpatializerInetractor(repository: SpatializerRepository): SpatializerInteractor =
            SpatializerInteractor(repository)
    }
}