fix passing bitmap thumbnail after IMAGE_CAPTURE intent
- add a new BitmapOutput, returned from the MediaOutputHelper when no output URI is specified in an IMAGE_CAPTURE intent - in this format, take the picture without actually saving it and return the bitmap - this behaviour is consistent with the implementation described in the official Android docs https://developer.android.com/training/camera/photobasics#TaskPhotoView
This commit is contained in:
parent
74e2656831
commit
d5e1d61d02
|
@ -2,18 +2,14 @@ package com.simplemobiletools.camera.activities
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.graphics.Bitmap
|
||||||
import android.hardware.SensorManager
|
import android.hardware.SensorManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.Size
|
import android.view.*
|
||||||
import android.view.KeyEvent
|
|
||||||
import android.view.OrientationEventListener
|
|
||||||
import android.view.View
|
|
||||||
import android.view.Window
|
|
||||||
import android.view.WindowManager
|
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
|
@ -22,38 +18,17 @@ import com.bumptech.glide.request.RequestOptions
|
||||||
import com.simplemobiletools.camera.BuildConfig
|
import com.simplemobiletools.camera.BuildConfig
|
||||||
import com.simplemobiletools.camera.R
|
import com.simplemobiletools.camera.R
|
||||||
import com.simplemobiletools.camera.extensions.config
|
import com.simplemobiletools.camera.extensions.config
|
||||||
import com.simplemobiletools.camera.helpers.FLASH_OFF
|
import com.simplemobiletools.camera.helpers.*
|
||||||
import com.simplemobiletools.camera.helpers.FLASH_ON
|
|
||||||
import com.simplemobiletools.camera.helpers.ORIENT_LANDSCAPE_LEFT
|
|
||||||
import com.simplemobiletools.camera.helpers.ORIENT_LANDSCAPE_RIGHT
|
|
||||||
import com.simplemobiletools.camera.helpers.ORIENT_PORTRAIT
|
|
||||||
import com.simplemobiletools.camera.helpers.PhotoProcessor
|
|
||||||
import com.simplemobiletools.camera.implementations.CameraXInitializer
|
import com.simplemobiletools.camera.implementations.CameraXInitializer
|
||||||
import com.simplemobiletools.camera.implementations.CameraXPreviewListener
|
import com.simplemobiletools.camera.implementations.CameraXPreviewListener
|
||||||
import com.simplemobiletools.camera.implementations.MyCameraImpl
|
import com.simplemobiletools.camera.implementations.MyCameraImpl
|
||||||
import com.simplemobiletools.camera.interfaces.MyPreview
|
import com.simplemobiletools.camera.interfaces.MyPreview
|
||||||
import com.simplemobiletools.camera.views.FocusCircleView
|
import com.simplemobiletools.camera.views.FocusCircleView
|
||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.commons.helpers.BROADCAST_REFRESH_MEDIA
|
import com.simplemobiletools.commons.helpers.*
|
||||||
import com.simplemobiletools.commons.helpers.PERMISSION_CAMERA
|
|
||||||
import com.simplemobiletools.commons.helpers.PERMISSION_RECORD_AUDIO
|
|
||||||
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
|
|
||||||
import com.simplemobiletools.commons.helpers.REFRESH_PATH
|
|
||||||
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
|
|
||||||
import com.simplemobiletools.commons.models.Release
|
import com.simplemobiletools.commons.models.Release
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlinx.android.synthetic.main.activity_main.btn_holder
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
import kotlinx.android.synthetic.main.activity_main.capture_black_screen
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.change_resolution
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.last_photo_video_preview
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.settings
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.shutter
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.toggle_camera
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.toggle_flash
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.toggle_photo_video
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.video_rec_curr_timer
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.preview_view
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.view_holder
|
|
||||||
|
|
||||||
class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, CameraXPreviewListener {
|
class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, CameraXPreviewListener {
|
||||||
private val TAG = "MainActivity"
|
private val TAG = "MainActivity"
|
||||||
|
@ -562,28 +537,35 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMediaCaptured(uri: Uri) {
|
override fun onMediaSaved(uri: Uri) {
|
||||||
loadLastTakenMedia(uri)
|
loadLastTakenMedia(uri)
|
||||||
ensureBackgroundThread {
|
if (isImageCaptureIntent()) {
|
||||||
if (isImageCaptureIntent()) {
|
Intent().apply {
|
||||||
val bitmap = contentResolver.loadThumbnail(uri, Size(30, 30), null)
|
data = uri
|
||||||
Intent().apply {
|
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
data = uri
|
setResult(Activity.RESULT_OK, this)
|
||||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
|
||||||
putExtra("data", bitmap)
|
|
||||||
setResult(Activity.RESULT_OK, this)
|
|
||||||
}
|
|
||||||
Log.w(TAG, "onMediaCaptured: exiting uri=$uri")
|
|
||||||
finish()
|
|
||||||
} else if (isVideoCaptureIntent()) {
|
|
||||||
Intent().apply {
|
|
||||||
data = uri
|
|
||||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
|
||||||
setResult(Activity.RESULT_OK, this)
|
|
||||||
}
|
|
||||||
Log.w(TAG, "onMediaCaptured: video exiting uri=$uri")
|
|
||||||
finish()
|
|
||||||
}
|
}
|
||||||
|
Log.w(TAG, "onMediaCaptured: exiting uri=$uri")
|
||||||
|
finish()
|
||||||
|
} else if (isVideoCaptureIntent()) {
|
||||||
|
Intent().apply {
|
||||||
|
data = uri
|
||||||
|
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
|
setResult(Activity.RESULT_OK, this)
|
||||||
|
}
|
||||||
|
Log.w(TAG, "onMediaCaptured: video exiting uri=$uri")
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onImageCaptured(bitmap: Bitmap) {
|
||||||
|
if (isImageCaptureIntent()) {
|
||||||
|
Intent().apply {
|
||||||
|
putExtra("data", bitmap)
|
||||||
|
setResult(Activity.RESULT_OK, this)
|
||||||
|
}
|
||||||
|
Log.w(TAG, "onImageCaptured: exiting bitmap size=${bitmap.byteCount}")
|
||||||
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.simplemobiletools.camera.extensions
|
||||||
|
|
||||||
|
import androidx.camera.core.ImageProxy
|
||||||
|
|
||||||
|
// Only for JPEG format
|
||||||
|
fun ImageProxy.toJpegByteArray(): ByteArray {
|
||||||
|
val buffer = planes.first().buffer
|
||||||
|
val jpegImageData = ByteArray(buffer.remaining())
|
||||||
|
buffer[jpegImageData]
|
||||||
|
return jpegImageData
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.simplemobiletools.camera.helpers
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.util.Log
|
||||||
|
import kotlin.math.ceil
|
||||||
|
import kotlin.math.floor
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
|
//inspired by https://android.googlesource.com/platform/packages/apps/Camera2/+/refs/heads/master/src/com/android/camera/util/CameraUtil.java#244
|
||||||
|
object BitmapUtils {
|
||||||
|
private const val TAG = "BitmapUtils"
|
||||||
|
private const val INLINE_BITMAP_MAX_PIXEL_NUM = 50 * 1024
|
||||||
|
|
||||||
|
fun makeBitmap(jpegData: ByteArray, maxNumOfPixels: Int = INLINE_BITMAP_MAX_PIXEL_NUM): Bitmap? {
|
||||||
|
return try {
|
||||||
|
val options = BitmapFactory.Options()
|
||||||
|
options.inJustDecodeBounds = true
|
||||||
|
|
||||||
|
BitmapFactory.decodeByteArray(jpegData, 0, jpegData.size, options)
|
||||||
|
|
||||||
|
if (options.mCancel || options.outWidth == -1 || options.outHeight == -1) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
options.inSampleSize = computeSampleSize(options, -1, maxNumOfPixels)
|
||||||
|
options.inJustDecodeBounds = false
|
||||||
|
options.inDither = false
|
||||||
|
options.inPreferredConfig = Bitmap.Config.ARGB_8888
|
||||||
|
BitmapFactory.decodeByteArray(
|
||||||
|
jpegData, 0, jpegData.size,
|
||||||
|
options
|
||||||
|
)
|
||||||
|
} catch (ex: OutOfMemoryError) {
|
||||||
|
Log.e(TAG, "Got oom exception ", ex)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun computeSampleSize(options: BitmapFactory.Options, minSideLength: Int, maxNumOfPixels: Int): Int {
|
||||||
|
val initialSize = computeInitialSampleSize(
|
||||||
|
options, minSideLength,
|
||||||
|
maxNumOfPixels
|
||||||
|
)
|
||||||
|
var roundedSize: Int
|
||||||
|
if (initialSize <= 8) {
|
||||||
|
roundedSize = 1
|
||||||
|
while (roundedSize < initialSize) {
|
||||||
|
roundedSize = roundedSize shl 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
roundedSize = (initialSize + 7) / 8 * 8
|
||||||
|
}
|
||||||
|
return roundedSize
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun computeInitialSampleSize(options: BitmapFactory.Options, minSideLength: Int, maxNumOfPixels: Int): Int {
|
||||||
|
val w = options.outWidth.toDouble()
|
||||||
|
val h = options.outHeight.toDouble()
|
||||||
|
val lowerBound = if (maxNumOfPixels < 0) 1 else ceil(sqrt(w * h / maxNumOfPixels)).toInt()
|
||||||
|
val upperBound = if (minSideLength < 0) 128 else floor(w / minSideLength).coerceAtMost(floor(h / minSideLength)).toInt()
|
||||||
|
if (upperBound < lowerBound) {
|
||||||
|
// return the larger one when there is no overlapping zone.
|
||||||
|
return lowerBound
|
||||||
|
}
|
||||||
|
return if (maxNumOfPixels < 0 && minSideLength < 0) {
|
||||||
|
1
|
||||||
|
} else if (minSideLength < 0) {
|
||||||
|
lowerBound
|
||||||
|
} else {
|
||||||
|
upperBound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,20 +11,7 @@ import com.simplemobiletools.camera.extensions.getOutputMediaFile
|
||||||
import com.simplemobiletools.camera.extensions.getRandomMediaName
|
import com.simplemobiletools.camera.extensions.getRandomMediaName
|
||||||
import com.simplemobiletools.camera.models.MediaOutput
|
import com.simplemobiletools.camera.models.MediaOutput
|
||||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||||
import com.simplemobiletools.commons.extensions.createDocumentUriFromRootTree
|
import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.commons.extensions.createDocumentUriUsingFirstParentTreeUri
|
|
||||||
import com.simplemobiletools.commons.extensions.getAndroidSAFUri
|
|
||||||
import com.simplemobiletools.commons.extensions.getDocumentFile
|
|
||||||
import com.simplemobiletools.commons.extensions.getDoesFilePathExist
|
|
||||||
import com.simplemobiletools.commons.extensions.getFileOutputStreamSync
|
|
||||||
import com.simplemobiletools.commons.extensions.getFilenameFromPath
|
|
||||||
import com.simplemobiletools.commons.extensions.getMimeType
|
|
||||||
import com.simplemobiletools.commons.extensions.hasProperStoredAndroidTreeUri
|
|
||||||
import com.simplemobiletools.commons.extensions.hasProperStoredFirstParentUri
|
|
||||||
import com.simplemobiletools.commons.extensions.hasProperStoredTreeUri
|
|
||||||
import com.simplemobiletools.commons.extensions.isAccessibleWithSAFSdk30
|
|
||||||
import com.simplemobiletools.commons.extensions.isRestrictedSAFOnlyRoot
|
|
||||||
import com.simplemobiletools.commons.extensions.needsStupidWritePermissions
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
|
@ -56,7 +43,7 @@ class MediaOutputHelper(
|
||||||
getMediaStoreOutput(isPhoto = true)
|
getMediaStoreOutput(isPhoto = true)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getMediaStoreOutput(isPhoto = true)
|
MediaOutput.BitmapOutput
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getOutputStreamMediaOutput() ?: getMediaStoreOutput(isPhoto = true)
|
getOutputStreamMediaOutput() ?: getMediaStoreOutput(isPhoto = true)
|
||||||
|
|
|
@ -5,34 +5,14 @@ import android.content.Context
|
||||||
import android.hardware.SensorManager
|
import android.hardware.SensorManager
|
||||||
import android.hardware.display.DisplayManager
|
import android.hardware.display.DisplayManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.Display
|
import android.view.*
|
||||||
import android.view.GestureDetector
|
|
||||||
import android.view.GestureDetector.SimpleOnGestureListener
|
import android.view.GestureDetector.SimpleOnGestureListener
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.OrientationEventListener
|
|
||||||
import android.view.ScaleGestureDetector
|
|
||||||
import android.view.Surface
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.camera.core.AspectRatio
|
import androidx.camera.core.*
|
||||||
import androidx.camera.core.Camera
|
import androidx.camera.core.ImageCapture.*
|
||||||
import androidx.camera.core.CameraSelector
|
|
||||||
import androidx.camera.core.CameraState
|
|
||||||
import androidx.camera.core.DisplayOrientedMeteringPointFactory
|
|
||||||
import androidx.camera.core.FocusMeteringAction
|
|
||||||
import androidx.camera.core.ImageCapture
|
|
||||||
import androidx.camera.core.ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY
|
|
||||||
import androidx.camera.core.ImageCapture.FLASH_MODE_AUTO
|
|
||||||
import androidx.camera.core.ImageCapture.FLASH_MODE_OFF
|
|
||||||
import androidx.camera.core.ImageCapture.FLASH_MODE_ON
|
|
||||||
import androidx.camera.core.ImageCapture.Metadata
|
|
||||||
import androidx.camera.core.ImageCapture.OnImageSavedCallback
|
|
||||||
import androidx.camera.core.ImageCapture.OutputFileOptions
|
|
||||||
import androidx.camera.core.ImageCapture.OutputFileResults
|
|
||||||
import androidx.camera.core.ImageCaptureException
|
|
||||||
import androidx.camera.core.Preview
|
|
||||||
import androidx.camera.core.UseCase
|
|
||||||
import androidx.camera.lifecycle.ProcessCameraProvider
|
import androidx.camera.lifecycle.ProcessCameraProvider
|
||||||
import androidx.camera.video.*
|
import androidx.camera.video.*
|
||||||
|
import androidx.camera.video.VideoCapture
|
||||||
import androidx.camera.view.PreviewView
|
import androidx.camera.view.PreviewView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.doOnLayout
|
import androidx.core.view.doOnLayout
|
||||||
|
@ -359,29 +339,53 @@ class CameraXPreview(
|
||||||
}
|
}
|
||||||
|
|
||||||
val mediaOutput = mediaOutputHelper.getImageMediaOutput()
|
val mediaOutput = mediaOutputHelper.getImageMediaOutput()
|
||||||
val outputOptionsBuilder = when (mediaOutput) {
|
|
||||||
is MediaOutput.MediaStoreOutput -> OutputFileOptions.Builder(contentResolver, mediaOutput.contentUri, mediaOutput.contentValues)
|
if (mediaOutput is MediaOutput.BitmapOutput) {
|
||||||
is MediaOutput.OutputStreamMediaOutput -> OutputFileOptions.Builder(mediaOutput.outputStream)
|
imageCapture.takePicture(mainExecutor, object : ImageCapture.OnImageCapturedCallback() {
|
||||||
else -> throw IllegalArgumentException("Unexpected option for image")
|
override fun onCaptureSuccess(image: ImageProxy) {
|
||||||
|
listener.toggleBottomButtons(false)
|
||||||
|
val bitmap = BitmapUtils.makeBitmap(image.toJpegByteArray())
|
||||||
|
if (bitmap != null) {
|
||||||
|
listener.onImageCaptured(bitmap)
|
||||||
|
} else {
|
||||||
|
cameraErrorHandler.handleImageCaptureError(ImageCapture.ERROR_CAPTURE_FAILED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(exception: ImageCaptureException) {
|
||||||
|
handleImageCaptureError(exception)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
val outputOptionsBuilder = when (mediaOutput) {
|
||||||
|
is MediaOutput.MediaStoreOutput -> OutputFileOptions.Builder(contentResolver, mediaOutput.contentUri, mediaOutput.contentValues)
|
||||||
|
is MediaOutput.OutputStreamMediaOutput -> OutputFileOptions.Builder(mediaOutput.outputStream)
|
||||||
|
is MediaOutput.BitmapOutput -> throw IllegalStateException("Cannot produce an OutputFileOptions for a bitmap output")
|
||||||
|
else -> throw IllegalArgumentException("Unexpected option for image ")
|
||||||
|
}
|
||||||
|
|
||||||
|
val outputOptions = outputOptionsBuilder.setMetadata(metadata).build()
|
||||||
|
|
||||||
|
imageCapture.takePicture(outputOptions, mainExecutor, object : OnImageSavedCallback {
|
||||||
|
override fun onImageSaved(outputFileResults: OutputFileResults) {
|
||||||
|
listener.toggleBottomButtons(false)
|
||||||
|
listener.onMediaSaved(mediaOutput.uri ?: outputFileResults.savedUri!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(exception: ImageCaptureException) {
|
||||||
|
handleImageCaptureError(exception)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
val outputOptions = outputOptionsBuilder.setMetadata(metadata).build()
|
|
||||||
|
|
||||||
imageCapture.takePicture(outputOptions, mainExecutor, object : OnImageSavedCallback {
|
|
||||||
override fun onImageSaved(outputFileResults: OutputFileResults) {
|
|
||||||
listener.toggleBottomButtons(false)
|
|
||||||
listener.onMediaCaptured(mediaOutput.uri ?: outputFileResults.savedUri!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(exception: ImageCaptureException) {
|
|
||||||
Log.e(TAG, "Error", exception)
|
|
||||||
listener.toggleBottomButtons(false)
|
|
||||||
cameraErrorHandler.handleImageCaptureError(exception.imageCaptureError)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
playShutterSoundIfEnabled()
|
playShutterSoundIfEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleImageCaptureError(exception: ImageCaptureException) {
|
||||||
|
Log.e(TAG, "Error", exception)
|
||||||
|
listener.toggleBottomButtons(false)
|
||||||
|
cameraErrorHandler.handleImageCaptureError(exception.imageCaptureError)
|
||||||
|
}
|
||||||
|
|
||||||
override fun initPhotoMode() {
|
override fun initPhotoMode() {
|
||||||
isPhotoCapture = true
|
isPhotoCapture = true
|
||||||
startCamera()
|
startCamera()
|
||||||
|
@ -441,7 +445,7 @@ class CameraXPreview(
|
||||||
Log.e(TAG, "recording failed:", recordEvent.cause)
|
Log.e(TAG, "recording failed:", recordEvent.cause)
|
||||||
cameraErrorHandler.handleVideoRecordingError(recordEvent.error)
|
cameraErrorHandler.handleVideoRecordingError(recordEvent.error)
|
||||||
} else {
|
} else {
|
||||||
listener.onMediaCaptured(mediaOutput.uri ?: recordEvent.outputResults.outputUri)
|
listener.onMediaSaved(mediaOutput.uri ?: recordEvent.outputResults.outputUri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.simplemobiletools.camera.implementations
|
package com.simplemobiletools.camera.implementations
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
|
||||||
interface CameraXPreviewListener {
|
interface CameraXPreviewListener {
|
||||||
|
@ -8,7 +9,8 @@ interface CameraXPreviewListener {
|
||||||
fun setFlashAvailable(available: Boolean)
|
fun setFlashAvailable(available: Boolean)
|
||||||
fun onChangeCamera(frontCamera: Boolean)
|
fun onChangeCamera(frontCamera: Boolean)
|
||||||
fun toggleBottomButtons(hide:Boolean)
|
fun toggleBottomButtons(hide:Boolean)
|
||||||
fun onMediaCaptured(uri: Uri)
|
fun onMediaSaved(uri: Uri)
|
||||||
|
fun onImageCaptured(bitmap: Bitmap)
|
||||||
fun onChangeFlashMode(flashMode: Int)
|
fun onChangeFlashMode(flashMode: Int)
|
||||||
fun onVideoRecordingStarted()
|
fun onVideoRecordingStarted()
|
||||||
fun onVideoRecordingStopped()
|
fun onVideoRecordingStopped()
|
||||||
|
|
|
@ -22,4 +22,6 @@ sealed class MediaOutput(
|
||||||
val fileDescriptor: ParcelFileDescriptor,
|
val fileDescriptor: ParcelFileDescriptor,
|
||||||
override val uri: Uri,
|
override val uri: Uri,
|
||||||
) : MediaOutput(uri)
|
) : MediaOutput(uri)
|
||||||
|
|
||||||
|
object BitmapOutput : MediaOutput(null)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,9 @@ enum class VideoQuality(val width: Int, val height: Int) {
|
||||||
HD(1280, 720),
|
HD(1280, 720),
|
||||||
SD(720, 480);
|
SD(720, 480);
|
||||||
|
|
||||||
|
|
||||||
val pixels: Int = width * height
|
val pixels: Int = width * height
|
||||||
|
|
||||||
val megaPixels: String = String.format("%.1f", (width * height.toFloat()) / VideoQuality.ONE_MEGA_PIXELS)
|
val megaPixels: String = String.format("%.1f", (width * height.toFloat()) / VideoQuality.ONE_MEGA_PIXEL)
|
||||||
|
|
||||||
val ratio = width / height.toFloat()
|
val ratio = width / height.toFloat()
|
||||||
|
|
||||||
|
@ -54,6 +53,6 @@ enum class VideoQuality(val width: Int, val height: Int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val ONE_MEGA_PIXELS = 1000000
|
private const val ONE_MEGA_PIXEL = 1000000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue