Skip to content

Commit

Permalink
all: use android.hardware.camera2.* (fixes #3619) (#3625)
Browse files Browse the repository at this point in the history
Co-authored-by: dogi <[email protected]>
  • Loading branch information
strawberrybread and dogi authored Jun 18, 2024
1 parent 50adba9 commit d946ade
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 24 deletions.
9 changes: 7 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ android {
applicationId "org.ole.planet.myplanet"
minSdkVersion 21
targetSdkVersion 34
versionCode 1590
versionName "0.15.90"
versionCode 1591
versionName "0.15.91"
ndkVersion '21.3.6528147'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
Expand Down Expand Up @@ -131,6 +131,11 @@ dependencies {
implementation 'com.mikepenz:crossfadedrawerlayout:1.1.0@aar'
implementation('com.mikepenz:materialdrawer:6.1.1@aar') { transitive = true}

implementation "androidx.camera:camera-core:1.1.0"
implementation "androidx.camera:camera-camera2:1.1.0"
implementation "androidx.camera:camera-lifecycle:1.1.0"
implementation "androidx.camera:camera-view:1.0.0-alpha31"

def dagger_hilt_version = "2.51.1"
implementation "com.google.dagger:hilt-android:$dagger_hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$dagger_hilt_version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,12 @@ class CourseStepFragment : BaseContainerFragment(), ImageCaptureCallback {
b.putInt("stepNum", stepNumber)
takeExam.arguments = b
homeItemClickListener?.openCallFragment(takeExam)
CapturePhoto(this)
context?.let { it1 ->
CapturePhoto(it1, object : ImageCaptureCallback {
override fun onImageCapture(fileUri: String?) {
}
})
}
}
}
val downloadedResources: List<RealmMyLibrary> = cRealm.where(RealmMyLibrary::class.java).equalTo("stepId", stepId).equalTo("resourceOffline", true).isNotNull("resourceLocalAddress").findAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,12 @@ class TakeExamFragment : BaseExamFragment(), View.OnClickListener, CompoundButto
private fun capturePhoto() {
try {
if (isCertified && !isMySurvey) {
CapturePhoto(this)
context?.let { it1 ->
CapturePhoto(it1, object : ImageCaptureCallback {
override fun onImageCapture(fileUri: String?) {
}
})
}
}
} catch (e: Exception) {
e.printStackTrace()
Expand Down
150 changes: 130 additions & 20 deletions app/src/main/java/org/ole/planet/myplanet/utilities/CameraUtils.kt
Original file line number Diff line number Diff line change
@@ -1,34 +1,62 @@
package org.ole.planet.myplanet.utilities

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.ImageFormat
import android.graphics.SurfaceTexture
import android.hardware.Camera
import android.hardware.Camera.CameraInfo
import android.hardware.camera2.*
import android.media.ImageReader
import android.os.Handler
import android.os.HandlerThread
import android.util.Size
import android.view.Surface
import androidx.core.content.ContextCompat
import java.io.File
import java.io.FileOutputStream
import java.util.Date
import java.util.*

object CameraUtils {
private var cameraDevice: CameraDevice? = null
private var captureSession: CameraCaptureSession? = null
private var imageReader: ImageReader? = null
private var backgroundHandler: Handler
private var backgroundThread: HandlerThread
@JvmStatic
fun CapturePhoto(callback: ImageCaptureCallback) {
val cameraInfo = CameraInfo()
val frontCamera = 1
val camera: Camera = try {
Camera.getCameraInfo(frontCamera, cameraInfo)
Camera.open(frontCamera)
} catch (e: RuntimeException) {
e.printStackTrace()
fun CapturePhoto(context: Context, callback: ImageCaptureCallback) {
if (ContextCompat.checkSelfPermission(
context,
Manifest.permission.CAMERA
) != PackageManager.PERMISSION_GRANTED
) {
return
}
try {
camera.setPreviewTexture(SurfaceTexture(0))
camera.startPreview()
camera.takePicture(null, null) { data, camera ->
savePicture(data, callback)
camera.release()
openCamera(context)
imageReader = ImageReader.newInstance(
IMAGE_WIDTH, IMAGE_HEIGHT, ImageFormat.JPEG, 1
)
imageReader?.setOnImageAvailableListener({ reader ->
val image = reader.acquireLatestImage()
val buffer = image.planes[0].buffer
val bytes = ByteArray(buffer.capacity())
buffer.get(bytes)
savePicture(bytes, callback)
image.close()
}, backgroundHandler)

val captureBuilder = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
captureBuilder?.addTarget(imageReader!!.surface)
captureBuilder?.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)

val captureCallback = object : CameraCaptureSession.CaptureCallback() {
override fun onCaptureCompleted(session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult) {
super.onCaptureCompleted(session, request, result)
}
} catch (e: Exception) {
camera.release()
}

captureSession?.stopRepeating()
captureSession?.abortCaptures()
captureSession?.capture(captureBuilder!!.build(), captureCallback, null)
}

@JvmStatic
Expand All @@ -49,8 +77,90 @@ object CameraUtils {
error.printStackTrace()
}
}
@SuppressLint("MissingPermission")
@JvmStatic
private fun openCamera(context: Context) {
val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
try {
val cameraId = manager.cameraIdList[0] // Assuming we want to use the first (rear) camera
val characteristics = manager.getCameraCharacteristics(cameraId)
val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
val largest = Collections.max(
listOf(*map!!.getOutputSizes(ImageFormat.JPEG)),
CompareSizesByArea()
)
val reader = ImageReader.newInstance(largest.width, largest.height, ImageFormat.JPEG, 2)
manager.openCamera(cameraId, object : CameraDevice.StateCallback() {
override fun onOpened(camera: CameraDevice) {
cameraDevice = camera
createCameraPreview()
}

override fun onDisconnected(camera: CameraDevice) {
cameraDevice?.close()
}

override fun onError(camera: CameraDevice, error: Int) {
cameraDevice?.close()
cameraDevice = null
}
}, null)
} catch (e: CameraAccessException) {
e.printStackTrace()
}
}

private fun createCameraPreview() {
try {
val texture = SurfaceTexture(0)
texture.setDefaultBufferSize(IMAGE_WIDTH, IMAGE_HEIGHT)
val surface = Surface(texture)
val captureRequestBuilder = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
captureRequestBuilder.addTarget(surface)
cameraDevice!!.createCaptureSession(
listOf(surface),
object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
if (cameraDevice == null) return
captureSession = session
try {
captureRequestBuilder.set(
CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE
)
captureSession!!.setRepeatingRequest(
captureRequestBuilder.build(),
null,
backgroundHandler
)
} catch (e: CameraAccessException) {
e.printStackTrace()
}
}

override fun onConfigureFailed(session: CameraCaptureSession) {}
},
backgroundHandler
)
} catch (e: CameraAccessException) {
e.printStackTrace()
}
}

interface ImageCaptureCallback {
fun onImageCapture(fileUri: String?)
}

private class CompareSizesByArea : Comparator<Size> {
override fun compare(lhs: Size, rhs: Size): Int {
return java.lang.Long.signum(lhs.width.toLong() * lhs.height - rhs.width.toLong() * rhs.height)
}
}
init {
backgroundThread = HandlerThread("CameraBackground")
backgroundThread.start()
backgroundHandler = Handler(backgroundThread.looper)
}
private const val IMAGE_WIDTH = 640
private const val IMAGE_HEIGHT = 480
}

0 comments on commit d946ade

Please sign in to comment.