|
@@ -1,18 +1,13 @@
|
|
|
package com.ethan.psbc.ui.widgets
|
|
|
|
|
|
import android.Manifest
|
|
|
-import android.animation.ValueAnimator
|
|
|
-import android.annotation.SuppressLint
|
|
|
import android.content.Context
|
|
|
import android.content.pm.PackageManager
|
|
|
-import android.content.res.TypedArray
|
|
|
import android.graphics.*
|
|
|
-import android.graphics.Canvas.ALL_SAVE_FLAG
|
|
|
import android.util.AttributeSet
|
|
|
import android.util.Log
|
|
|
import android.view.SurfaceHolder
|
|
|
import android.view.SurfaceView
|
|
|
-import android.view.animation.LinearInterpolator
|
|
|
import android.widget.Toast
|
|
|
import androidx.appcompat.app.AppCompatActivity
|
|
|
import androidx.camera.core.*
|
|
@@ -23,102 +18,58 @@ import androidx.core.content.ContextCompat
|
|
|
import cn.face.sdk.FaceDetTrack
|
|
|
import cn.face.sdk.FaceInterface
|
|
|
import cn.face.sdk.FaceParam
|
|
|
-import com.ethan.psbc.R
|
|
|
import java.nio.ByteBuffer
|
|
|
import java.util.concurrent.ExecutorService
|
|
|
import java.util.concurrent.Executors
|
|
|
-import kotlin.math.cos
|
|
|
-import kotlin.math.max
|
|
|
import kotlin.math.min
|
|
|
-import kotlin.math.sin
|
|
|
|
|
|
-class CameraScanView(mContext: Context, attrs:AttributeSet?, defStyleAttr:Int) : SurfaceView(mContext,attrs,defStyleAttr) ,SurfaceHolder.Callback {
|
|
|
+class CameraScanView(mContext: Context, attrs:AttributeSet?, defStyleAttr:Int) : SurfaceView(mContext,attrs,defStyleAttr) {
|
|
|
|
|
|
constructor(context: Context) : this(context, null)
|
|
|
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
|
|
|
|
|
+ private val mLogger: org.slf4j.Logger = org.slf4j.LoggerFactory.getLogger(this.javaClass)
|
|
|
+
|
|
|
+ private lateinit var holder:SurfaceHolder
|
|
|
+
|
|
|
+ private var mSurfaceCallback= SurfaceCallback(mContext)
|
|
|
+
|
|
|
+ init {
|
|
|
+ holder=getHolder()
|
|
|
+ holder.addCallback(mSurfaceCallback)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
|
|
|
- private var mBackGroundPaint: Paint
|
|
|
- private var mCirclePaint: Paint
|
|
|
- private var mScanLinePaint: Paint
|
|
|
|
|
|
- //渐变色的起始值
|
|
|
- private var mStartColor: Int
|
|
|
- //渐变色的终止值
|
|
|
- private var mFinishColor: Int
|
|
|
|
|
|
- //圆形半径
|
|
|
- private var mRadius: Float
|
|
|
- //整个view的宽度
|
|
|
- private var mWidth: Float = 0.0f
|
|
|
- //整个view的高度度
|
|
|
- private var mHeight: Float = 0.0f
|
|
|
- //圆心的横坐标
|
|
|
- private var mCenterX: Float = 0.0f
|
|
|
- //圆心的纵坐标
|
|
|
- private var mCenterY: Float = 0.0f
|
|
|
|
|
|
- //扫描线(梯形)右上角的点对圆心的角度
|
|
|
- private var mDegree: Double = 0.0
|
|
|
- //扫描线(梯形)右下角的点对圆心的角度-右上角的点对圆心的角度的差值,体现为扫描线的线宽
|
|
|
- private var mDegreeAdd: Double = 1.0
|
|
|
|
|
|
- private val mXfermode: Xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)
|
|
|
- //遮罩的颜色
|
|
|
- private var mBackGroundColor: Int
|
|
|
- //扫描的动画时间
|
|
|
- private var mDuration: Int
|
|
|
- private var mAnimator: ValueAnimator? = null
|
|
|
|
|
|
- init {
|
|
|
- @SuppressLint("Recycle")
|
|
|
- val typedArray: TypedArray =
|
|
|
- context.obtainStyledAttributes(attrs, R.styleable.CameraScan)
|
|
|
-
|
|
|
- mBackGroundPaint = Paint()
|
|
|
- mBackGroundPaint.run {
|
|
|
- style = Paint.Style.FILL
|
|
|
- isAntiAlias = true // 设置抗锯齿
|
|
|
- isDither = true // 设置抖动
|
|
|
- }
|
|
|
|
|
|
- mBackGroundColor = typedArray.getColor(R.styleable.CameraScan_backGroundColor, Color.WHITE)
|
|
|
|
|
|
|
|
|
- mCirclePaint = Paint()
|
|
|
- mCirclePaint.run {
|
|
|
- style = Paint.Style.STROKE
|
|
|
- isAntiAlias = true
|
|
|
- isDither = true
|
|
|
- strokeWidth = typedArray.getDimension(R.styleable.CameraScan_circleWidth, 10f)
|
|
|
- color = typedArray.getColor(R.styleable.CameraScan_circleColor, Color.BLACK)
|
|
|
- }
|
|
|
- mRadius = typedArray.getDimension(R.styleable.CameraScan_circleRadius, 0.0f)
|
|
|
|
|
|
|
|
|
- mScanLinePaint = Paint()
|
|
|
- mScanLinePaint.run {
|
|
|
- style = Paint.Style.FILL
|
|
|
- strokeCap = Paint.Cap.ROUND
|
|
|
- isAntiAlias = true
|
|
|
- isDither = true
|
|
|
- color = Color.GREEN
|
|
|
- }
|
|
|
- mDegreeAdd = typedArray.getFloat(R.styleable.CameraScan_scanLineWidth, 1.0f).toDouble()
|
|
|
- mDuration = typedArray.getInt(R.styleable.CameraScan_scanDuration, 10000)
|
|
|
- mStartColor = typedArray.getColor(R.styleable.CameraScan_scanLineStartColor, -1)
|
|
|
- mFinishColor = typedArray.getColor(R.styleable.CameraScan_scanLineFinishColor, -1)
|
|
|
|
|
|
- typedArray.recycle()
|
|
|
- }
|
|
|
|
|
|
|
|
|
+
|
|
|
+ private var mWidth:Float=0.0f
|
|
|
+ private var mHeight:Float=0.0f
|
|
|
+ private var mCenterY:Float=0.0f
|
|
|
+ private var mCenterX:Float=0.0f
|
|
|
+ private var mRadius:Float=160f
|
|
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
|
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
|
|
mWidth = (measuredWidth - paddingLeft - paddingRight).toFloat()
|
|
|
mHeight = (measuredHeight - paddingTop - paddingBottom).toFloat()
|
|
|
-
|
|
|
mCenterX = mWidth / 2
|
|
|
mCenterY = mHeight / 2
|
|
|
|
|
@@ -126,186 +77,206 @@ class CameraScanView(mContext: Context, attrs:AttributeSet?, defStyleAttr:Int) :
|
|
|
if (mRadius == 0.0f || mRadius * 2 > short) {
|
|
|
mRadius = short / 2
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ mSurfaceCallback.mCenterX=this@CameraScanView.mCenterX;
|
|
|
+ mSurfaceCallback.mCenterY=this@CameraScanView.mCenterY;
|
|
|
+ mSurfaceCallback.mRadius=this@CameraScanView.mRadius;
|
|
|
}
|
|
|
|
|
|
- override fun onDraw(canvas: Canvas) {
|
|
|
- super.onDraw(canvas)
|
|
|
|
|
|
- //绘制黑色遮罩,先绘制黑色背景,再绘制透明圆形
|
|
|
- mBackGroundPaint.color = Color.BLACK //随便设个颜色值,只要不是透明的就行,防止第二次绘制时,mBackGroundPaint.color 被下面赋值了Color.TRANSPARENT 导致canvas.drawColor(mBackGroundColor)不起效果
|
|
|
- val layerID = canvas.saveLayer(0.0f, 0.0f, mWidth, mHeight, mBackGroundPaint, ALL_SAVE_FLAG) //保存图层,下面通过estoreToCount恢复
|
|
|
- canvas.drawColor(mBackGroundColor) //遮罩的颜色
|
|
|
- mBackGroundPaint.xfermode = mXfermode //这里选择DST_ATOP
|
|
|
- mBackGroundPaint.color = Color.TRANSPARENT //颜色设置成透明
|
|
|
- canvas.drawCircle(mCenterX, mCenterY, mRadius, mBackGroundPaint) //透明的圆形
|
|
|
- mBackGroundPaint.xfermode = null
|
|
|
- canvas.restoreToCount(layerID)
|
|
|
|
|
|
- //绘制白色框,圆弧
|
|
|
- canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint)
|
|
|
|
|
|
|
|
|
- //角度制转弧度制
|
|
|
- val radians = Math.toRadians(mDegree).toFloat()
|
|
|
- val radiansAdd = Math.toRadians(mDegree + mDegreeAdd).toFloat()
|
|
|
|
|
|
- //着色器,实现扫描线的渐变效果
|
|
|
- takeIf { mStartColor != -1 && mFinishColor != -1 }?.run {
|
|
|
- val y0 = mCenterY - mRadius * cos(radians)
|
|
|
- val y1 = mCenterY - mRadius * cos(radiansAdd)
|
|
|
- mScanLinePaint.shader = LinearGradient(0.0f, max(y0, y1), 0.0f, min(y0, y1), mStartColor, mFinishColor, Shader.TileMode.CLAMP)
|
|
|
- }
|
|
|
|
|
|
- //绘制扫描线,梯形
|
|
|
- val path = Path()
|
|
|
- path.moveTo(mCenterX + mRadius * sin(-radians), mCenterY - mRadius * cos(radians))
|
|
|
- path.lineTo(mCenterX + mRadius * sin(radians), mCenterY - mRadius * cos(radians))
|
|
|
- path.lineTo(mCenterX + mRadius * sin(radiansAdd), mCenterY - mRadius * cos(radiansAdd))
|
|
|
- path.lineTo(mCenterX + mRadius * sin(-radiansAdd), mCenterY - mRadius * cos(radiansAdd))
|
|
|
- path.close()
|
|
|
- canvas.drawPath(path, mScanLinePaint)
|
|
|
- }
|
|
|
|
|
|
|
|
|
- //扫描动画,通过改变角度,实现扫描线上下移动
|
|
|
- fun startScan() {
|
|
|
- mAnimator?.run { cancel() }
|
|
|
- mAnimator = ValueAnimator.ofFloat(0.0f, 360.0f)
|
|
|
- mAnimator?.let {
|
|
|
- it.addUpdateListener { animation ->
|
|
|
- this.mDegree = (animation.animatedValue as Float).toDouble()
|
|
|
- invalidate()
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ class SurfaceCallback() :SurfaceHolder.Callback{
|
|
|
+
|
|
|
+ constructor(tContext:Context) : this() {
|
|
|
+ this.tContext=tContext
|
|
|
}
|
|
|
- it.duration = mDuration.toLong()
|
|
|
- it.interpolator = LinearInterpolator()
|
|
|
- it.repeatCount = ValueAnimator.INFINITE
|
|
|
- it.repeatMode = ValueAnimator.RESTART
|
|
|
- it.start()
|
|
|
- }
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ private lateinit var cameraExecutor: ExecutorService
|
|
|
+ private var cameraProvider: ProcessCameraProvider? = null
|
|
|
+ private var preview: Preview? = null
|
|
|
+ private var imageCamera: ImageCapture? = null
|
|
|
+ private lateinit var camera: Camera //相机对象
|
|
|
+ private lateinit var imageAnalysis: ImageAnalysis
|
|
|
+ private lateinit var tContext: Context
|
|
|
|
|
|
- override fun surfaceCreated(holder: SurfaceHolder) {
|
|
|
+ private val licence:String="MDQwNTE3NWQyNTkzNGM4MmQ3ZDk2MmQyM2UzODBhMmI1YjFjNjdjd2F1dGhvcml6Zd3n5+Xk5+fk/OXm5+fg5ef15efn5+Xk4Mfl4OXm5uvliObm6+Xm5uuR5ebm6+Xm5qLr5ebm6+Xmrubg5ufr5+v95+vn4OTk59Dk5ubr5+vn1uvn5+fm5Of+5g=="
|
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
- override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
|
|
- TODO("Not yet implemented")
|
|
|
- }
|
|
|
|
|
|
- override fun surfaceDestroyed(holder: SurfaceHolder) {
|
|
|
- TODO("Not yet implemented")
|
|
|
- }
|
|
|
+ var mCenterY:Float=0.0f
|
|
|
+ var mCenterX:Float=0.0f
|
|
|
+ var mRadius:Float=160f
|
|
|
|
|
|
|
|
|
+ override fun surfaceCreated(holder: SurfaceHolder) {
|
|
|
|
|
|
- private lateinit var cameraExecutor: ExecutorService
|
|
|
- private var cameraProvider: ProcessCameraProvider? = null
|
|
|
- private var preview: Preview? = null
|
|
|
- private var imageCamera: ImageCapture? = null
|
|
|
- private lateinit var camera: Camera //相机对象
|
|
|
- private lateinit var imageAnalysis: ImageAnalysis
|
|
|
|
|
|
- private val licence:String="MDQwNTE3NWQyNTkzNGM4MmQ3ZDk2MmQyM2UzODBhMmI1YjFjNjdjd2F1dGhvcml6Zd3n5+Xk5+fk/OXm5+fg5ef15efn5+Xk4Mfl4OXm5uvliObm6+Xm5uuR5ebm6+Xm5qLr5ebm6+Xmrubg5ufr5+v95+vn4OTk59Dk5ubr5+vn1uvn5+fm5Of+5g=="
|
|
|
+ val canvas: Canvas =holder.lockCanvas()
|
|
|
+ var backLayer=Paint();
|
|
|
+ backLayer.run {
|
|
|
|
|
|
+ style = Paint.Style.FILL
|
|
|
+ isAntiAlias = true // 设置抗锯齿
|
|
|
+ isDither = true // 设置抖动
|
|
|
|
|
|
+ }
|
|
|
+ backLayer.color=Color.TRANSPARENT
|
|
|
+ var layerId=canvas.saveLayer(0.0F,0.0F,0.0F,0.0F,backLayer)
|
|
|
+ canvas.drawColor(Color.TRANSPARENT)
|
|
|
+ backLayer.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_ATOP) //这里选择DST_ATOP
|
|
|
+ backLayer.color = Color.TRANSPARENT //颜色设置成透明
|
|
|
+ canvas.drawCircle(mCenterX, mCenterY, mRadius, backLayer) //透明的圆形
|
|
|
+ backLayer.xfermode = null
|
|
|
+ canvas.restoreToCount(layerId)
|
|
|
|
|
|
|
|
|
- fun runCamera(context: Context){
|
|
|
|
|
|
- if( PackageManager.PERMISSION_GRANTED!= ContextCompat.checkSelfPermission(context , Manifest.permission.CAMERA)){
|
|
|
- ActivityCompat.requestPermissions(context as AppCompatActivity, arrayOf(Manifest.permission.CAMERA),1)
|
|
|
- Toast.makeText(context as AppCompatActivity, "申请相机权限", Toast.LENGTH_SHORT).show()
|
|
|
- }else{
|
|
|
- Toast.makeText(context as AppCompatActivity, "已经拥有相机权限", Toast.LENGTH_SHORT).show()
|
|
|
+
|
|
|
+
|
|
|
+ val mCirclePaint= Paint()
|
|
|
+ mCirclePaint.run {
|
|
|
+ style = Paint.Style.STROKE
|
|
|
+ isAntiAlias = true
|
|
|
+ isDither = true
|
|
|
+ strokeWidth =10f
|
|
|
+ color = Color.WHITE
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //绘制白色框,圆弧
|
|
|
+ canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint)
|
|
|
+
|
|
|
+ holder.unlockCanvasAndPost(canvas);
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
|
|
+ runCamera(tContext,holder)
|
|
|
}
|
|
|
|
|
|
+ override fun surfaceDestroyed(holder: SurfaceHolder) {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ fun runCamera(context: Context,holder: SurfaceHolder){
|
|
|
+
|
|
|
+ if( PackageManager.PERMISSION_GRANTED!= ContextCompat.checkSelfPermission(context , Manifest.permission.CAMERA)){
|
|
|
+ ActivityCompat.requestPermissions(context as AppCompatActivity, arrayOf(Manifest.permission.CAMERA),1)
|
|
|
+ Toast.makeText(context as AppCompatActivity, "申请相机权限", Toast.LENGTH_SHORT).show()
|
|
|
+ }else{
|
|
|
+ Toast.makeText(context as AppCompatActivity, "已经拥有相机权限", Toast.LENGTH_SHORT).show()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ val cameraSelector: CameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
|
|
|
+ // mBinding.btnDemoView.implementationMode= PreviewView.ImplementationMode.COMPATIBLE
|
|
|
+
|
|
|
|
|
|
- val cameraSelector: CameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
|
|
|
- // mBinding.btnDemoView.implementationMode= PreviewView.ImplementationMode.COMPATIBLE
|
|
|
|
|
|
|
|
|
+ cameraExecutor = Executors.newSingleThreadExecutor()
|
|
|
+ val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
|
|
|
+ cameraProviderFuture.addListener({
|
|
|
+ cameraProvider = cameraProviderFuture.get()//获取相机信息
|
|
|
|
|
|
+ //预览配置
|
|
|
+ preview = Preview.Builder()
|
|
|
+ .build()
|
|
|
|
|
|
- cameraExecutor = Executors.newSingleThreadExecutor()
|
|
|
- val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
|
|
|
- cameraProviderFuture.addListener({
|
|
|
- cameraProvider = cameraProviderFuture.get()//获取相机信息
|
|
|
|
|
|
- //预览配置
|
|
|
- preview = Preview.Builder()
|
|
|
- .build()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+ imageCamera = ImageCapture.Builder()
|
|
|
+ .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
|
|
|
+ .build()
|
|
|
|
|
|
|
|
|
- imageCamera = ImageCapture.Builder()
|
|
|
- .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
|
|
|
- .build()
|
|
|
+ imageAnalysis = ImageAnalysis.Builder()
|
|
|
+ .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
|
|
+ .build()
|
|
|
|
|
|
|
|
|
- imageAnalysis = ImageAnalysis.Builder()
|
|
|
- .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
|
|
- .build()
|
|
|
+ imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy ->
|
|
|
+ val planes: Array<ImageProxy.PlaneProxy> = imageProxy.planes
|
|
|
+ val buffer: ByteBuffer = planes[0].buffer;
|
|
|
+ val data: ByteArray = ByteArray(buffer.capacity())
|
|
|
+ buffer.rewind()
|
|
|
+ buffer.get(data)
|
|
|
|
|
|
|
|
|
- imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy ->
|
|
|
- val planes: Array<ImageProxy.PlaneProxy> = imageProxy.planes
|
|
|
- val buffer: ByteBuffer = planes[0].buffer;
|
|
|
- val data: ByteArray = ByteArray(buffer.capacity())
|
|
|
- buffer.rewind()
|
|
|
- buffer.get(data)
|
|
|
|
|
|
+ Log.d("demo", "正在识别图像信息")
|
|
|
+ FaceDetTrack.getInstance()
|
|
|
+ val ret: Int = FaceDetTrack.cwCreateDetHandle("", licence)
|
|
|
+ if (ret >= FaceInterface.cw_errcode_t.CW_UNKNOWN_ERR) {
|
|
|
+ Log.d("demo", "启用识别程序SDK失败")
|
|
|
+ } else {
|
|
|
+ Log.d("demo", "启用识别程序SDK成功")
|
|
|
+ val faceParam = FaceParam()
|
|
|
+ FaceDetTrack.cwGetFaceParam(ret, faceParam)
|
|
|
+ faceParam.minSize = 30
|
|
|
+ faceParam.maxSize = 400;
|
|
|
+ FaceDetTrack.cwSetFaceParam(ret, faceParam, "");
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- Log.d("demo", "正在识别图像信息")
|
|
|
- FaceDetTrack.getInstance()
|
|
|
- val ret: Int = FaceDetTrack.cwCreateDetHandle("", licence)
|
|
|
- if (ret >= FaceInterface.cw_errcode_t.CW_UNKNOWN_ERR) {
|
|
|
- Log.d("demo", "启用识别程序SDK失败")
|
|
|
- } else {
|
|
|
- Log.d("demo", "启用识别程序SDK成功")
|
|
|
- val faceParam = FaceParam()
|
|
|
- FaceDetTrack.cwGetFaceParam(ret, faceParam)
|
|
|
- faceParam.minSize = 30
|
|
|
- faceParam.maxSize = 400;
|
|
|
- FaceDetTrack.cwSetFaceParam(ret, faceParam, "");
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+ imageProxy.close()
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+ try {
|
|
|
+ cameraProvider?.unbindAll()//先解绑所有用例
|
|
|
+ camera = cameraProvider?.bindToLifecycle(
|
|
|
+ context,
|
|
|
+ cameraSelector,
|
|
|
+ preview,
|
|
|
+ imageCamera,
|
|
|
+ imageAnalysis
|
|
|
+ )!!//绑定用例
|
|
|
+ } catch (_: Exception) {
|
|
|
|
|
|
- imageProxy.close()
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
|
|
- try {
|
|
|
- cameraProvider?.unbindAll()//先解绑所有用例
|
|
|
- camera = cameraProvider?.bindToLifecycle(
|
|
|
- context,
|
|
|
- cameraSelector,
|
|
|
- preview,
|
|
|
- imageCamera,
|
|
|
- imageAnalysis
|
|
|
- )!!//绑定用例
|
|
|
- } catch (_: Exception) {
|
|
|
|
|
|
- }
|
|
|
+ //preview?.setSurfaceProvider()
|
|
|
+
|
|
|
|
|
|
- preview?.setSurfaceProvider(null)
|
|
|
|
|
|
+ }, ContextCompat.getMainExecutor(context))
|
|
|
+ }
|
|
|
|
|
|
|
|
|
- }, ContextCompat.getMainExecutor(context))
|
|
|
}
|
|
|
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
-}
|