5

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!

Community
  • 1
  • 1
Karl Jamoralin
  • 1,240
  • 1
  • 14
  • 27

2 Answers2

4

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)
        }
    }
}
Karl Jamoralin
  • 1,240
  • 1
  • 14
  • 27
  • 1
    We had this same problem for the Samsung S6 this fixed it! – Jelle de Fries Dec 14 '18 at 10:15
  • By "continuous focus" you mean calling `camera.autoFocus()` every X seconds? About the delaying of getting the supported focus modes, this didn't help me (tested on SGS7 and Pixel 2). It returned me the same tiny set of available focus modes ("fixed" for Pixel 2 and "fixed","infinity" for SGS7). – android developer Jan 21 '19 at 12:21
  • @androiddeveloper no, autoFocus is a different way of focusing, as opposed to FOCUS_MODE_CONTINUOUS_PICTURE. – Brill Pappin Feb 08 '19 at 21:53
  • So, what I want to know, is what the fallback is for Samsungs, if they don't support FOCUS_MODE_CONTINUOUS_PICTURE? – Brill Pappin Feb 08 '19 at 21:54
  • @BrillPappin I noticed that they barely provide any of those modes. Max of 2 or something like that. So, what we did is just call this function of `autoFocus` every now and then. – android developer Feb 08 '19 at 23:23
  • @androiddeveloper you mean if it didn't support FOCUS_MODE_CONTINUOUS_PICTURE, you simply call autoFocus periodically? – Brill Pappin Feb 09 '19 at 23:04
  • @BrillPappin Indeed. In fact, since I've noticed that I can't even try this mode on any of the devices we had at the office, I didn't bother to add anything related to it in code, sadly... – android developer Feb 10 '19 at 01:11
0

I faced the same issue with the Samsung J7 Prime, where the code was working but the camera focus was fixed. Setting the focus mode using a handler fixed the issue for me:

Handler().post { 
    camera.apply {
        val params = camera.parameters

        if (params.supportedFocusModes?.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) == true) {
            params.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
            camera.parameters = params
        }
    }
}
Angad Singh
  • 1,032
  • 1
  • 17
  • 36