Created
August 10, 2021 12:03
-
-
Save ibrajix/e9931069973e96c33c18e4b8eabcde3b to your computer and use it in GitHub Desktop.
CameraFragment
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
class CameraFragment : Fragment() { | |
//View binding, you can access your view anyhow you want | |
private val binding by viewBinding(FragmentCameraBinding::bind) | |
private var imageCapture: ImageCapture? = null | |
private lateinit var outputDirectory: File | |
private lateinit var cameraExecutor: ExecutorService | |
private var lensFacing = CameraSelector.DEFAULT_FRONT_CAMERA | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
} | |
override fun onCreateView( | |
inflater: LayoutInflater, container: ViewGroup?, | |
savedInstanceState: Bundle? | |
): View? { | |
// Inflate the layout for this fragment | |
return inflater.inflate(R.layout.fragment_camera, container, false) | |
} | |
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | |
super.onViewCreated(view, savedInstanceState) | |
initView() | |
} | |
private fun initView(){ | |
// Request camera permissions | |
if (allPermissionsGranted()) { | |
startCamera() | |
} else { | |
ActivityCompat.requestPermissions( | |
requireActivity(), REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS | |
) | |
} | |
// Set up the listener for take photo button | |
binding.cameraCaptureButton.setOnClickListener { | |
takePhoto() | |
} | |
outputDirectory = getOutputDirectory() | |
cameraExecutor = Executors.newSingleThreadExecutor() | |
handleClicks() | |
} | |
private fun handleClicks(){ | |
//on click switch camera | |
binding.imgSwitchCamera.setOnClickListener { | |
if (lensFacing == CameraSelector.DEFAULT_FRONT_CAMERA) lensFacing = CameraSelector.DEFAULT_BACK_CAMERA; | |
else if (lensFacing == CameraSelector.DEFAULT_BACK_CAMERA) lensFacing = CameraSelector.DEFAULT_FRONT_CAMERA; | |
startCamera() | |
} | |
} | |
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(requireContext()), | |
object : ImageCapture.OnImageSavedCallback { | |
override fun onError(exc: ImageCaptureException) { | |
Log.e(TAG, "Photo capture failed: ${exc.message}", exc) | |
} | |
override fun onImageSaved(output: ImageCapture.OutputFileResults) { | |
//the uri of photo captured here | |
val savedUri = Uri.fromFile(photoFile) | |
val msg = "Photo capture successfully" | |
Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show() | |
Log.d(TAG, msg) | |
} | |
}) | |
} | |
private fun startCamera() { | |
val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext()) | |
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.surfaceProvider) | |
} | |
imageCapture = ImageCapture.Builder() | |
.build() | |
try { | |
// Unbind use cases before rebinding | |
cameraProvider.unbindAll() | |
cameraProvider.bindToLifecycle(this, lensFacing, imageCapture, preview) | |
} catch (exc: Exception) { | |
Log.e(TAG, "Use case binding failed", exc) | |
} | |
}, ContextCompat.getMainExecutor(requireContext())) | |
} | |
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all { | |
ContextCompat.checkSelfPermission( | |
requireContext(), it | |
) == PackageManager.PERMISSION_GRANTED | |
} | |
private fun getOutputDirectory(): File { | |
val mediaDir = activity?.externalMediaDirs?.firstOrNull()?.let { | |
File(it, resources.getString(R.string.app_name)).apply { mkdirs() } } | |
return if (mediaDir != null && mediaDir.exists()) | |
mediaDir else requireActivity().filesDir | |
} | |
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) | |
} | |
override fun onRequestPermissionsResult( | |
requestCode: Int, permissions: Array<String>, grantResults: | |
IntArray | |
) { | |
if (requestCode == REQUEST_CODE_PERMISSIONS) { | |
if (allPermissionsGranted()) { | |
startCamera() | |
} else { | |
Toast.makeText( | |
requireContext(), | |
"Permissions not granted by the user.", | |
Toast.LENGTH_SHORT | |
).show() | |
requireActivity().finish() | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment