1 /*
<lambda>null2 * Copyright 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package androidx.core.telecom.test.ui.calling
18
19 import androidx.compose.foundation.layout.Column
20 import androidx.compose.foundation.layout.Row
21 import androidx.compose.foundation.layout.Spacer
22 import androidx.compose.foundation.layout.fillMaxWidth
23 import androidx.compose.foundation.layout.padding
24 import androidx.compose.material3.Card
25 import androidx.compose.material3.CardDefaults
26 import androidx.compose.material3.ElevatedCard
27 import androidx.compose.material3.HorizontalDivider
28 import androidx.compose.material3.Icon
29 import androidx.compose.material3.MaterialTheme
30 import androidx.compose.material3.OutlinedCard
31 import androidx.compose.material3.Text
32 import androidx.compose.runtime.Composable
33 import androidx.compose.runtime.getValue
34 import androidx.compose.runtime.mutableStateOf
35 import androidx.compose.runtime.remember
36 import androidx.compose.runtime.rememberCoroutineScope
37 import androidx.compose.runtime.setValue
38 import androidx.compose.ui.Alignment
39 import androidx.compose.ui.Modifier
40 import androidx.compose.ui.res.painterResource
41 import androidx.compose.ui.tooling.preview.Preview
42 import androidx.compose.ui.tooling.preview.PreviewParameter
43 import androidx.compose.ui.tooling.preview.Wallpapers
44 import androidx.compose.ui.unit.dp
45 import androidx.compose.ui.window.Dialog
46 import androidx.core.telecom.test.R
47 import androidx.core.telecom.test.services.AudioRoute
48 import androidx.core.telecom.test.ui.calling.OngoingCallsViewModel.Companion.UnknownAudioUiState
49 import androidx.lifecycle.compose.collectAsStateWithLifecycle
50 import kotlinx.coroutines.launch
51
52 /**
53 * The dialog that pops up on the screen when the user tries to change the audio route of the
54 * device.
55 */
56 @Composable
57 fun AudioRoutePickerDialog(
58 ongoingCallsViewModel: OngoingCallsViewModel,
59 onDismissDialog: () -> Unit,
60 onChangeAudioRoute: suspend (String) -> Unit
61 ) {
62 val currentAudioRoute: AudioEndpointUiState by
63 ongoingCallsViewModel
64 .streamCurrentEndpointAudioData()
65 .collectAsStateWithLifecycle(UnknownAudioUiState)
66 val availableAudioRoutes: List<AudioEndpointUiState> by
67 ongoingCallsViewModel
68 .streamAvailableEndpointAudioData()
69 .collectAsStateWithLifecycle(emptyList())
70 Dialog(onDismissRequest = onDismissDialog) {
71 Card(
72 modifier = Modifier.fillMaxWidth(),
73 colors =
74 CardDefaults.cardColors(
75 containerColor = MaterialTheme.colorScheme.surfaceContainerHigh
76 )
77 ) {
78 Column(modifier = Modifier.padding(6.dp)) {
79 Text("Current Audio Route")
80 Spacer(modifier = Modifier.padding(vertical = 3.dp))
81 OutlinedCard { AudioRouteContent(currentAudioRoute) }
82 HorizontalDivider(modifier = Modifier.padding(vertical = 6.dp))
83 Text("Available Audio Routes")
84 val available = availableAudioRoutes.filter { it.id != currentAudioRoute.id }
85 if (available.isEmpty()) {
86 Text(modifier = Modifier.padding(6.dp), text = "<None Available>")
87 } else {
88 available.forEach { route ->
89 ClickableAudioRouteContent(route, onChangeAudioRoute)
90 }
91 }
92 }
93 }
94 }
95 }
96
97 @Preview(showBackground = true, wallpaper = Wallpapers.BLUE_DOMINATED_EXAMPLE)
98 @Composable
ClickableAudioRouteContentnull99 fun ClickableAudioRouteContent(
100 @PreviewParameter(UserPreviewEndpointProvider::class) audioRoute: AudioEndpointUiState,
101 onChangeAudioRoute: suspend (String) -> Unit = {}
102 ) {
103 val coroutineScope = rememberCoroutineScope()
<lambda>null104 var isLoading: Boolean by remember { mutableStateOf(false) }
105 ElevatedCard(
106 enabled = !isLoading,
<lambda>null107 onClick = {
108 coroutineScope.launch {
109 isLoading = true
110 onChangeAudioRoute(audioRoute.id)
111 isLoading = false
112 }
113 }
<lambda>null114 ) {
115 AudioRouteContent(audioRoute)
116 }
117 }
118
119 @Composable
AudioRouteContentnull120 fun AudioRouteContent(audioRoute: AudioEndpointUiState) {
121 Row(
122 modifier = Modifier.fillMaxWidth().padding(6.dp),
123 verticalAlignment = Alignment.CenterVertically
124 ) {
125 Icon(
126 painter = painterResource(getResourceForAudioRoute(audioRoute.audioRoute)),
127 contentDescription = "audio route details"
128 )
129 Spacer(modifier = Modifier.padding(horizontal = 6.dp))
130 Text(audioRoute.name)
131 }
132 }
133
getResourceForAudioRoutenull134 fun getResourceForAudioRoute(audioRoute: AudioRoute): Int {
135 return when (audioRoute) {
136 AudioRoute.UNKNOWN -> R.drawable.phone_in_talk_24px
137 AudioRoute.EARPIECE -> R.drawable.phone_in_talk_24px
138 AudioRoute.SPEAKER -> R.drawable.speaker_phone_24px
139 AudioRoute.BLUETOOTH -> R.drawable.bluetooth_24px
140 AudioRoute.HEADSET -> R.drawable.headset_mic_24px
141 AudioRoute.STREAMING -> R.drawable.cast_24px
142 }
143 }
144