Created
October 9, 2020 11:33
-
-
Save buildbro/517ca120a1490ee75fed5141480eea7c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.buildbrothers.poster2action | |
import android.Manifest | |
import android.annotation.SuppressLint | |
import android.content.pm.PackageManager | |
import android.net.Uri | |
import android.os.Build | |
import androidx.appcompat.app.AppCompatActivity | |
import android.os.Bundle | |
import android.util.Log | |
import android.widget.Toast | |
import androidx.annotation.RequiresApi | |
import androidx.camera.core.* | |
import androidx.camera.lifecycle.ProcessCameraProvider | |
import androidx.core.app.ActivityCompat | |
import androidx.core.content.ContextCompat | |
import com.google.mlkit.vision.common.InputImage | |
import kotlinx.android.synthetic.main.activity_main.* | |
import java.io.File | |
import java.text.SimpleDateFormat | |
import java.util.* | |
import java.util.concurrent.ExecutorService | |
import java.util.concurrent.Executors | |
class MainActivity : AppCompatActivity() { | |
private var imageCapture: ImageCapture? = null | |
private lateinit var outputDirectory: File | |
private lateinit var cameraExecutor: ExecutorService | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContentView(R.layout.activity_main) | |
// Request camera permissions | |
if (allPermissionsGranted()) { | |
startCamera() | |
} else { | |
ActivityCompat.requestPermissions( | |
this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS) | |
} | |
// Set up the listener for take photo button | |
camera_capture_button.setOnClickListener { takePhoto() } | |
outputDirectory = getOutputDirectory() | |
cameraExecutor = Executors.newSingleThreadExecutor() | |
} | |
private fun takePhoto() { | |
// Get a stable reference of the modifiable image capture use case | |
val imageCapture = imageCapture ?: return | |
// Create time-stamped output file to hold the image | |
val photoFile = File( | |
outputDirectory, | |
SimpleDateFormat(FILENAME_FORMAT, Locale.US | |
).format(System.currentTimeMillis()) + ".jpg") | |
// Create output options object which contains file + metadata | |
val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build() | |
// Set up image capture listener, which is triggered after photo has | |
// been taken | |
imageCapture.takePicture( | |
outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback { | |
override fun onError(exc: ImageCaptureException) { | |
Log.e(TAG, "Photo capture failed: ${exc.message}", exc) | |
} | |
override fun onImageSaved(output: ImageCapture.OutputFileResults) { | |
val savedUri = Uri.fromFile(photoFile) | |
val msg = "Photo capture succeeded: $savedUri" | |
Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show() | |
Log.d(TAG, msg) | |
} | |
}) | |
} | |
private fun startCamera() { | |
val cameraProviderFuture = ProcessCameraProvider.getInstance(this) | |
cameraProviderFuture.addListener(Runnable { | |
// Used to bind the lifecycle of cameras to the lifecycle owner | |
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() | |
// Preview | |
val preview = Preview.Builder() | |
.build() | |
.also { | |
it.setSurfaceProvider(viewFinder.createSurfaceProvider()) | |
} | |
imageCapture = ImageCapture.Builder() | |
.build() | |
// Select back camera as a default | |
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA | |
try { | |
// Unbind use cases before rebinding | |
cameraProvider.unbindAll() | |
// Bind use cases to camera | |
cameraProvider.bindToLifecycle( | |
this, cameraSelector, preview, imageCapture) | |
} catch(exc: Exception) { | |
Log.e(TAG, "Use case binding failed", exc) | |
} | |
}, ContextCompat.getMainExecutor(this)) | |
} | |
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all { | |
ContextCompat.checkSelfPermission( | |
baseContext, it) == PackageManager.PERMISSION_GRANTED | |
} | |
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) | |
private fun getOutputDirectory(): File { | |
val mediaDir = externalMediaDirs.firstOrNull()?.let { | |
File(it, resources.getString(R.string.app_name)).apply { mkdirs() } } | |
return if (mediaDir != null && mediaDir.exists()) | |
mediaDir else filesDir | |
} | |
override fun onRequestPermissionsResult( | |
requestCode: Int, permissions: Array<String>, grantResults: | |
IntArray) { | |
if (requestCode == REQUEST_CODE_PERMISSIONS) { | |
if (allPermissionsGranted()) { | |
startCamera() | |
} else { | |
Toast.makeText(this, | |
"Permissions not granted by the user.", | |
Toast.LENGTH_SHORT).show() | |
finish() | |
} | |
} | |
} | |
override fun onDestroy() { | |
super.onDestroy() | |
cameraExecutor.shutdown() | |
} | |
companion object { | |
private const val TAG = "CameraXBasic" | |
private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS" | |
private const val REQUEST_CODE_PERMISSIONS = 10 | |
private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment