Skip to content

Commit

Permalink
Audio Manager Sample
Browse files Browse the repository at this point in the history
Change-Id: I31d9c0eb6a4431131ebe8490b910d80d41657eaf
  • Loading branch information
Nodroid7 committed Jan 31, 2023
1 parent 33e5a45 commit 1b3aecc
Show file tree
Hide file tree
Showing 14 changed files with 675 additions and 7 deletions.
6 changes: 0 additions & 6 deletions .idea/vcs.xml

This file was deleted.

15 changes: 15 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,21 @@ gradlePlugin = "7.3.1"
hilt = "2.44.2"
kotlin = "1.8.0"
ktlint = "0.48.1"
coroutines = "1.6.4"

[libraries]
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
affectedmoduledetector = "com.dropbox.affectedmoduledetector:affectedmoduledetector:0.2.0"
android-gradlePlugin = { module = "com.android.tools.build:gradle", version.ref = "gradlePlugin" }

androidx-activity = "androidx.activity:activity:1.6.1"
androidx-core = "androidx.core:core-ktx:1.9.0"
androidx-fragment = "androidx.fragment:fragment-ktx:1.5.4"
androidx-activity-compose = "androidx.activity:activity-compose:1.6.1"
androidx-navigation-fragment = "androidx.navigation:navigation-fragment:2.5.3"
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidx-navigation" }
androidx-lifecycle-viewmodel-compose = "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.0"

casa-base = { module = "com.google.android.catalog.framework:casa-base", version.ref = "casa" }
casa-processor = { module = "com.google.android.catalog.framework:casa-processor", version.ref = "casa" }
casa-ui = { module = "com.google.android.catalog.framework:casa-ui", version.ref = "casa" }
Expand All @@ -40,16 +47,24 @@ compose-animation-animation = { module = "androidx.compose.animation:animation"
compose-foundation-foundation = { module = "androidx.compose.foundation:foundation" }
compose-foundation-layout = { module = "androidx.compose.foundation:layout" }
compose-material3 = { module = "androidx.compose.material3:material3" }
compose-material-material = { module = "androidx.compose.material:material", version.ref = "compose-bom" }
compose-material-iconsext = { module = "androidx.compose.material:material-icons-extended", version.ref = "compose-bom" }
compose-runtime-runtime = { module = "androidx.compose.runtime:runtime" }
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "compose-bom" }
compose-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "compose-bom" }
compose-ui-ui = { module = "androidx.compose.ui:ui" }
compose-ui-util = { module = "androidx.compose.ui:util" }
google-ksp = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "com-google-devtools-ksp" }
google-ksp-api = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "com-google-devtools-ksp" }

hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" }
hilt-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" }
hilt-plugin = { module = "com.google.dagger:hilt-android-gradle-plugin", version.ref = "hilt" }
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
kotlin-gradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlin-stdlibJdk8 = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
kotlin-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
kotlin-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
2 changes: 1 addition & 1 deletion gradle/sample-build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ dependencies {

implementation libs.androidx.core
implementation libs.compose.foundation.foundation
implementation libs.androidx.lifecycle.viewmodel.compose
implementation libs.compose.ui.ui
implementation libs.compose.material3
implementation libs.accompanist.permissions

implementation libs.compose.ui.tooling.preview
debugImplementation libs.compose.ui.tooling
}
22 changes: 22 additions & 0 deletions samples/connectivity/audio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Connectivity samples

> Audio Manager Sample Complete
## License

```
Copyright 2022 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
https://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.
```

9 changes: 9 additions & 0 deletions samples/connectivity/audio/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apply from: "$rootDir/gradle/sample-build.gradle"

android {
namespace 'com.example.platform.connectivity.audio'
}

