What could cause a black screen?

1,005 views
Skip to first unread message

Seph Soliman

unread,
Jun 17, 2020, 4:08:51 PM6/17/20
to Android CameraX Discussion Group
I recently built a standalone app using code from the example repository. It works.

However, when I take my example code and embed it into a library that I intend to use in another app, then my PreviewView only displays black instead of the camera contents. Ie. the viewfinder is rendering all black.

The main changes I made was to how to access the current activity and avoid using layout.xml (because it's a simple 1-view app I won't need it). That code was replaced by creating the PreviewView myself and adding it as a child to a FrameLayout view.

Code:

import ...

class CameraView(context: ThemedReactContext) : FrameLayout(context) {
    private val currentContext: ThemedReactContext = context
    private var preview: Preview? = null
    private var camera: Camera? = null
    private var viewFinder: PreviewView? = null
    private var imageCapture: ImageCapture? = null
    private var cameraExecutor: ExecutorService = Executors.newSingleThreadExecutor()

    private fun getActivity() : Activity {
        return currentContext.currentActivity!!
    }

    init {
        layoutParams = LinearLayout.LayoutParams(
            LayoutParams.MATCH_PARENT,
            LayoutParams.MATCH_PARENT
        )

        viewFinder = PreviewView(context)
        viewFinder!!.layoutParams = LinearLayout.LayoutParams(
            LayoutParams.MATCH_PARENT,
            LayoutParams.MATCH_PARENT
        )
        addView(viewFinder, 0)

        if (allPermissionsGranted()) {
            viewFinder!!.post {
                startCamera()
            }
        } else {
            Toast.makeText(getActivity(),
                "Permissions not granted by the user.",
                Toast.LENGTH_SHORT).show()
            ActivityCompat.requestPermissions(
                getActivity(), REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)

        }
    }

    private fun startCamera() {
        Log.d(TAG, "startCamera")
        val cameraProviderFuture = ProcessCameraProvider.getInstance(context)

        cameraProviderFuture.addListener(Runnable {
            // Used to bind the lifecycle of cameras to the lifecycle owner
            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
            val cameraSelector = CameraSelector.Builder().build()

            viewFinder!!.post {
                preview = Preview.Builder().build()
                imageCapture = ImageCapture.Builder().build()

                try {
                    // Unbind use cases before rebinding
                    cameraProvider.unbindAll()

                    // Bind use cases to camera
                    camera = cameraProvider.bindToLifecycle(
                        getActivity() as AppCompatActivity,
                        cameraSelector,
                        preview,
                        imageCapture
                    )
                    preview!!.setSurfaceProvider(viewFinder!!.createSurfaceProvider())
                    Log.d(TAG, "Use case binding worked " + imageCapture.toString())
                } catch (exc: Exception) {
                    Log.e(TAG, "Use case binding failed", exc)
                }
            }
        }, cameraExecutor)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        Log.d(TAG, "Photo capture?")
        val outputDirectory = getActivity().filesDir

        val photoFile = File(outputDirectory, SimpleDateFormat(FILENAME_FORMAT, Locale.US)
            .format(System.currentTimeMillis()) + ".jpg")

        val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

        imageCapture!!.takePicture(
            outputOptions, cameraExecutor, object : ImageCapture.OnImageSavedCallback {
                override fun onError(exc: ImageCaptureException) {
                    Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
                }

                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    val savedUri = Uri.fromFile(photoFile)
                    val msg = "Photo capture succeeded: $savedUri"
                    Toast.makeText(currentContext, msg, Toast.LENGTH_SHORT).show()
                    Log.d(TAG, msg)
                }
            })

        return super.onTouchEvent(event)
    }

    private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
        ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
    }

    companion object {
        private const val TAG = "camera"
        private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
        private const val REQUEST_CODE_PERMISSIONS = 10
        private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
    }
}


