diff --git a/experimental/examples/imageviewer/shared/build.gradle.kts b/experimental/examples/imageviewer/shared/build.gradle.kts index 4a44c50b45..6826d46797 100755 --- a/experimental/examples/imageviewer/shared/build.gradle.kts +++ b/experimental/examples/imageviewer/shared/build.gradle.kts @@ -43,12 +43,12 @@ kotlin { } val androidMain by getting { dependencies { - api("androidx.activity:activity-compose:1.6.1") + api("androidx.activity:activity-compose:1.7.0") api("androidx.appcompat:appcompat:1.6.1") api("androidx.core:core-ktx:1.9.0") - implementation("androidx.camera:camera-camera2:1.2.1") - implementation("androidx.camera:camera-lifecycle:1.2.1") - implementation("androidx.camera:camera-view:1.2.1") + implementation("androidx.camera:camera-camera2:1.2.2") + implementation("androidx.camera:camera-lifecycle:1.2.2") + implementation("androidx.camera:camera-view:1.2.2") implementation("com.google.accompanist:accompanist-permissions:0.29.2-rc") implementation("com.google.android.gms:play-services-maps:18.1.0") implementation("com.google.android.gms:play-services-location:21.0.1") @@ -57,7 +57,7 @@ kotlin { } val iosMain by getting { dependencies { - // TODO: update coroutines (or remove, if 1.8.0 will be presented in Compose) + // Kotlin Coroutines 1.7.0 contains Dispatchers.IO implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.0-Beta") } } diff --git a/experimental/examples/imageviewer/shared/src/androidMain/kotlin/example/imageviewer/view/CameraView.android.kt b/experimental/examples/imageviewer/shared/src/androidMain/kotlin/example/imageviewer/view/CameraView.android.kt index 0f36132941..fda53a57d5 100644 --- a/experimental/examples/imageviewer/shared/src/androidMain/kotlin/example/imageviewer/view/CameraView.android.kt +++ b/experimental/examples/imageviewer/shared/src/androidMain/kotlin/example/imageviewer/view/CameraView.android.kt @@ -19,6 +19,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.unit.dp @@ -32,6 +33,10 @@ import example.imageviewer.* import example.imageviewer.model.GpsPosition import example.imageviewer.model.PictureData import example.imageviewer.model.createCameraPictureData +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import org.jetbrains.compose.resources.ExperimentalResourceApi +import org.jetbrains.compose.resources.resource import java.nio.ByteBuffer import java.util.* import java.util.concurrent.Executors @@ -62,6 +67,7 @@ internal actual fun CameraView( } } +@OptIn(ExperimentalResourceApi::class) @SuppressLint("MissingPermission") @Composable private fun CameraWithGrantedPermission( @@ -77,6 +83,7 @@ private fun CameraWithGrantedPermission( val cameraSelector = CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK) .build() + val viewScope = rememberCoroutineScope() LaunchedEffect(Unit) { val cameraProvider = suspendCoroutine { continuation -> @@ -102,38 +109,50 @@ private fun CameraWithGrantedPermission( Button( enabled = !capturePhotoStarted, onClick = { + fun addLocationInfoAndReturnResult(imageBitmap: ImageBitmap) { + fun sendToStorage(gpsPosition: GpsPosition) { + onCapture( + createCameraPictureData( + name = nameAndDescription.name, + description = nameAndDescription.description, + gps = gpsPosition + ), + AndroidStorableImage(imageBitmap) + ) + capturePhotoStarted = false + } + LocationServices.getFusedLocationProviderClient(context) + .getCurrentLocation(CurrentLocationRequest.Builder().build(), null) + .apply { + addOnSuccessListener { + sendToStorage(GpsPosition(it.latitude, it.longitude)) + } + addOnFailureListener { + sendToStorage(GpsPosition(0.0, 0.0)) + } + } + } + capturePhotoStarted = true imageCapture.takePicture(executor, object : OnImageCapturedCallback() { override fun onCaptureSuccess(image: ImageProxy) { val byteArray: ByteArray = image.planes[0].buffer.toByteArray() val imageBitmap = byteArray.toImageBitmap() image.close() - fun sendToStorage(gpsPosition: GpsPosition) { - onCapture( - createCameraPictureData( - name = nameAndDescription.name, - description = nameAndDescription.description, - gps = gpsPosition - ), - AndroidStorableImage(imageBitmap) - ) - capturePhotoStarted = false - } - - val lastLocation: Task = - LocationServices.getFusedLocationProviderClient(context) - .getCurrentLocation( - CurrentLocationRequest.Builder().build(), - null - ) - lastLocation.addOnSuccessListener { - sendToStorage(GpsPosition(it.latitude, it.longitude)) - } - lastLocation.addOnFailureListener { - sendToStorage(GpsPosition(0.0, 0.0)) - } + addLocationInfoAndReturnResult(imageBitmap) } }) + viewScope.launch { + // TODO: There is a known issue with Android emulator + // https://partnerissuetracker.corp.google.com/issues/161034252 + // After 5 seconds delay, let's assume that the bug appears and publish a prepared photo + delay(5000) + if (capturePhotoStarted) { + addLocationInfoAndReturnResult( + resource("android-emulator-photo.jpg").readBytes().toImageBitmap() + ) + } + } }) { Text(LocalLocalization.current.takePhoto, color = Color.White) } diff --git a/experimental/examples/imageviewer/shared/src/commonMain/resources/android-emulator-photo.jpg b/experimental/examples/imageviewer/shared/src/commonMain/resources/android-emulator-photo.jpg new file mode 100644 index 0000000000..0d848dd2e8 Binary files /dev/null and b/experimental/examples/imageviewer/shared/src/commonMain/resources/android-emulator-photo.jpg differ