Browse Source

Workaround for Android emulator camera on some hardware (#2955)

pull/2962/head
dima.avdeev 2 years ago committed by GitHub
parent
commit
b87868d75e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      experimental/examples/imageviewer/shared/build.gradle.kts
  2. 47
      experimental/examples/imageviewer/shared/src/androidMain/kotlin/example/imageviewer/view/CameraView.android.kt
  3. BIN
      experimental/examples/imageviewer/shared/src/commonMain/resources/android-emulator-photo.jpg

10
experimental/examples/imageviewer/shared/build.gradle.kts

@ -43,12 +43,12 @@ kotlin {
} }
val androidMain by getting { val androidMain by getting {
dependencies { 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.appcompat:appcompat:1.6.1")
api("androidx.core:core-ktx:1.9.0") api("androidx.core:core-ktx:1.9.0")
implementation("androidx.camera:camera-camera2:1.2.1") implementation("androidx.camera:camera-camera2:1.2.2")
implementation("androidx.camera:camera-lifecycle:1.2.1") implementation("androidx.camera:camera-lifecycle:1.2.2")
implementation("androidx.camera:camera-view:1.2.1") implementation("androidx.camera:camera-view:1.2.2")
implementation("com.google.accompanist:accompanist-permissions:0.29.2-rc") 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-maps:18.1.0")
implementation("com.google.android.gms:play-services-location:21.0.1") implementation("com.google.android.gms:play-services-location:21.0.1")
@ -57,7 +57,7 @@ kotlin {
} }
val iosMain by getting { val iosMain by getting {
dependencies { 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") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.0-Beta")
} }
} }

47
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.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -32,6 +33,10 @@ import example.imageviewer.*
import example.imageviewer.model.GpsPosition import example.imageviewer.model.GpsPosition
import example.imageviewer.model.PictureData import example.imageviewer.model.PictureData
import example.imageviewer.model.createCameraPictureData 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.nio.ByteBuffer
import java.util.* import java.util.*
import java.util.concurrent.Executors import java.util.concurrent.Executors
@ -62,6 +67,7 @@ internal actual fun CameraView(
} }
} }
@OptIn(ExperimentalResourceApi::class)
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
@Composable @Composable
private fun CameraWithGrantedPermission( private fun CameraWithGrantedPermission(
@ -77,6 +83,7 @@ private fun CameraWithGrantedPermission(
val cameraSelector = CameraSelector.Builder() val cameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK) .requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build() .build()
val viewScope = rememberCoroutineScope()
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
val cameraProvider = suspendCoroutine<ProcessCameraProvider> { continuation -> val cameraProvider = suspendCoroutine<ProcessCameraProvider> { continuation ->
@ -102,12 +109,7 @@ private fun CameraWithGrantedPermission(
Button( Button(
enabled = !capturePhotoStarted, enabled = !capturePhotoStarted,
onClick = { onClick = {
capturePhotoStarted = true fun addLocationInfoAndReturnResult(imageBitmap: ImageBitmap) {
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) { fun sendToStorage(gpsPosition: GpsPosition) {
onCapture( onCapture(
createCameraPictureData( createCameraPictureData(
@ -119,21 +121,38 @@ private fun CameraWithGrantedPermission(
) )
capturePhotoStarted = false capturePhotoStarted = false
} }
val lastLocation: Task<Location> =
LocationServices.getFusedLocationProviderClient(context) LocationServices.getFusedLocationProviderClient(context)
.getCurrentLocation( .getCurrentLocation(CurrentLocationRequest.Builder().build(), null)
CurrentLocationRequest.Builder().build(), .apply {
null addOnSuccessListener {
)
lastLocation.addOnSuccessListener {
sendToStorage(GpsPosition(it.latitude, it.longitude)) sendToStorage(GpsPosition(it.latitude, it.longitude))
} }
lastLocation.addOnFailureListener { addOnFailureListener {
sendToStorage(GpsPosition(0.0, 0.0)) 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()
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) Text(LocalLocalization.current.takePhoto, color = Color.White)
} }

BIN
experimental/examples/imageviewer/shared/src/commonMain/resources/android-emulator-photo.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Loading…
Cancel
Save