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

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

Merge "Add Spatial audio repository" into main

parents 9b971ac8 d1f363cc
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
@@ -54,5 +57,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)
    }
}