dependencies {
// Add samples specific dependencies
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package com.example.platform.connectivity.audio

import android.content.Context
import android.media.AudioDeviceInfo
import android.media.AudioManager
import android.widget.Toast
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Icon
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.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.example.platform.connectivity.audio.datasource.PlatformAudioSource
import com.example.platform.connectivity.audio.viewmodel.AudioDeviceUI
import com.example.platform.connectivity.audio.viewmodel.AudioDeviceViewModel
import com.example.platform.connectivity.audio.viewmodel.getDeviceName
import com.example.platform.connectivity.audio.viewmodel.getStatusColor
import com.google.android.catalog.framework.annotations.Sample

@Sample(
name = "Audio Manager",
description = "This sample will show you how get all audio sources and set an audio device. Covers Bluetooth, LEA, Wired and internal speakers"
)
@Composable
fun AudioSample() {
val context = LocalContext.current

val audioManager: AudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val viewModel = AudioDeviceViewModel(PlatformAudioSource(audioManager))
AudioSampleScreen(viewModel)
}

@Composable
fun AudioSampleScreen(viewModel: AudioDeviceViewModel) {
val uiStateAvailableDevices by viewModel.availableDeviceUiState.collectAsState()
val uiStateActiveDevice by viewModel.activeDeviceUiState.collectAsState()
val uiStateErrorMessage by viewModel.errorUiState.collectAsState()

uiStateErrorMessage?.let {
Toast.makeText(LocalContext.current, uiStateErrorMessage, Toast.LENGTH_LONG).show()
viewModel.onErrorMessageShown()
}

Column {
ActiveAudioSource(uiStateActiveDevice)
Text(stringResource(id = R.string.selectdevice),
modifier = Modifier
.padding(8.dp, 12.dp),
style = MaterialTheme.typography.displayMedium)
AvailableDevicesList(uiStateAvailableDevices, viewModel::setAudioDevice)
}
}

@Composable
fun AvailableDevicesList(audioDeviceWidgetUiState: AudioDeviceViewModel.AudioDeviceListUiState, onDeviceSelected: (AudioDeviceInfo) -> Unit){
when(audioDeviceWidgetUiState){
AudioDeviceViewModel.AudioDeviceListUiState.Loading -> {}
is AudioDeviceViewModel.AudioDeviceListUiState.Success -> {
ListOfAudioDevices(audioDeviceWidgetUiState.audioDevices, onDeviceSelected)
}
}
}

@Composable
fun ActiveAudioSource(activeAudioDeviceUiState: AudioDeviceViewModel.ActiveAudioDeviceUiState) =
when(activeAudioDeviceUiState){
AudioDeviceViewModel.ActiveAudioDeviceUiState.NotActive -> {
ActiveAudioSource(stringResource(id = R.string.nodevice), "", R.drawable.phone_icon)
}
is AudioDeviceViewModel.ActiveAudioDeviceUiState.OnActiveDevice -> {
ActiveAudioSource(stringResource(id = R.string.connected),
activeAudioDeviceUiState.audioDevice.getDeviceName(),
activeAudioDeviceUiState.audioDevice.resIconId)
}
}

/**
* Shows user the active audio source
*/
@Composable
fun ActiveAudioSource(title: String, subTitle: String, resId: Int){
Row(verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.padding(12.dp, 24.dp)){
Icon(painterResource(resId),
contentDescription = null,
tint = MaterialTheme.colorScheme.primary)
Column {
Text(title, modifier = Modifier.padding(8.dp, 0.dp),
color = MaterialTheme.colorScheme.primary,
style = MaterialTheme.typography.headlineMedium)
Text(subTitle, modifier = Modifier.padding(8.dp, 0.dp),
color = MaterialTheme.colorScheme.primary,
style = MaterialTheme.typography.headlineSmall)
}
}
}

/**
* Build an list of Audio Devices we can connect to
*/
@Composable
fun ListOfAudioDevices(devices: List<AudioDeviceUI>, onDeviceSelected: (AudioDeviceInfo) -> Unit) {
LazyColumn() {
items(devices) { item ->
AudioItem(audioDevice = item, onDeviceSelected = onDeviceSelected)
}
}
}

/**
* Displays the audio device with Icon and Text
*/
@Composable
fun AudioItem(
audioDevice : AudioDeviceUI,
onDeviceSelected: (AudioDeviceInfo) -> Unit
){
Box(modifier = Modifier
.fillMaxWidth()
.clickable { onDeviceSelected(audioDevice.audioDeviceInfo) }){
Row(modifier = Modifier.padding(12.dp, 8.dp),
verticalAlignment = Alignment.CenterVertically,) {
Icon(painterResource(audioDevice.resIconId),
contentDescription = null,
tint = Color.White)
Column {
Text(audioDevice.getDeviceName(),
modifier = Modifier
.padding(8.dp, 0.dp),
audioDevice.getStatusColor())
Text("",
modifier = Modifier.
padding(8.dp, 0.dp),
audioDevice.getStatusColor())
}
}
}
}
Loading

0 comments on commit 1b3aecc

Please sign in to comment.