Skip to content

Commit dba04b3

Browse files
committed
Permissions correctly requested
1 parent 1d0a1ca commit dba04b3

File tree

4 files changed

+69
-28
lines changed

4 files changed

+69
-28
lines changed

firebase-ai/app/src/main/java/com/google/firebase/quickstart/ai/MainActivity.kt

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,7 @@ class MainActivity : ComponentActivity() {
4444
@OptIn(ExperimentalMaterial3Api::class)
4545
override fun onCreate(savedInstanceState: Bundle?) {
4646
super.onCreate(savedInstanceState)
47-
if(ContextCompat.checkSelfPermission(this,
48-
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
49-
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.RECORD_AUDIO), 1)
50-
}
51-
if(ContextCompat.checkSelfPermission(this,
52-
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
53-
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), 1)
54-
}
47+
5548
enableEdgeToEdge()
5649
catImage = BitmapFactory.decodeResource(applicationContext.resources, R.drawable.cat)
5750
setContent {

firebase-ai/app/src/main/java/com/google/firebase/quickstart/ai/feature/live/BidiViewModel.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.google.firebase.quickstart.ai.feature.media.imagen
1+
package com.google.firebase.quickstart.ai.feature.live
22

33
import android.Manifest
44
import android.graphics.Bitmap
@@ -73,7 +73,7 @@ class BidiViewModel(
7373
return FunctionResponsePart("fetchWeather", response, fetchWeatherCall.id)
7474
}
7575

76-
@RequiresPermission(Manifest.permission.RECORD_AUDIO)
76+
7777
suspend fun startConversation() {
7878
liveSession.startAudioConversation(::handler)
7979
}
@@ -82,9 +82,7 @@ class BidiViewModel(
8282
liveSession.stopAudioConversation()
8383
}
8484

85-
// ... (imports and class definition)
86-
87-
@RequiresPermission(android.Manifest.permission.RECORD_AUDIO)
85+
8886
fun sendVideoFrame(frame: Bitmap) {
8987
viewModelScope.launch {
9088
// Directly compress the Bitmap to a ByteArray

firebase-ai/app/src/main/java/com/google/firebase/quickstart/ai/feature/live/StreamRealtimeScreen.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ import androidx.compose.runtime.remember
3232
import androidx.compose.runtime.mutableStateOf
3333

3434
import androidx.lifecycle.viewmodel.compose.viewModel
35-
import com.google.firebase.quickstart.ai.feature.media.imagen.BidiViewModel
36-
import com.google.firebase.quickstart.ai.feature.media.imagen.ImagenViewModel
3735
import kotlinx.coroutines.CoroutineScope
3836
import kotlinx.coroutines.Dispatchers
3937
import kotlinx.coroutines.launch
Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,31 @@
11
package com.google.firebase.quickstart.ai.feature.live
22

33
import android.Manifest
4+
import android.content.Context
5+
import android.content.pm.PackageManager
6+
import androidx.activity.compose.rememberLauncherForActivityResult
7+
import androidx.activity.result.contract.ActivityResultContracts
48
import androidx.annotation.RequiresPermission
59
import androidx.compose.foundation.layout.Box
10+
import androidx.compose.foundation.layout.Column
611
import androidx.compose.foundation.layout.fillMaxHeight
712
import androidx.compose.foundation.layout.fillMaxSize
813
import androidx.compose.material3.MaterialTheme
914
import androidx.compose.material3.Surface
15+
import androidx.compose.material3.Text
1016
import androidx.compose.runtime.Composable
1117
import androidx.compose.runtime.DisposableEffect
18+
import androidx.compose.runtime.LaunchedEffect
19+
import androidx.compose.runtime.getValue
20+
import androidx.compose.runtime.mutableStateOf
21+
import androidx.compose.runtime.remember
1222
import androidx.compose.runtime.rememberCoroutineScope
23+
import androidx.compose.runtime.setValue
1324
import androidx.compose.ui.Modifier
25+
import androidx.compose.ui.platform.LocalContext
26+
import androidx.core.content.ContextCompat
1427
import androidx.lifecycle.viewmodel.compose.viewModel
15-
import com.google.firebase.quickstart.ai.feature.media.imagen.BidiViewModel
28+
import com.google.firebase.quickstart.ai.feature.live.BidiViewModel
1629
import kotlinx.coroutines.launch
1730
import kotlinx.serialization.Serializable
1831

@@ -26,9 +39,42 @@ fun StreamRealtimeVideoScreen(bidiView: BidiViewModel = viewModel<BidiViewModel>
2639
MaterialTheme.colorScheme.background
2740

2841
val scope = rememberCoroutineScope()
29-
DisposableEffect(Unit) {
30-
scope.launch {
31-
bidiView.startConversation()
42+
43+
val context = LocalContext.current
44+
var hasPermissions by remember {
45+
mutableStateOf(
46+
ContextCompat.checkSelfPermission(
47+
context,
48+
Manifest.permission.CAMERA
49+
) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(
50+
context,
51+
Manifest.permission.RECORD_AUDIO
52+
) == PackageManager.PERMISSION_GRANTED
53+
)
54+
}
55+
56+
val launcher = rememberLauncherForActivityResult(
57+
ActivityResultContracts.RequestMultiplePermissions()
58+
) { permissions ->
59+
hasPermissions = permissions.values.all { it }
60+
}
61+
62+
LaunchedEffect(Unit) {
63+
if (!hasPermissions) {
64+
launcher.launch(
65+
arrayOf(
66+
Manifest.permission.CAMERA,
67+
Manifest.permission.RECORD_AUDIO
68+
)
69+
)
70+
}
71+
}
72+
73+
DisposableEffect(hasPermissions) {
74+
if (hasPermissions) {
75+
scope.launch {
76+
bidiView.startConversation()
77+
}
3278
}
3379
onDispose {
3480
bidiView.endConversation()
@@ -39,16 +85,22 @@ fun StreamRealtimeVideoScreen(bidiView: BidiViewModel = viewModel<BidiViewModel>
3985
modifier = Modifier.fillMaxSize(),
4086
color = backgroundColor
4187
) {
42-
Box(
43-
modifier = Modifier
44-
.fillMaxSize()
45-
) {
46-
CameraView(
47-
modifier = Modifier.fillMaxHeight(0.5f),
48-
onFrameCaptured = { bitmap ->
49-
bidiView.sendVideoFrame(bitmap)
88+
Column(modifier = Modifier.fillMaxSize()) {
89+
if (hasPermissions) {
90+
Box(
91+
modifier = Modifier
92+
.fillMaxSize()
93+
) {
94+
CameraView(
95+
modifier = Modifier.fillMaxHeight(0.5f),
96+
onFrameCaptured = { bitmap ->
97+
bidiView.sendVideoFrame(bitmap)
98+
}
99+
)
50100
}
51-
)
101+
} else {
102+
Text("Camera and audio permissions are required to use this feature.")
103+
}
52104
}
53105
}
54106
}

0 commit comments

Comments
 (0)