Merge branch 'master' of gitlab.navinfo.com:CollectVehicle/OneMapQS

 Conflicts:
	vtm
This commit is contained in:
squallzhjch
2023-06-29 17:23:12 +08:00
53 changed files with 1142 additions and 68 deletions

View File

@@ -37,7 +37,8 @@ public class CheckPermissionsActivity extends BaseActivity {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.RECORD_AUDIO
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA,
};
private static final int PERMISSON_REQUESTCODE = 0;
@@ -53,6 +54,7 @@ public class CheckPermissionsActivity extends BaseActivity {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA,
BACKGROUND_LOCATION_PERMISSION
};
}

View File

@@ -0,0 +1,256 @@
package com.navinfo.omqs.ui.activity.scan
import android.content.Context
import android.text.TextUtils
import android.widget.Toast
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.navinfo.omqs.Constant
import com.navinfo.omqs.bean.IndoorConnectionInfoBean
import com.navinfo.omqs.bean.QRCodeBean
import com.navinfo.omqs.bean.SysUserBean
import com.navinfo.omqs.http.DefaultResponse
import com.navinfo.omqs.http.NetResult
import com.navinfo.omqs.http.NetworkService
import com.navinfo.omqs.ui.activity.login.LoginStatus
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.IOException
import javax.inject.Inject
enum class QrCodeStatus {
/**
* 网络访问失败
*/
QR_CODE_STATUS_NET_FAILURE,
/**
* 成功
*/
QR_CODE_STATUS_SUCCESS,
/**
* 信息更新成功
*/
QR_CODE_STATUS_SERVER_INFO_SUCCESS,
}
@HiltViewModel
class QrCodeViewModel @Inject constructor(
private val networkService: NetworkService
) : ViewModel() {
//用户信息
val qrCodeBean: MutableLiveData<QRCodeBean> = MutableLiveData()
//是不是连接成功
val qrCodeStatus: MutableLiveData<QrCodeStatus> = MutableLiveData()
init {
qrCodeBean.value = QRCodeBean()
}
/**
* 扫一扫按钮
*/
fun connect(context: Context, ips: String) {
if (TextUtils.isEmpty(ips)) {
Toast.makeText(context, "获取ip失败", Toast.LENGTH_LONG).show()
return
}
val ipArray = ips.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
//测试代码
//final String[] ipArray = new String[]{"172.21.2.137"};
if (ipArray.isEmpty()) {
Toast.makeText(context, "获取ip失败", Toast.LENGTH_SHORT).show()
return
}
ipArray.forEach { ip ->
if (!TextUtils.isEmpty(ip)) {
viewModelScope.launch(Dispatchers.Default) {
val ipTemp: String = ip
val url = "http://$ipTemp:8080/sensor/service/keepalive"
when (val result = networkService.connectIndoorTools(url)) {
is NetResult.Success<*> -> {
if (result.data != null) {
try {
val defaultUserResponse = result.data as QRCodeBean
if (defaultUserResponse.errcode == 0) {
Constant.INDOOR_IP = ipTemp
qrCodeStatus.postValue(QrCodeStatus.QR_CODE_STATUS_SUCCESS)
withContext(Dispatchers.Main) {
Toast.makeText(
context,
"连接室内整理工具成功。",
Toast.LENGTH_LONG
).show()
}
} else {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
"${defaultUserResponse.msg}",
Toast.LENGTH_SHORT
)
.show()
}
}
} catch (e: IOException) {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
"${e.message}",
Toast.LENGTH_SHORT
).show()
}
}
}
}
is NetResult.Error<*> -> {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
"${result.exception.message}",
Toast.LENGTH_SHORT
)
.show()
}
qrCodeStatus.postValue(QrCodeStatus.QR_CODE_STATUS_NET_FAILURE)
}
is NetResult.Failure<*> -> {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
"${result.code}:${result.msg}",
Toast.LENGTH_SHORT
)
.show()
}
qrCodeStatus.postValue(QrCodeStatus.QR_CODE_STATUS_NET_FAILURE)
}
else -> {}
}
}
}
}
}
/**
* 扫一扫按钮
*/
fun updateServerInfo(context: Context) {
if (TextUtils.isEmpty(Constant.INDOOR_IP)) {
Toast.makeText(context, "获取ip失败", Toast.LENGTH_LONG).show()
return
}
viewModelScope.launch(Dispatchers.Default) {
val url = "http://${Constant.INDOOR_IP}:8080/sensor/service/connection"
when (val result = networkService.updateServerInfo(
url = url,
indoorConnectionInfoBean = IndoorConnectionInfoBean(
Constant.USER_ID,
Constant.USER_ID,
Constant.USER_ID,
Constant.USER_ID,
com.navinfo.collect.library.system.Constant.SERVER_ADDRESS,
Constant.USER_ID,
"Android"
)
)) {
is NetResult.Success<*> -> {
if (result.data != null) {
try {
val defaultUserResponse = result.data as QRCodeBean
if (defaultUserResponse.errcode == 0) {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
"信息更新成功。",
Toast.LENGTH_LONG
).show()
qrCodeStatus.postValue(QrCodeStatus.QR_CODE_STATUS_SERVER_INFO_SUCCESS)
}
} else {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
"${defaultUserResponse.msg}",
Toast.LENGTH_SHORT
)
.show()
}
}
} catch (e: IOException) {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
"${e.message}",
Toast.LENGTH_SHORT
).show()
}
}
}
}
is NetResult.Error<*> -> {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
"${result.exception.message}",
Toast.LENGTH_SHORT
)
.show()
}
qrCodeStatus.postValue(QrCodeStatus.QR_CODE_STATUS_NET_FAILURE)
}
is NetResult.Failure<*> -> {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
"${result.code}:${result.msg}",
Toast.LENGTH_SHORT
)
.show()
}
qrCodeStatus.postValue(QrCodeStatus.QR_CODE_STATUS_NET_FAILURE)
}
else -> {}
}
}
}
override fun onCleared() {
super.onCleared()
}
}

