From 842e12a58da3f3d3b5acf2535f4e214e7829b299 Mon Sep 17 00:00:00 2001 From: Ivan Zakharov <79067180651@ya.ru> Date: Thu, 17 Oct 2019 16:19:04 +0300 Subject: [PATCH 1/2] Update gradle and libs --- build.gradle | 14 +++++--------- fotoapparat/build.gradle | 2 +- .../coroutines/AwaitBroadcastChannel.kt | 12 +++++++++--- gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index 2bde8c78..8e5ea8c3 100644 --- a/build.gradle +++ b/build.gradle @@ -9,8 +9,7 @@ subprojects { buildscript { ext { versions = [ - gradle : '4.10.2', - kotlin : '1.3.0', + kotlin : '1.3.50', code : 1, name : '1.0.0', sdk : [ @@ -19,13 +18,13 @@ buildscript { ], android: [ buildTools: '28.0.3', - appcompat : '1.0.1', - annotation : '1.0.0', + appcompat : '1.1.0', + annotation : '1.1.0', exifinterface : '1.0.0' ], rx : [ rxJava1: '1.3.8', - rxJava2: '2.2.3' + rxJava2: '2.2.12' ], test : [ junit : '4.12', @@ -38,7 +37,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:3.5.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}" classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' @@ -57,6 +56,3 @@ task clean(type: Delete) { delete rootProject.buildDir } -task wrapper(type: Wrapper) { - gradleVersion = versions.gradle -} diff --git a/fotoapparat/build.gradle b/fotoapparat/build.gradle index d2065b93..628043e7 100644 --- a/fotoapparat/build.gradle +++ b/fotoapparat/build.gradle @@ -32,7 +32,7 @@ dependencies { implementation "androidx.annotation:annotation:${versions.android.annotation}" implementation "androidx.exifinterface:exifinterface:${versions.android.exifinterface}" implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0' testImplementation "junit:junit:${versions.test.junit}" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:${versions.kotlin}" testImplementation "org.mockito:mockito-core:${versions.test.mockito}" diff --git a/fotoapparat/src/main/java/io/fotoapparat/coroutines/AwaitBroadcastChannel.kt b/fotoapparat/src/main/java/io/fotoapparat/coroutines/AwaitBroadcastChannel.kt index 0fbc471e..f22bbaf1 100644 --- a/fotoapparat/src/main/java/io/fotoapparat/coroutines/AwaitBroadcastChannel.kt +++ b/fotoapparat/src/main/java/io/fotoapparat/coroutines/AwaitBroadcastChannel.kt @@ -1,13 +1,13 @@ package io.fotoapparat.coroutines -import kotlinx.coroutines.CompletableDeferred -import kotlinx.coroutines.Deferred +import kotlinx.coroutines.* import kotlinx.coroutines.channels.BroadcastChannel import kotlinx.coroutines.channels.ConflatedBroadcastChannel /** * A [ConflatedBroadcastChannel] which exposes a [getValue] which will [await] for at least one value. */ +@ExperimentalCoroutinesApi internal class AwaitBroadcastChannel( private val channel: ConflatedBroadcastChannel = ConflatedBroadcastChannel(), private val deferred: CompletableDeferred = CompletableDeferred() @@ -31,7 +31,13 @@ internal class AwaitBroadcastChannel( channel.send(element) } + override fun cancel(cause: CancellationException?) { + channel.cancel(cause) + deferred.cancel(cause) + } + override fun cancel(cause: Throwable?): Boolean { - return channel.cancel(cause) && deferred.cancel(cause) + deferred.cancel(cause?.message ?:"", cause) + return channel.close(cause) } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d76b502e..d757f3d3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip From 7cbeb1a872b1632262e9c14857e911f795f53cb3 Mon Sep 17 00:00:00 2001 From: Ivan Zakharov <79067180651@ya.ru> Date: Thu, 17 Oct 2019 16:16:30 +0300 Subject: [PATCH 2/2] Added the ability to take photo without immediately restart preview --- .../main/java/io/fotoapparat/Fotoapparat.kt | 47 ++++++++++++++++++- .../io/fotoapparat/result/PendingResult.kt | 1 + .../routine/photo/TakePhotoRoutine.kt | 19 ++++++++ .../routine/photo/TakePhotoRoutineTest.kt | 4 +- 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/fotoapparat/src/main/java/io/fotoapparat/Fotoapparat.kt b/fotoapparat/src/main/java/io/fotoapparat/Fotoapparat.kt index 3a0138a2..10a5a34c 100644 --- a/fotoapparat/src/main/java/io/fotoapparat/Fotoapparat.kt +++ b/fotoapparat/src/main/java/io/fotoapparat/Fotoapparat.kt @@ -22,7 +22,10 @@ import io.fotoapparat.routine.camera.updateDeviceConfiguration import io.fotoapparat.routine.capability.getCapabilities import io.fotoapparat.routine.focus.focus import io.fotoapparat.routine.parameter.getCurrentParameters +import io.fotoapparat.routine.photo.startPreview +import io.fotoapparat.routine.photo.stopPreview import io.fotoapparat.routine.photo.takePhoto +import io.fotoapparat.routine.photo.takePhotoRestartPreview import io.fotoapparat.routine.zoom.updateZoomLevel import io.fotoapparat.selector.* import io.fotoapparat.view.CameraRenderer @@ -113,15 +116,57 @@ class Fotoapparat */ fun takePicture(): PhotoResult { logger.recordMethod() + return takePicture(restartPreview = true) + } + + /** + * Takes picture with ability to disable automatically restart preview, returns immediately. + * + * @return [PhotoResult] which will deliver result asynchronously. + */ + fun takePicture(restartPreview: Boolean): PhotoResult { + logger.recordMethod() val future = executor.execute(Operation( cancellable = true, - function = device::takePhoto + function = if(restartPreview) device::takePhotoRestartPreview else device::takePhoto )) return PhotoResult.fromFuture(future, logger) } + /** + * Start preview manually, returns immediately. + * + * @return [BooleanResult] which will deliver result asynchronously. + */ + fun startPreview(): BooleanResult { + logger.recordMethod() + + val future = executor.execute(Operation( + cancellable = true, + function = device::startPreview + )) + + return PendingResult.fromFuture(future, logger) + } + + /** + * Stop preview manually, returns immediately. + * + * @return [BooleanResult] which will deliver result asynchronously. + */ + fun stopPreview(): BooleanResult { + logger.recordMethod() + + val future = executor.execute(Operation( + cancellable = true, + function = device::stopPreview + )) + + return PendingResult.fromFuture(future, logger) + } + /** * Provides camera capabilities asynchronously, returns immediately. * diff --git a/fotoapparat/src/main/java/io/fotoapparat/result/PendingResult.kt b/fotoapparat/src/main/java/io/fotoapparat/result/PendingResult.kt index a2e2daf1..6b14b39f 100644 --- a/fotoapparat/src/main/java/io/fotoapparat/result/PendingResult.kt +++ b/fotoapparat/src/main/java/io/fotoapparat/result/PendingResult.kt @@ -125,4 +125,5 @@ private fun notifyOnMainThread(function: () -> Unit) { typealias CapabilitiesResult = PendingResult typealias ParametersResult = PendingResult +typealias BooleanResult = PendingResult diff --git a/fotoapparat/src/main/java/io/fotoapparat/routine/photo/TakePhotoRoutine.kt b/fotoapparat/src/main/java/io/fotoapparat/routine/photo/TakePhotoRoutine.kt index 3342b3aa..db4b172d 100644 --- a/fotoapparat/src/main/java/io/fotoapparat/routine/photo/TakePhotoRoutine.kt +++ b/fotoapparat/src/main/java/io/fotoapparat/routine/photo/TakePhotoRoutine.kt @@ -9,8 +9,14 @@ import kotlinx.coroutines.runBlocking /** * Takes a photo. */ + internal fun Device.takePhoto(): Photo = runBlocking { val cameraDevice = awaitSelectedCamera() + cameraDevice.takePhoto() +} + +internal fun Device.takePhotoRestartPreview(): Photo = runBlocking { + val cameraDevice = awaitSelectedCamera() cameraDevice.takePhoto().also { cameraDevice.startPreviewSafely() @@ -23,3 +29,16 @@ private fun CameraDevice.startPreviewSafely() { } catch (ignore: CameraException) { } } + +internal fun Device.startPreview(): Boolean = runBlocking { + val cameraDevice = awaitSelectedCamera() + cameraDevice.startPreview() + true +} + +internal fun Device.stopPreview(): Boolean = runBlocking { + val cameraDevice = awaitSelectedCamera() + cameraDevice.stopPreview() + true +} + diff --git a/fotoapparat/src/test/java/io/fotoapparat/routine/photo/TakePhotoRoutineTest.kt b/fotoapparat/src/test/java/io/fotoapparat/routine/photo/TakePhotoRoutineTest.kt index eff9a1ba..b0a8cd55 100644 --- a/fotoapparat/src/test/java/io/fotoapparat/routine/photo/TakePhotoRoutineTest.kt +++ b/fotoapparat/src/test/java/io/fotoapparat/routine/photo/TakePhotoRoutineTest.kt @@ -30,7 +30,7 @@ internal class TakePhotoRoutineTest { cameraDevice.takePhoto() willReturn photo // When - val result = device.takePhoto() + val result = device.takePhotoRestartPreview() // Then val inOrder = inOrder(cameraDevice) @@ -54,7 +54,7 @@ internal class TakePhotoRoutineTest { cameraDevice.startPreview() willThrow CameraException("test") // When - val result = device.takePhoto() + val result = device.takePhotoRestartPreview() // Then val inOrder = inOrder(cameraDevice)