From 86e7db965ff9f0a08a078bc3027c6cd9cc08bf95 Mon Sep 17 00:00:00 2001 From: Kohei Date: Wed, 18 Feb 2026 21:35:36 +0900 Subject: [PATCH] fix: add runtime camera permission request to prevent SecurityException crash Co-Authored-By: Claude Opus 4.6 --- .../android/feature/chat/screen/ChatScreen.kt | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/android/feature/chat/src/main/java/io/picoclaw/android/feature/chat/screen/ChatScreen.kt b/android/feature/chat/src/main/java/io/picoclaw/android/feature/chat/screen/ChatScreen.kt index 47d0cf206..f903d8e12 100644 --- a/android/feature/chat/src/main/java/io/picoclaw/android/feature/chat/screen/ChatScreen.kt +++ b/android/feature/chat/src/main/java/io/picoclaw/android/feature/chat/screen/ChatScreen.kt @@ -1,8 +1,11 @@ package io.picoclaw.android.feature.chat.screen +import android.Manifest +import android.content.pm.PackageManager import android.net.Uri import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.content.ContextCompat import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -55,6 +58,24 @@ fun ChatScreen( } } + val launchCamera = { + val imagesDir = File(context.cacheDir, "images").apply { mkdirs() } + val imageFile = File(imagesDir, "camera_${System.currentTimeMillis()}.jpg") + val uri = FileProvider.getUriForFile( + context, + "${context.packageName}.fileprovider", + imageFile + ) + cameraImageUri = uri + cameraLauncher.launch(uri) + } + + val cameraPermissionLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.RequestPermission() + ) { granted -> + if (granted) launchCamera() + } + val galleryLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.GetContent() ) { uri -> @@ -107,15 +128,13 @@ fun ChatScreen( onTextChanged = { viewModel.onEvent(ChatEvent.OnInputChanged(it)) }, onSendClick = { viewModel.onEvent(ChatEvent.OnSendClick) }, onCameraClick = { - val imagesDir = File(context.cacheDir, "images").apply { mkdirs() } - val imageFile = File(imagesDir, "camera_${System.currentTimeMillis()}.jpg") - val uri = FileProvider.getUriForFile( - context, - "${context.packageName}.fileprovider", - imageFile - ) - cameraImageUri = uri - cameraLauncher.launch(uri) + if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) + == PackageManager.PERMISSION_GRANTED + ) { + launchCamera() + } else { + cameraPermissionLauncher.launch(Manifest.permission.CAMERA) + } }, onGalleryClick = { galleryLauncher.launch("image/*")