View File

@@ -0,0 +1,147 @@
package com.navinfo.omqs.ui.activity.scan
import android.annotation.SuppressLint
import android.graphics.Rect
import android.graphics.RectF
import android.os.Bundle
import android.util.Log
import androidx.activity.viewModels
import androidx.camera.core.ImageCapture
import androidx.camera.view.LifecycleCameraController
import androidx.databinding.DataBindingUtil
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.ActivityQrCodeBinding
import com.navinfo.omqs.ui.activity.BaseActivity
import com.navinfo.omqs.ui.listener.QRCodeAnalyser
import dagger.hilt.android.AndroidEntryPoint
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import androidx.lifecycle.Observer
import com.navinfo.omqs.ui.activity.login.LoginStatus
/**
* date:2023/6/18
* author:qj
* description:二维码扫描
*/
@AndroidEntryPoint
class QrCodeActivity : BaseActivity() {
private lateinit var binding: ActivityQrCodeBinding
private lateinit var lifecycleCameraController: LifecycleCameraController
private lateinit var cameraExecutor: ExecutorService
private val viewModel by viewModels<QrCodeViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_qr_code)
binding.qrCodeModel = viewModel
binding.lifecycleOwner = this
binding.activity = this
initView()
initController()
}
private fun initView() {
//登录校验,初始化成功
viewModel.qrCodeStatus.observe(this, qrCodeObserve)
}
/*
* 监听扫描结果
* */
private val qrCodeObserve = Observer<QrCodeStatus> {
when (it) {
QrCodeStatus.QR_CODE_STATUS_SUCCESS -> {
finish()
}
QrCodeStatus.QR_CODE_STATUS_NET_FAILURE -> {
}
QrCodeStatus.QR_CODE_STATUS_SERVER_INFO_SUCCESS -> {
}
}
}
@SuppressLint("ClickableViewAccessibility", "UnsafeOptInUsageError")
private fun initController() {
cameraExecutor = Executors.newSingleThreadExecutor()
lifecycleCameraController = LifecycleCameraController(this)
lifecycleCameraController.bindToLifecycle(this)
lifecycleCameraController.imageCaptureFlashMode = ImageCapture.FLASH_MODE_AUTO
lifecycleCameraController.setImageAnalysisAnalyzer(
cameraExecutor,
QRCodeAnalyser { barcodes, imageWidth, imageHeight ->
if (barcodes.isEmpty()) {
return@QRCodeAnalyser
}
initScale(imageWidth, imageHeight)
val list = ArrayList<RectF>()
val strList = ArrayList<String>()
barcodes.forEach { barcode ->
barcode.boundingBox?.let { rect ->
val translateRect = translateRect(rect)
list.add(translateRect)
Log.e(
"ztzt", "left${translateRect.left} +" +
" top${translateRect.top} + right${translateRect.right}" +
" + bottom${translateRect.bottom}"
)
Log.e("ztzt", "barcode.rawValue${barcode.rawValue}")
strList.add(barcode.rawValue ?: "No Value")
}
}
judgeIntent(strList)
binding.scanView.setRectList(list)
})
binding.previewView.controller = lifecycleCameraController
}
fun judgeIntent(list: ArrayList<String>) {
val sb = StringBuilder()
list.forEach {
sb.append(it)
sb.append("\n")
}
intentToResult(sb.toString())
}
private fun intentToResult(result: String) {
Log.e("qj", "QRCodeActivity === $result")
viewModel.connect(this, result)
/* val intent = Intent(this, QRCodeResultActivity::class.java)
intent.putExtra(QRCodeResultActivity.RESULT_KEY, result)
startActivity(intent)
finish()*/
}
private var scaleX = 0f
private var scaleY = 0f
private fun translateX(x: Float): Float = x * scaleX
private fun translateY(y: Float): Float = y * scaleY
//将扫描的矩形换算为当前屏幕大小
private fun translateRect(rect: Rect) = RectF(
translateX(rect.left.toFloat()),
translateY(rect.top.toFloat()),
translateX(rect.right.toFloat()),
translateY(rect.bottom.toFloat())
)
//初始化缩放比例
private fun initScale(imageWidth: Int, imageHeight: Int) {
Log.e("ztzt", "imageWidth${imageWidth} + imageHeight${imageHeight}")
scaleY = binding.scanView.height.toFloat() / imageWidth.toFloat()
scaleX = binding.scanView.width.toFloat() / imageHeight.toFloat()
Log.e("ztzt", "scaleX${scaleX} + scaleY${scaleY}")
}
}

