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!
I finally figured out -- it appears that autofocus mode parameters should be set differently in Samsung S8.
Here's what I tried that failed:
camera.autoFocus()
to run every
one second immdediately after camera.openHere's what I tried that worked:
camera.autoFocus()
in a button onClickcamera.open()
<-- this is what solved my issueMy 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)
}
}
}