Logcat output:
06-17 12:54:12.684 25113 25113 D camera  : startCamera
06-17 12:54:12.740 25113 25945 I CameraManagerGlobal: Connecting to camera service
06-17 12:54:12.743 25113 25945 D VendorTagDescriptor: addVendorDescriptor: vendor tag id 3854507339 added
06-17 12:54:12.746 25113 25945 I CameraManager: getCameraCharacteristics : cameraId = 0
06-17 12:54:12.758 25113 25945 I CameraManager: getCameraCharacteristics : cameraId = 1
06-17 12:54:12.766 25113 25945 D CameraRepository: Added camera: 0
06-17 12:54:12.769 25113 25945 I CameraManager: getCameraCharacteristics : cameraId = 0
06-17 12:54:12.780 25113 25945 I Camera2CameraInfo: Device Level: INFO_SUPPORTED_HARDWARE_LEVEL_FULL
06-17 12:54:12.781 25113 25945 D CameraRepository: Added camera: 1
06-17 12:54:12.782 25113 25945 I CameraManager: getCameraCharacteristics : cameraId = 1
06-17 12:54:12.785 25113 25945 I Camera2CameraInfo: Device Level: INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
06-17 12:54:12.792 25113 25945 D UseCaseAttachState: Active and attached use case: [] for camera: 1
06-17 12:54:12.794 25113 25955 D UseCaseAttachState: Active and attached use case: [] for camera: 0
06-17 12:54:13.039 25113 25945 D UseCaseAttachState: Active and attached use case: [] for camera: 0
06-17 12:54:13.039 25113 25113 V Surface : sf_framedrop debug : 0x4f4c, game : false, logging : 0
06-17 12:54:13.043 25113 25955 D UseCaseAttachState: Active and attached use case: [] for camera: 0
06-17 12:54:13.045 25113 25955 D UseCaseAttachState: All use case: [androidx.camera.core.Preview-08e7096b-2a4e-4d09-bc37-9686cd4b0b20, androidx.camera.core.ImageCapture-04eeb38e-c834-40f6-b726-87b6e84fe28b] for camera: 0
06-17 12:54:13.045 25113 25113 D camera  : Use case binding worked ImageCapture:androidx.camera.core.ImageCapture-04eeb38e-c834-40f6-b726-87b6e84fe28b
06-17 12:54:13.045 25113 25955 D Camera2CameraImpl: mMeteringRepeating is ATTACHED, SessionConfig Surfaces: 2, CaptureConfig Surfaces: 1
06-17 12:54:13.046 25113 25955 D UseCaseAttachState: Active and attached use case: [androidx.camera.core.ImageCapture-04eeb38e-c834-40f6-b726-87b6e84fe28b] for camera: 0
06-17 12:54:13.058 25113 25955 D UseCaseAttachState: All use case: [androidx.camera.core.Preview-08e7096b-2a4e-4d09-bc37-9686cd4b0b20, androidx.camera.core.ImageCapture-04eeb38e-c834-40f6-b726-87b6e84fe28b] for camera: 0
06-17 12:54:13.059 25113 25955 I CameraManager: getCameraCharacteristics : cameraId = 0
06-17 12:54:13.061 25113 25113 D PreviewView: Surface requested by Preview.
06-17 12:54:13.078 25113 25113 D TSBackgroundFetch: BootReceiver: android.intent.action.MY_PACKAGE_REPLACED
06-17 12:54:13.081 25113 25113 D SurfaceViewImpl: Wait for new Surface creation.
06-17 12:54:13.180 25113 25955 D UseCaseAttachState: Active and attached use case: [androidx.camera.core.ImageCapture-04eeb38e-c834-40f6-b726-87b6e84fe28b] for camera: 0
06-17 12:54:13.185 25113 25955 D UseCaseAttachState: Active and attached use case: [androidx.camera.core.ImageCapture-04eeb38e-c834-40f6-b726-87b6e84fe28b] for camera: 0
06-17 12:54:13.194 25113 25955 D UseCaseAttachState: Active and attached use case: [androidx.camera.core.Preview-08e7096b-2a4e-4d09-bc37-9686cd4b0b20, androidx.camera.core.ImageCapture-04eeb38e-c834-40f6-b726-87b6e84fe28b] for camera: 0
06-17 12:54:13.206 25113 25955 D UseCaseAttachState: Active and attached use case: [androidx.camera.core.Preview-08e7096b-2a4e-4d09-bc37-9686cd4b0b20, androidx.camera.core.ImageCapture-04eeb38e-c834-40f6-b726-87b6e84fe28b] for camera: 0
06-17 12:54:13.222 25113 25955 D UseCaseAttachState: All use case: [androidx.camera.core.Preview-08e7096b-2a4e-4d09-bc37-9686cd4b0b20, androidx.camera.core.ImageCapture-04eeb38e-c834-40f6-b726-87b6e84fe28b] for camera: 0
06-17 12:54:13.231 25113 25955 D CaptureSession: Some surfaces were closed.
06-17 12:54:13.235 25113 25113 D PreviewView: Surface requested by Preview.
06-17 12:54:13.238 25113 25945 D UseCaseAttachState: Active and attached use case: [androidx.camera.core.Preview-08e7096b-2a4e-4d09-bc37-9686cd4b0b20, androidx.camera.core.ImageCapture-04eeb38e-c834-40f6-b726-87b6e84fe28b] for camera: 0
06-17 12:54:13.243 25113 25113 D SurfaceViewImpl: Wait for new Surface creation.
06-17 12:54:13.247 25113 25945 D UseCaseAttachState: All use case: [androidx.camera.core.Preview-08e7096b-2a4e-4d09-bc37-9686cd4b0b20, androidx.camera.core.ImageCapture-04eeb38e-c834-40f6-b726-87b6e84fe28b] for camera: 0
06-17 12:54:14.426 25113 25211 V FA      : Inactivity, disconnecting from the service
06-17 12:54:18.277 25113 25955 E Camera2CameraImpl: Unable to configure camera 0, timeout!
06-17 12:54:18.319 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 0
06-17 12:54:18.331 25113 25113 D camera  : Photo capture?
06-17 12:54:18.346 25113 25113 D ImageCapture: Send image capture request [current, pending] = [0, 1]
06-17 12:54:18.444 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 1
06-17 12:54:24.915 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 0
06-17 12:54:24.920 25113 25113 D camera  : Photo capture?
06-17 12:54:24.925 25113 25113 D ImageCapture: Send image capture request [current, pending] = [1, 1]
06-17 12:54:25.026 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 1
06-17 12:54:52.167 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 0
06-17 12:54:52.171 25113 25113 D camera  : Photo capture?
06-17 12:54:52.177 25113 25113 D ImageCapture: Send image capture request [current, pending] = [1, 2]
06-17 12:54:52.307 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 1
06-17 12:54:52.643 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 0
06-17 12:54:52.648 25113 25113 D camera  : Photo capture?
06-17 12:54:52.653 25113 25113 D ImageCapture: Send image capture request [current, pending] = [1, 3]
06-17 12:54:52.765 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 1
06-17 12:54:53.180 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 0
06-17 12:54:53.187 25113 25113 D camera  : Photo capture?
06-17 12:54:53.192 25113 25113 D ImageCapture: Send image capture request [current, pending] = [1, 4]
06-17 12:54:53.302 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 1
06-17 12:54:53.728 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 0
06-17 12:54:53.732 25113 25113 D camera  : Photo capture?
06-17 12:54:53.738 25113 25113 D ImageCapture: Send image capture request [current, pending] = [1, 5]
06-17 12:54:53.824 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 1
06-17 12:54:55.488 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 0
06-17 12:54:55.494 25113 25113 D camera  : Photo capture?
06-17 12:54:55.504 25113 25113 D ImageCapture: Send image capture request [current, pending] = [1, 6]
06-17 12:54:55.561 25113 25113 D ViewRootImpl@b2d992e[MainActivity]: ViewPostIme pointer 1

The last couple of lines are generated when I tap the view finder multiple times. As you can see, it's somehow queueing up the captures but it never actually captures the image.

What could some potential causes be?

Really appreciate any guesses here!
Thanks

Seph Soliman

unread,
Jun 17, 2020, 7:12:20 PM6/17/20
to Android CameraX Discussion Group
Found the issue:
It's a known React Native (Android) bug, where any subviews are not laid out again:

The fix was to use the suggestion from this comment. This causes .layout() to be called when it should. Note that it must be attached to the view that is causing problems (in my case that was the viewFinder (aka PreviewView)).
Reply all
Reply to author
Forward
0 new messages