Hey there I want to flip my camera with an image button (e.g. btn_switch_camera) from back to front and vice-versa, help me!, this beautiful code has all basic things but no camera flip option so I want a flip camera imagebutton in this camera app , it has latest CameraX api it supports gradle 7.0.0 +. I just need some code to switch camera , when I did it on my own it gave me null error on image preview , so I deleted that mess and give you this original code (it must include front_camera_ icon switch to rear_camera_icon effect):
private val cameraExecutor = Executors.newSingleThreadExecutor()
private var imagePreview: Preview? = null
private var imageAnalysis: ImageAnalysis? = null
private var imageCapture: ImageCapture? = null
private var videoCapture: VideoCapture? = null
private lateinit var outputDirectory: File
private var cameraControl: CameraControl? = null
private var cameraInfo: CameraInfo? = null
private var linearZoom = 0f
private var recording = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = MainActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
if (allPermissionsGranted()) {
startCamera()
} else {
requestPermissions(
REQUIRED_PERMISSIONS,
REQUEST_CODE_PERMISSIONS
)
}
outputDirectory = getOutputDirectory()
binding.cameraCaptureButton.setOnClickListener {
takePicture()
}
initCameraModeSelector()
binding.cameraTorchButton.setOnClickListener {
toggleTorch()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_CODE_PERMISSIONS) {
if (allPermissionsGranted()) {
startCamera()
} else {
finish()
}
}
}
/**
* Check if all permission specified in the manifest have been granted
*/
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED
}
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
val cameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
cameraProviderFuture.addListener({
imagePreview = Preview.Builder().apply {
setTargetAspectRatio(AspectRatio.RATIO_16_9)
setTargetRotation(binding.previewView.display.rotation)
}.build()
imageAnalysis = ImageAnalysis.Builder().apply {
setImageQueueDepth(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
}.build()
imageAnalysis?.setAnalyzer(cameraExecutor, LuminosityAnalyzer())
imageCapture = ImageCapture.Builder().apply {
setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
setFlashMode(ImageCapture.FLASH_MODE_AUTO)
}.build()
videoCapture = VideoCapture.Builder().apply {
setTargetAspectRatio(AspectRatio.RATIO_16_9)
}.build()
val cameraProvider = cameraProviderFuture.get()
val camera = cameraProvider.bindToLifecycle(
this,
cameraSelector,
imagePreview,
// imageAnalysis,
imageCapture,
videoCapture
)
binding.previewView.implementationMode = PreviewView.ImplementationMode.COMPATIBLE
imagePreview?.setSurfaceProvider(binding.previewView.surfaceProvider)
cameraControl = camera.cameraControl
cameraInfo = camera.cameraInfo
setTorchStateObserver()
setZoomStateObserver()
}, ContextCompat.getMainExecutor(this))
}
private fun setTorchStateObserver() {
cameraInfo?.torchState?.observe(this, { state ->
if (state == TorchState.ON) {
binding.cameraTorchButton.setImageDrawable(
ContextCompat.getDrawable(
this,
R.drawable.ic_flashlight_off_24dp
)
)
} else {
binding.cameraTorchButton.setImageDrawable(
ContextCompat.getDrawable(
this,
R.drawable.ic_flashlight_on_24dp
)
)
}
})
}
private fun setZoomStateObserver() {
cameraInfo?.zoomState?.observe(this, { state ->
// state.linearZoom
// state.zoomRatio
// state.maxZoomRatio
// state.minZoomRatio
Log.d(TAG, "${state.linearZoom}")
})
}
private fun initCameraModeSelector() {
binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?) {}
override fun onTabUnselected(tab: TabLayout.Tab?) {}
override fun onTabSelected(tab: TabLayout.Tab?) {
when (tab?.position) {
PHOTO -> {
binding.cameraCaptureButton.setOnClickListener {
takePicture()
}
}
VIDEO -> {
binding.cameraCaptureButton.setOnClickListener {
if (recording) {
videoCapture?.stopRecording()
it.isSelected = false
recording = false
} else {
recordVideo()
it.isSelected = true
recording = true
}
}
}
}
}
})
}
private fun takePicture() {
val file = createFile(
outputDirectory,
FILENAME,
PHOTO_EXTENSION
)
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(file).build()
imageCapture?.takePicture(outputFileOptions, cameraExecutor, object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
val msg = "Photo capture succeeded: ${file.absolutePath}"
binding.previewView.post {
Toast.makeText(this@MainActivity, msg, Toast.LENGTH_LONG).show()
}
}
override fun onError(exception: ImageCaptureException) {
val msg = "Photo capture failed: ${exception.message}"
binding.previewView.post {
Toast.makeText(this@MainActivity, msg, Toast.LENGTH_LONG).show()
}
}
})
}
private fun recordVideo() {
val file = createFile(
outputDirectory,
FILENAME,
VIDEO_EXTENSION
)
val outputFileOptions = VideoCapture.OutputFileOptions.Builder(file).build()
videoCapture?.startRecording(outputFileOptions, cameraExecutor, object : VideoCapture.OnVideoSavedCallback {
override fun onVideoSaved(outputFileResults: VideoCapture.OutputFileResults) {
val msg = "Video capture succeeded: ${file.absolutePath}"
binding.previewView.post {
Toast.makeText(this@MainActivity, msg, Toast.LENGTH_LONG).show()
}
}
override fun onError(videoCaptureError: Int, message: String, cause: Throwable?) {
val msg = "Video capture failed: $message"
binding.previewView.post {
Toast.makeText(this@MainActivity, msg, Toast.LENGTH_LONG).show()
}
}
})
}
private fun toggleTorch() {
if (cameraInfo?.torchState?.value == TorchState.ON) {
cameraControl?.enableTorch(false)
} else {
cameraControl?.enableTorch(true)
}
}
// Manage camera Zoom
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
return when (keyCode) {
KeyEvent.KEYCODE_VOLUME_UP -> {
if (linearZoom <= 0.9) {
linearZoom += 0.1f
}
cameraControl?.setLinearZoom(linearZoom)
true
}
KeyEvent.KEYCODE_VOLUME_DOWN -> {
if (linearZoom >= 0.1) {
linearZoom -= 0.1f
}
cameraControl?.setLinearZoom(linearZoom)
true
}
else -> super.onKeyDown(keyCode, event)
}
}
private class LuminosityAnalyzer : ImageAnalysis.Analyzer {
private var lastAnalyzedTimestamp = 0L
/**
* Helper extension function used to extract a byte array from an
* image plane buffer
*/
private fun ByteBuffer.toByteArray(): ByteArray {
rewind() // Rewind the buffer to zero
val data = ByteArray(remaining())
get(data) // Copy the buffer into a byte array
return data // Return the byte array
}
override fun analyze(image: ImageProxy) {
image.imageInfo.rotationDegrees
val currentTimestamp = System.currentTimeMillis()
// Calculate the average luma no more often than every second
if (currentTimestamp - lastAnalyzedTimestamp >=
TimeUnit.SECONDS.toMillis(1)
) {
// Since format in ImageAnalysis is YUV, image.planes[0]
// contains the Y (luminance) plane
val buffer = image.planes[0].buffer
// Extract image data from callback object
val data = buffer.toByteArray()
// Convert the data into an array of pixel values
val pixels = data.map { it.toInt() and 0xFF }
// Compute average luminance for the image
val luma = pixels.average()
// Log the new luma value
Log.d("CameraXApp", "Average luminosity: $luma")
// Update timestamp of last analyzed frame
lastAnalyzedTimestamp = currentTimestamp
}
image.close()
}
}
override fun onDestroy() {
super.onDestroy()
cameraExecutor.shutdown()
}
private fun getOutputDirectory(): File {
// TODO: 29/01/2021 Remove externalMediaDirs (deprecated)
val mediaDir = externalMediaDirs.firstOrNull()?.let {
File(it, resources.getString(R.string.app_name)).apply { mkdirs() }
}
return if (mediaDir != null && mediaDir.exists())
mediaDir else filesDir
}
companion object {
private const val TAG = "MainActivity"
private const val FILENAME = "yyyy-MM-dd-HH-mm-ss-SSS"
private const val PHOTO_EXTENSION = ".jpg"
private const val VIDEO_EXTENSION = ".mp4"
private const val REQUEST_CODE_PERMISSIONS = 10
private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
private const val PHOTO = 0
private const val VIDEO = 1
fun createFile(baseFolder: File, format: String, extension: String) =
File(
baseFolder, SimpleDateFormat(format, Locale.US)
.format(System.currentTimeMillis()) + extension
)
}
} Footer © 2022 GitHub, Inc. Footer navigation Terms Privacy Security Status Docs Contact GitHub Pricing API Training Blog About
You can use cameraX Library.
In CameraSelector you can use
requireLensFacing(int lensFacing)to flip the camera.Here is the code that copied from here: