将本机代码与CameraX集成到自定义React Native组件失败

时间:2020-09-15 06:48:01

标签: android react-native kotlin android-camerax

你好,我有一个应用程序,该应用程序现在在android中使用了不推荐使用的Camera模块,用于显示相机视图并使用mlkit人脸检测在其上绘制滤镜。最近,我们决定将其升级到CameraX,我做了所有必要的步骤,以使其能够作为单独的android应用程序正常工作。无论我做什么,当我想将其合并到我们现有的Custom React Native模块中时,它在屏幕上什么都没有显示。我检查了视图的大小,看来还可以。下面是我用来启动相机模块的代码。

package com.myProject.speech.components

import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Canvas
import android.hardware.camera2.CameraManager
import android.os.Bundle
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.size
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import com.facebook.react.uimanager.ThemedReactContext
import com.google.mlkit.common.MlKitException
import com.google.mlkit.vision.face.FaceDetectorOptions
import com.myProject.grpc.speech.StickerDatabase
import com.myProject.speech.R
import com.myProject.speech.utils.PreferenceUtils
import java.util.*
import androidx.databinding.DataBindingUtil
import com.myProject.camera_test.mlkit.facedetection.FaceContourDetectionProcessor
import com.myProject.speech.mlkit.GraphicOverlay
import java.util.concurrent.ExecutorService


class myProjectCameraView : RelativeLayout {
    private var previewView: PreviewView? = null
    private var graphicOverlay: GraphicOverlay? = null
    private var context: ThemedReactContext? = null
    private lateinit var cameraExecutor: ExecutorService
    var faceRecognitionEnabled = false
    var cameraSelector: CameraSelector? = null
    private var cameraProvider: ProcessCameraProvider? = null
    var cameraLifecycleObserver: CameraLifecycleObserver? = null
    private var lensFacing = CameraSelector.LENS_FACING_FRONT
    private lateinit var cameraManager: CameraManager
    private var imageCapture: ImageCapture? = null
    val TAG = "myProjectCameraView"

    constructor(context: ThemedReactContext,
                cameraLifecycleObserver: CameraLifecycleObserver?) : super(context) {
        this.context = context
        this.cameraLifecycleObserver = cameraLifecycleObserver;

        Log.d(TAG, "constructor Called")

        val inflater = context.getSystemService(
                Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        inflater.inflate(R.layout.live_preview, this, true)
        previewView = findViewById(R.id.firePreview)
        graphicOverlay = findViewById(R.id.fireFaceOverlay)
        if (allPermissionsGranted()) {
            startCamera()
            if (cameraLifecycleObserver != null) {
                cameraLifecycleObserver.registerActionHandler(this);
            }


        } else {
            Log.d(TAG, "Not all Permissions Granted")
        }
        this.cameraLifecycleObserver!!.registerActionHandler(this)


    }


    private fun startCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this.context as Context)

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

            // Preview
            val preview = Preview.Builder()
                    .build()
                    .also {
                        it.setSurfaceProvider(previewView!!.createSurfaceProvider())
                    }

            imageCapture = ImageCapture.Builder()
                    .build()


            val imageAnalyzer = ImageAnalysis.Builder().setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                    .build()
                    .also {
                        it.setAnalyzer(cameraExecutor, FaceContourDetectionProcessor(graphicOverlay!!))
                    }

            // Select back camera as a default
            val cameraSelector = CameraSelector.Builder()
                    .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
                    .build()

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

                // Bind use cases to camera
                cameraProvider.bindToLifecycle(
                        this.context!!.currentActivity!! as AppCompatActivity, cameraSelector, preview, imageCapture, imageAnalyzer)
            } catch (exc: Exception) {
                Log.e(TAG, "Use case binding failed", exc)
            }

        }, ContextCompat.getMainExecutor(this.context as Context))
    }


    fun enableFaceRecognition(enabled: Boolean) {
        Log.d(TAG, "enableFaceRecognition Called")
        if (enabled) {
            Log.d(TAG, "With FaceRecognition")
            Log.d(TAG, "Parent size: ${this!!.measuredWidth}x${this!!.measuredHeight}")
            Log.d(TAG, "previewView sizes: ${previewView!!.measuredWidth}x${previewView!!.measuredHeight}")
            Log.d(TAG, "graphicOverlay sizes: ${graphicOverlay!!.measuredWidth}x${graphicOverlay!!.measuredHeight}")
        } else {
            Log.d(TAG, "Without FaceRecognition")
        }
    }


    fun onActivityStopped() {

        Log.d(TAG, "onActivityStopped")

    }

    fun onActivityResumed() {
        Log.d(TAG, "onActivityResumed")

    }

    fun onActivityPaused() {

        Log.d(TAG, "onActivityPaused")

    }

    fun onActivityDestroyed() {
        Log.d(TAG, "onActivityDestroyed")


    }


    private fun allPermissionsGranted(): Boolean {
        for (permission in requiredPermissions) {
            if (!isPermissionGranted(getContext(), permission)) {
                return false
            }
        }
        return true
    }


    private val requiredPermissions: Array<String?>
        private get() = try {
            val info = getContext().packageManager.getPackageInfo(
                    getContext().packageName, PackageManager.GET_PERMISSIONS)
            val ps = info.requestedPermissions
            if (ps != null && ps.size > 0) {
                ps
            } else {
                arrayOfNulls(0)
            }
        } catch (e: Exception) {
            arrayOfNulls(0)
        }


    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {}
    constructor(context: Context?, attrs: AttributeSet?,
                defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
    }

    val viewBitmap: Bitmap
        get() {
            val v = rootView
            val b = Bitmap.createBitmap(v.layoutParams.width,
                    v.layoutParams.height,
                    Bitmap.Config.ARGB_8888)
            val c = Canvas(b)
            v.layout(v.left, v.top, v.right, v.bottom)
            v.draw(c)
            return b
        }

    private fun isPermissionGranted(context: Context,
                                    permission: String?): Boolean {
        if (ContextCompat.checkSelfPermission(context, permission!!) ==
                PackageManager.PERMISSION_GRANTED) {
            Log.i(this.TAG, "Permission granted: $permission")
            return true
        }
        Log.i(TAG, "Permission NOT granted: $permission")
        return false
    }


    companion object {
        private const val FACE_DETECTION = "Face Detection"
        private const val CLASSIFICATION = "Classification"
        private const val PERMISSION_REQUESTS = 1
        private const val lastDBPath = ""
        private var context: ThemedReactContext? = null
        val lastDB: StickerDatabase? = null
    }
}

任何见解将不胜感激。 谢谢

1 个答案:

答案 0 :(得分:2)

之所以发生此问题,是因为相对布局在添加到场景后没有调整大小。解决方法不是我的,但我现在无法找到它的位置,因此如果有人遇到类似问题,我将其留在这里。我通过在RelativeLayout的构造函数中调用layoutHack解决了该问题

 fun setupLayoutHack() {
    Choreographer.getInstance().postFrameCallback(object : Choreographer.FrameCallback {
        override fun doFrame(frameTimeNanos: Long) {
            manuallyLayoutChildren()
            viewTreeObserver.dispatchOnGlobalLayout()
            Choreographer.getInstance().postFrameCallback(this)
        }
    })
}

fun manuallyLayoutChildren() {
    for (i in 0 until childCount) {
        val child = getChildAt(i)
        child.measure(MeasureSpec.makeMeasureSpec(measuredWidth, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY))
        child.layout(0, 0, child.measuredWidth, child.measuredHeight)
    }
}