androidkotlinandroid-camerasamsung-mobilegalaxy

Auto Focus Modes Not Working In Samsung S8


Update 2: Any focus modes apparently don't work

Update 1: Problem seems to be isolated to my Samsung S8 device. It's working on Nexus 5X and Xiaomi phones

I've been trying to make FOCUS_MODE_CONTINUOUS_PICTURE work but to no avail. I've confirmed my device supports continuous auto picture via getSupportedFocusModes(), and not sure why it doesn't work.

Here's my code, continuous auto focus is being set in startCamera():

class CaptureReceiptFragment : Fragment(), CaptureReceiptContract.View {

private val MY_PERMISSIONS_REQUEST_CAMERA = 1

private var camera: Camera? = null
private var hasCameraPermission: Boolean? = null

private lateinit var preview: CameraPreview

override var presenter: CaptureReceiptContract.Presenter? = null

private val picture = Camera.PictureCallback { data, camera ->

    val pictureStorageDir = File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), getAppName())

    presenter?.saveReceipt(pictureStorageDir, data)


}

override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {
    val root = inflater!!.inflate(R.layout.capturereceipt_frag, container, false)

    return root
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    hasCameraPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED

    if (hasCameraPermission!!) {
        showCameraErrorMsg()
    } else {
        capturereceipt_button_capturereceipt.setOnClickListener {
            captureReceipt()
        }
        startCameraOnCreate()
    }
}

override fun onResume() {
    super.onResume()
    presenter?.start()
    if (hasCameraPermission!!) {
        showCameraErrorMsg()
    } else {
        startCamera()
        setCameraRotation()
    }
}

override fun onPause() {
    super.onPause()
    camera?.release()
    camera = null
}

override fun gotoReceiptList() {
    //TODO
}

override fun goBack() {
    //TODO
}

private fun startCameraOnCreate() {
    preview = CameraPreview(context)
    capturereceipt_framelayout_viewfinder.addView(preview)
    startCamera()
}

private fun startCamera() {
    if (camera == null) {
        camera = Camera.open()
        if (camera == null) {
            showCameraErrorMsg()
        } else {
            val params: Camera.Parameters? = camera!!.parameters
            if (params!!.getSupportedFocusModes()
                    .contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                params.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE;
            }
            camera?.parameters = params
            preview.camera = camera
            capturereceipt_textview_cameraerrormsg.visibility = View.GONE
            capturereceipt_framelayout_viewfinder.visibility = View.VISIBLE
        }
    }
}

private fun showCameraErrorMsg() {
    capturereceipt_textview_cameraerrormsg.visibility = View.VISIBLE
    capturereceipt_framelayout_viewfinder.visibility = View.GONE
}

override fun captureReceipt() {
    camera?.takePicture(null, null, picture)
}

private fun getOutputPictureFile(): File? {
    val appName = getAppName()

    val pictureStorageDir = File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), appName)

    if (!pictureStorageDir.exists()) {
        pictureStorageDir.mkdirs()
    }

    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
    return File(pictureStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg")
}

private fun getAppName(): String {
    val appInfo = context.getApplicationInfo()
    val stringId = appInfo.labelRes
    if (stringId == 0) {
        return appInfo.nonLocalizedLabel.toString()
    } else {
        return this.getString(stringId)
    }
}

fun setCameraDisplayOrientation() {
    val info = Camera.CameraInfo()
    Camera.getCameraInfo(CAMERA_FACING_BACK, info)
    val rotation = activity.windowManager.defaultDisplay.rotation
    var degrees = 0
    when (rotation) {
        Surface.ROTATION_0 -> degrees = 0
        Surface.ROTATION_90 -> degrees = 90
        Surface.ROTATION_180 -> degrees = 180
        Surface.ROTATION_270 -> degrees = 270
    }
    var result: Int
    if (info.facing == CAMERA_FACING_FRONT) {
        result = (info.orientation + degrees) % 360
        result = (360 - result) % 360  // compensate the mirror
    } else {  // back-facing
        result = (info.orientation - degrees + 360) % 360
    }
    camera?.setDisplayOrientation(result);
}

fun setCameraRotation() {
    val info: Camera.CameraInfo = Camera.CameraInfo()
    Camera.getCameraInfo(CAMERA_FACING_BACK, info)
    val rotation = activity.windowManager.defaultDisplay.rotation
    var degrees = 0
    when(rotation) {
        Surface.ROTATION_0 -> degrees = 0
        Surface.ROTATION_90 -> degrees = 90
        Surface.ROTATION_180 -> degrees = 180
        Surface.ROTATION_270 -> degrees = 270
    }
    val rotate = (info.orientation - degrees + 360) % 360
    camera?.setDisplayOrientation(rotate)
    val params: Camera.Parameters = camera!!.parameters
    params.setRotation(rotate)
    camera?.parameters = params
}

companion object {
    @JvmStatic fun newInstance(): CaptureReceiptFragment {
        return CaptureReceiptFragment()
    }
}

}

Any help would be appreciated. Thanks!


Solution

  • I finally figured out -- it appears that autofocus mode parameters should be set differently in Samsung S8.

    Here's what I tried that failed:

    1. Setting any autofocus modes (AUTO, CONTINUOUS_PICTURE, INFINITY) before starting preview
    2. Scheduled camera.autoFocus() to run every one second immdediately after camera.open

    Here's what I tried that worked:

    1. Putting continuous focus or camera.autoFocus() in a button onClick
    2. Delaying the setting of continuous focus by 1 second after camera.open() <-- this is what solved my issue

    My code for #2:

    private val autoFocusExecutor = ScheduledThreadPoolExecutor(1)
    
    fun startCamera() {
        if (camera == null) {
            camera = Camera.open()
            if (camera == null) {
                showCameraErrorMsg()
            } else {
                preview.camera = camera
                capturereceipt_textview_cameraerrormsg.visibility = View.GONE
                capturereceipt_framelayout_viewfinder.visibility = View.VISIBLE
    
                autoFocusExecutor.schedule(Sc{
                    val params: Camera.Parameters = camera!!.parameters
                    if (params.getSupportedFocusModes()
                            .contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                        //TODO: Auto focus not working
                        params.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
                    }
                    camera?.parameters = params
                }, 1000, TimeUnit.MILLISECONDS)
            }
        }
    }