View File

@@ -0,0 +1,30 @@
package com.navinfo.omqs.ui.activity.scan
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.navinfo.omqs.databinding.ActivityResultBinding
/**
* date:2021/6/18
* author:zhangteng
* description:
*/
class QRCodeResultActivity : AppCompatActivity() {
private lateinit var binding: ActivityResultBinding
companion object {
const val RESULT_KEY = "result_key";
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityResultBinding.inflate(layoutInflater)
setContentView(binding.root)
val intent = intent
binding.text.text = intent.getStringExtra(RESULT_KEY)
binding.button.setOnClickListener {
finish()
}
}
}

View File

@@ -26,6 +26,7 @@ import com.navinfo.collect.library.utils.GeometryTools
import com.navinfo.omqs.Constant
import com.navinfo.omqs.R
import com.navinfo.omqs.bean.ChatMsgEntity
import com.navinfo.omqs.bean.ScProblemTypeBean
import com.navinfo.omqs.bean.SignBean
import com.navinfo.omqs.db.RealmOperateHelper
import com.navinfo.omqs.db.RoomAppDatabase
@@ -65,7 +66,7 @@ class EvaluationResultViewModel @Inject constructor(
/**
* 问题分类 liveData给[LeftAdapter]展示的数据
*/
val liveDataLeftTypeList = MutableLiveData<List<String>>()
val liveDataLeftTypeList = MutableLiveData<List<ScProblemTypeBean>>()
/**
* 问题类型 liveData 给[MiddleAdapter]展示的数据
@@ -95,6 +96,8 @@ class EvaluationResultViewModel @Inject constructor(
var classTypeTemp: String = ""
var classCodeTemp: String = ""
init {
liveDataQsRecordBean.value = QsRecordBean(id = UUID.randomUUID().toString())
viewModelScope.launch {
@@ -194,22 +197,24 @@ class EvaluationResultViewModel @Inject constructor(
list?.let {
if (list.isNotEmpty()) {
//通知页面更新
var classType = list[0]
var classType = list[0].classType
var classCode = list[0].elementCode
liveDataLeftTypeList.postValue(it)
if (bean != null) {
val classType2 = roomAppDatabase.getScProblemTypeDao()
.findClassTypeByCode(bean.renderEntity.code)
val classType2 = roomAppDatabase.getScProblemTypeDao().findClassTypeByCode(bean.renderEntity.code)
if (classType2 != null) {
classType = classType2
}
}
//如果右侧栏没数据,给个默认值
if (liveDataQsRecordBean.value!!.classType.isEmpty()) {
liveDataQsRecordBean.value!!.classType = classType
liveDataQsRecordBean.value!!.classCode = classCode
classTypeTemp = classType
classCodeTemp = classCode
} else {
classType = liveDataQsRecordBean.value!!.classType
classCode = liveDataQsRecordBean.value!!.classCode
}
getProblemList(classType)
}
@@ -298,6 +303,7 @@ class EvaluationResultViewModel @Inject constructor(
*/
fun setPhenomenonMiddleBean(adapterBean: RightBean) {
liveDataQsRecordBean.value!!.classType = classTypeTemp
liveDataQsRecordBean.value!!.classCode = classCodeTemp
liveDataQsRecordBean.value!!.phenomenon = adapterBean.text
liveDataQsRecordBean.value!!.problemType = adapterBean.title
liveDataQsRecordBean.postValue(liveDataQsRecordBean.value)

View File

@@ -5,12 +5,13 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import com.navinfo.omqs.R
import com.navinfo.omqs.bean.ScProblemTypeBean
import com.navinfo.omqs.databinding.TextItemSelectBinding
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder
class LeftAdapter(private var itemListener: ((Int, String) -> Unit?)? = null) :
BaseRecyclerViewAdapter<String>() {
BaseRecyclerViewAdapter<ScProblemTypeBean>() {
private var selectTitle = ""
@@ -24,18 +25,18 @@ class LeftAdapter(private var itemListener: ((Int, String) -> Unit?)? = null) :
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
val bd = holder.viewBinding as TextItemSelectBinding
val title = data[position]
bd.itemId.text = title
holder.viewBinding.root.isSelected = selectTitle == title
bd.itemId.text = title.classType
holder.viewBinding.root.isSelected = selectTitle == title.classType
bd.root.setOnClickListener {
if (selectTitle != title) {
selectTitle = title
if (selectTitle != title.classType) {
selectTitle = title.classType
notifyDataSetChanged()
}
itemListener?.invoke(position, title)
itemListener?.invoke(position, title.classType)
}
}
override fun refreshData(newData: List<String>) {
override fun refreshData(newData: List<ScProblemTypeBean>) {
data = newData
notifyDataSetChanged()
}

View File

@@ -1,13 +1,14 @@
package com.navinfo.omqs.ui.fragment.personalcenter
import android.Manifest
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.blankj.utilcode.util.ToastUtils
import com.blankj.utilcode.util.UriUtils
@@ -21,6 +22,8 @@ import com.navinfo.omqs.db.ImportOMDBHelper
import com.navinfo.omqs.hilt.ImportOMDBHiltFactory
import com.navinfo.omqs.tools.CoroutineUtils
import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.activity.scan.QrCodeActivity
import com.permissionx.guolindev.PermissionX
import dagger.hilt.android.AndroidEntryPoint
import org.oscim.core.GeoPoint
import javax.inject.Inject
@@ -123,6 +126,16 @@ class PersonalCenterFragment(private var backListener: (() -> Unit?)? = null) :
// R.id.personal_center_menu_layer_manager -> { // 图层管理
// findNavController().navigate(R.id.QsLayerManagerFragment)
// }
/* R.id.personal_center_menu_qs_record_list -> {
findNavController().navigate(R.id.QsRecordListFragment)
}
R.id.personal_center_menu_layer_manager -> { // 图层管理
findNavController().navigate(R.id.QsLayerManagerFragment)
}*/
R.id.personal_center_menu_scan_qr_code -> {
//跳转二维码扫描界面
checkPermission()
}
}
true
}
@@ -134,6 +147,11 @@ class PersonalCenterFragment(private var backListener: (() -> Unit?)? = null) :
fileChooser.setCallbacks(this@PersonalCenterFragment)
}
private fun intentTOQRCode() {
var intent = Intent(context, QrCodeActivity::class.java);
startActivity(intent)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
@@ -147,4 +165,18 @@ class PersonalCenterFragment(private var backListener: (() -> Unit?)? = null) :
super.onActivityResult(requestCode, resultCode, data)
fileChooser.onActivityResult(requestCode, resultCode, data)
}
private fun checkPermission() {
PermissionX.init(this)
.permissions(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
.request { allGranted, grantedList, deniedList ->
if (allGranted) {
//所有权限已经授权
Toast.makeText(context,"授权成功",Toast.LENGTH_LONG).show()
intentTOQRCode()
} else {
Toast.makeText(context, "拒绝权限: $deniedList", Toast.LENGTH_LONG).show()
}
}
}
}

View File

@@ -4,6 +4,7 @@ import android.content.Context
import android.graphics.Color
import android.os.Build
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@@ -95,18 +96,21 @@ class TaskViewModel @Inject constructor(
}
}
}
is NetResult.Error<*> -> {
withContext(Dispatchers.Main) {
Toast.makeText(context, "${result.exception.message}", Toast.LENGTH_SHORT)
.show()
}
}
is NetResult.Failure<*> -> {
withContext(Dispatchers.Main) {
Toast.makeText(context, "${result.code}:${result.msg}", Toast.LENGTH_SHORT)
.show()
}
}
is NetResult.Loading -> {}
}
val realm = Realm.getDefaultInstance()
@@ -139,41 +143,42 @@ class TaskViewModel @Inject constructor(
/**
* 设置当前选择的任务并高亮当前任务的所有link
*/
@RequiresApi(Build.VERSION_CODES.M)
fun setSelectTaskBean(taskBean: TaskBean) {
currentSelectTaskBean = taskBean
liveDataTaskLinks.value = taskBean.hadLinkDvoList
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mapController.lineHandler.omdbTaskLinkLayer.removeAll()
if(taskBean.hadLinkDvoList.isNotEmpty()){
mapController.lineHandler.omdbTaskLinkLayer.addLineList(taskBean.hadLinkDvoList)
var maxX = 0.0
var maxY = 0.0
var minX = 0.0
var minY = 0.0
for (item in taskBean.hadLinkDvoList) {
val geometry = GeometryTools.createGeometry(item.geometry)
if(geometry!=null){
val envelope = geometry.envelopeInternal
if (envelope.maxX > maxX) {
maxX = envelope.maxX
}
if (envelope.maxY > maxY) {
maxY = envelope.maxY
}
if (envelope.minX < minX || minX == 0.0) {
minX = envelope.minX
}
if (envelope.minY < minY || minY == 0.0) {
minY = envelope.minY
}
mapController.lineHandler.omdbTaskLinkLayer.removeAll()
if (taskBean.hadLinkDvoList.isNotEmpty()) {
mapController.lineHandler.omdbTaskLinkLayer.addLineList(taskBean.hadLinkDvoList)
var maxX = 0.0
var maxY = 0.0
var minX = 0.0
var minY = 0.0
for (item in taskBean.hadLinkDvoList) {
val geometry = GeometryTools.createGeometry(item.geometry)
if (geometry != null) {
val envelope = geometry.envelopeInternal
if (envelope.maxX > maxX) {
maxX = envelope.maxX
}
if (envelope.maxY > maxY) {
maxY = envelope.maxY
}
if (envelope.minX < minX || minX == 0.0) {
minX = envelope.minX
}
if (envelope.minY < minY || minY == 0.0) {
minY = envelope.minY
}
}
//增加异常数据判断
if(maxX!=0.0&&maxY!=0.0&&minX!=0.0&&minY!=0.0){
mapController.animationHandler.animateToBox(
maxX = maxX, maxY = maxY, minX = minX, minY = minY
)
}
}
//增加异常数据判断
if (maxX != 0.0 && maxY != 0.0 && minX != 0.0 && minY != 0.0) {
mapController.animationHandler.animateToBox(
maxX = maxX, maxY = maxY, minX = minX, minY = minY
)
}
}
}
@@ -181,20 +186,20 @@ class TaskViewModel @Inject constructor(
/**
* 高亮当前选中的link
*/
@RequiresApi(Build.VERSION_CODES.M)
fun showCurrentLink(link: HadLinkDvoBean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mapController.lineHandler.omdbTaskLinkLayer.showSelectLine(link)
val geometry = GeometryTools.createGeometry(link.geometry)
if(geometry!=null){
val envelope = geometry.envelopeInternal
mapController.animationHandler.animateToBox(
maxX = envelope.maxX,
maxY = envelope.maxY,
minX = envelope.minX,
minY = envelope.minY
)
}
mapController.lineHandler.omdbTaskLinkLayer.showSelectLine(link)
val geometry = GeometryTools.createGeometry(link.geometry)
if (geometry != null) {
val envelope = geometry.envelopeInternal
mapController.animationHandler.animateToBox(
maxX = envelope.maxX,
maxY = envelope.maxY,
minX = envelope.minX,
minY = envelope.minY
)
}
}
override fun onCleared() {

View File

@@ -0,0 +1,43 @@
package com.navinfo.omqs.ui.listener
import android.annotation.SuppressLint
import android.util.Log
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.Barcode
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.common.InputImage
class QRCodeAnalyser(private val listener: (List<Barcode>, Int, Int) -> Unit) :
ImageAnalysis.Analyzer {
//配置当前扫码格式
private val options = BarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.FORMAT_QR_CODE,
Barcode.FORMAT_AZTEC
).build()
//获取解析器
private val detector = BarcodeScanning.getClient(options)
@SuppressLint("UnsafeExperimentalUsageError", "UnsafeOptInUsageError")
override fun analyze(imageProxy: ImageProxy) {
val mediaImage = imageProxy.image ?: kotlin.run {
imageProxy.close()
return
}
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
detector.process(image)
.addOnSuccessListener { barCodes ->
Log.e("ztzt", "barCodes: ${barCodes.size}")
if (barCodes.size > 0) {
listener.invoke(barCodes, imageProxy.width, imageProxy.height)
//接收到结果后,就关闭解析
detector.close()
}
}
.addOnFailureListener { Log.e("ztzt", "Error: ${it.message}") }
.addOnCompleteListener { imageProxy.close() }
}
}

View File

@@ -0,0 +1,88 @@
package com.navinfo.omqs.ui.widget
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import androidx.core.content.ContextCompat
import com.navinfo.omqs.R
/**
* Author:zhangteng
* description:
* date2021/6/19
*/
class ScanView(context: Context, attrs: AttributeSet) : View(context, attrs) {
private val circlePaint = Paint() //二维码圆圈画笔
private var rectList: ArrayList<RectF>? = null //二维码数组
private var scanLine: Bitmap//横线
private var isShowLine = true//是否显示扫描线
private var animator: ObjectAnimator? = null
private var floatYFraction = 0f
set(value) {
field = value
invalidate()
}
init {
circlePaint.apply {
this.style = Paint.Style.FILL
this.color = ContextCompat.getColor(
context, android.R.color.holo_green_dark
)
}
scanLine = BitmapFactory.decodeResource(resources, R.drawable.scan_light)
getAnimator().start()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
parseResult(canvas)
if (isShowLine) {
canvas?.drawBitmap(scanLine, (width - scanLine.width) / 2f, height * floatYFraction, circlePaint)
}
}
private fun getAnimator(): ObjectAnimator {
if (animator == null) {
animator = ObjectAnimator.ofFloat(
this,
"floatYFraction",
0f,
1f
)
animator?.duration = 5000
animator?.repeatCount = -1 //-1代表无限循环
}
return animator!!
}
private fun parseResult(canvas: Canvas?) {
rectList?.let { list ->
if (list.isEmpty()) {
return
}
list.forEach {
canvas?.drawCircle(
it.left + (it.right - it.left) / 2f,
it.top + (it.bottom - it.top) / 2f,
50f,
circlePaint
)
}
}
}
fun setRectList(list: ArrayList<RectF>?) {
rectList = list
rectList?.let {
if (it.isNotEmpty()) {
isShowLine = false
getAnimator().cancel()
invalidate()
}
}
}
}