From d0b85d649a32c428aaef8ba3a6b6156a02813154 Mon Sep 17 00:00:00 2001 From: qiji4215 Date: Wed, 21 Jun 2023 17:51:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=81=E8=A3=85=E4=BA=8C=E7=BB=B4=E7=A0=81?= =?UTF-8?q?=E6=89=AB=E6=8F=8F=E4=B8=9A=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 12 ++ app/src/main/AndroidManifest.xml | 16 ++ .../main/java/com/navinfo/omqs/Constant.kt | 5 + .../java/com/navinfo/omqs/bean/QRCodeBean.kt | 6 + .../com/navinfo/omqs/http/NetworkService.kt | 11 +- .../navinfo/omqs/http/NetworkServiceImpl.kt | 20 +++ .../omqs/http/RetrofitNetworkServiceAPI.kt | 9 ++ .../ui/activity/CheckPermissionsActivity.java | 4 +- .../omqs/ui/activity/map/MainActivity.kt | 2 - .../omqs/ui/activity/scan/QRCodeActivity.kt | 125 +++++++++++++++ .../ui/activity/scan/QRCodeResultActivity.kt | 30 ++++ .../omqs/ui/activity/scan/QRCodeViewModel.kt | 151 ++++++++++++++++++ .../personalcenter/PersonalCenterFragment.kt | 28 +++- .../omqs/ui/listener/QrCodeAnalyzer.kt | 43 +++++ .../com/navinfo/omqs/ui/widget/ScanView.kt | 88 ++++++++++ .../main/res/drawable-xhdpi/scan_light.png | Bin 0 -> 3342 bytes app/src/main/res/layout/activity_qr_code.xml | 49 ++++++ app/src/main/res/layout/activity_result.xml | 19 +++ .../main/res/menu/personal_center_menu.xml | 4 + 19 files changed, 616 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/com/navinfo/omqs/bean/QRCodeBean.kt create mode 100644 app/src/main/java/com/navinfo/omqs/ui/activity/scan/QRCodeActivity.kt create mode 100644 app/src/main/java/com/navinfo/omqs/ui/activity/scan/QRCodeResultActivity.kt create mode 100644 app/src/main/java/com/navinfo/omqs/ui/activity/scan/QRCodeViewModel.kt create mode 100644 app/src/main/java/com/navinfo/omqs/ui/listener/QrCodeAnalyzer.kt create mode 100644 app/src/main/java/com/navinfo/omqs/ui/widget/ScanView.kt create mode 100644 app/src/main/res/drawable-xhdpi/scan_light.png create mode 100644 app/src/main/res/layout/activity_qr_code.xml create mode 100644 app/src/main/res/layout/activity_result.xml diff --git a/app/build.gradle b/app/build.gradle index 027eb8ae..ab7fa750 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -115,6 +115,18 @@ dependencies { //kotlin反射 implementation "org.jetbrains.kotlin:kotlin-stdlib:1.7.0" implementation "org.jetbrains.kotlin:kotlin-reflect:1.7.0" + + implementation 'com.permissionx.guolindev:permissionx:1.4.0' + def camerax_version = "1.1.0-alpha04" + // The following line is optional, as the core library is included indirectly by camera-camera2 + implementation "androidx.camera:camera-core:${camerax_version}" + implementation "androidx.camera:camera-camera2:${camerax_version}" + // If you want to additionally use the CameraX Lifecycle library + implementation "androidx.camera:camera-lifecycle:${camerax_version}" + // If you want to additionally use the CameraX View class + implementation "androidx.camera:camera-view:1.0.0-alpha24" + + implementation 'com.google.mlkit:barcode-scanning:16.1.1' } //允许引用生成的代码 kapt { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 449d6cf9..ca45c1db 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,11 @@ android:versionCode="3" android:versionName="1.4" package="com.navinfo.omqs"> + + + @@ -31,6 +36,9 @@ + + + + + + + diff --git a/app/src/main/java/com/navinfo/omqs/Constant.kt b/app/src/main/java/com/navinfo/omqs/Constant.kt index ed6d845b..8e7477a7 100644 --- a/app/src/main/java/com/navinfo/omqs/Constant.kt +++ b/app/src/main/java/com/navinfo/omqs/Constant.kt @@ -45,6 +45,11 @@ class Constant { */ lateinit var DOWNLOAD_PATH: String + /** + * 室内整理工具IP + */ + lateinit var INDOOR_IPS: String + const val DEBUG = true var IS_VIDEO_SPEED by kotlin.properties.Delegates.notNull() diff --git a/app/src/main/java/com/navinfo/omqs/bean/QRCodeBean.kt b/app/src/main/java/com/navinfo/omqs/bean/QRCodeBean.kt new file mode 100644 index 00000000..4790dd17 --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/bean/QRCodeBean.kt @@ -0,0 +1,6 @@ +package com.navinfo.omqs.bean + +data class QRCodeBean( + var errcode: Int = -1, + var msg: String = "" +) \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/http/NetworkService.kt b/app/src/main/java/com/navinfo/omqs/http/NetworkService.kt index 5fe4dd2d..2fee5544 100644 --- a/app/src/main/java/com/navinfo/omqs/http/NetworkService.kt +++ b/app/src/main/java/com/navinfo/omqs/http/NetworkService.kt @@ -3,6 +3,7 @@ package com.navinfo.omqs.http import com.navinfo.omqs.bean.OfflineMapCityBean import com.navinfo.collect.library.data.entity.TaskBean import com.navinfo.omqs.bean.LoginUserBean +import com.navinfo.omqs.bean.QRCodeBean import com.navinfo.omqs.bean.SysUserBean import okhttp3.ResponseBody import retrofit2.Response @@ -15,14 +16,20 @@ interface NetworkService { /** * 获取离线地图城市列表 */ - suspend fun getOfflineMapCityList():NetResult> + suspend fun getOfflineMapCityList(): NetResult> + /** * 获取任务列表 */ - suspend fun getTaskList(evaluatorNo:String): NetResult>> + suspend fun getTaskList(evaluatorNo: String): NetResult>> /** * 登录接口 */ suspend fun loginUser(loginUserBean: LoginUserBean): NetResult> + + /** + * 连接室内整理工具 + */ + suspend fun connectIndoorTools(url: String): NetResult> } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/http/NetworkServiceImpl.kt b/app/src/main/java/com/navinfo/omqs/http/NetworkServiceImpl.kt index 374bd7e6..cf6bdcdd 100644 --- a/app/src/main/java/com/navinfo/omqs/http/NetworkServiceImpl.kt +++ b/app/src/main/java/com/navinfo/omqs/http/NetworkServiceImpl.kt @@ -3,6 +3,7 @@ package com.navinfo.omqs.http import com.navinfo.omqs.bean.OfflineMapCityBean import com.navinfo.collect.library.data.entity.TaskBean import com.navinfo.omqs.bean.LoginUserBean +import com.navinfo.omqs.bean.QRCodeBean import com.navinfo.omqs.bean.SysUserBean import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -75,4 +76,23 @@ class NetworkServiceImpl @Inject constructor( NetResult.Error(e) } } + + override suspend fun connectIndoorTools(url: String): NetResult> = + //在IO线程中运行 + withContext(Dispatchers.IO) { + return@withContext try { + val result = netApi.retrofitConnectIndoorTools(url) + if (result.isSuccessful) { + if (result.code() == 200) { + NetResult.Success(result.body()) + } else { + NetResult.Failure(result.code(), result.message()) + } + } else { + NetResult.Failure(result.code(), result.message()) + } + } catch (e: Exception) { + NetResult.Error(e) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/http/RetrofitNetworkServiceAPI.kt b/app/src/main/java/com/navinfo/omqs/http/RetrofitNetworkServiceAPI.kt index 67136348..d948588a 100644 --- a/app/src/main/java/com/navinfo/omqs/http/RetrofitNetworkServiceAPI.kt +++ b/app/src/main/java/com/navinfo/omqs/http/RetrofitNetworkServiceAPI.kt @@ -4,6 +4,7 @@ import com.navinfo.omqs.bean.EvaluationInfo import com.navinfo.omqs.bean.OfflineMapCityBean import com.navinfo.collect.library.data.entity.TaskBean import com.navinfo.omqs.bean.LoginUserBean +import com.navinfo.omqs.bean.QRCodeBean import com.navinfo.omqs.bean.SysUserBean import okhttp3.ResponseBody import retrofit2.Response @@ -64,6 +65,14 @@ interface RetrofitNetworkServiceAPI { @Query("evaluatorNo") evaluatorNo: String, ): Response>> + + + /** + * 获取离线地图城市列表 + */ + @GET("/drdc/MapDownload/maplist") + suspend fun retrofitConnectIndoorTools(@Url url: String): Response> + @Headers("Content-Type: application/json") @POST("/devcp/uploadSceneProblem") suspend fun postRequest(@Body listEvaluationInfo: List?): Response> diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/CheckPermissionsActivity.java b/app/src/main/java/com/navinfo/omqs/ui/activity/CheckPermissionsActivity.java index 6690ea72..00150288 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/activity/CheckPermissionsActivity.java +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/CheckPermissionsActivity.java @@ -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 }; } diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt index 286bf347..2e158b6c 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt @@ -123,8 +123,6 @@ class MainActivity : BaseActivity() { checkIntent.action = TextToSpeech.Engine.ACTION_CHECK_TTS_DATA someActivityResultLauncher.launch(checkIntent) - - binding = DataBindingUtil.setContentView(this, R.layout.activity_main) //初始化地图 diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/scan/QRCodeActivity.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/scan/QRCodeActivity.kt new file mode 100644 index 00000000..3160edbf --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/scan/QRCodeActivity.kt @@ -0,0 +1,125 @@ +package com.navinfo.omqs.ui.activity.scan + +import android.annotation.SuppressLint +import android.content.Intent +import android.graphics.Rect +import android.graphics.RectF +import android.os.Bundle +import android.util.Log +import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import androidx.camera.core.ImageCapture +import androidx.camera.view.LifecycleCameraController +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.viewModelScope +import com.navinfo.omqs.R +import com.navinfo.omqs.databinding.ActivityQrCodeBinding +import com.navinfo.omqs.ui.activity.login.LoginViewModel +import com.navinfo.omqs.ui.listener.QRCodeAnalyser +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors + +/** + * date:2021/6/18 + * author:zhangteng + * description:二维码扫描 + */ +class QRCodeActivity : AppCompatActivity() { + private lateinit var binding: ActivityQrCodeBinding + private lateinit var lifecycleCameraController: LifecycleCameraController + private lateinit var cameraExecutor: ExecutorService + private val viewModel by viewModels() + + 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 + + initController() + } + + @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() + val strList = ArrayList() + + 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) { + val sb = StringBuilder() + list.forEach { + sb.append(it) + sb.append("\n") + } + intentToResult(sb.toString()) + } + + private fun intentToResult(result: String) { + viewModel.connect(this, result) + + Log.e("qj", "QRCodeActivity === $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}") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/scan/QRCodeResultActivity.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/scan/QRCodeResultActivity.kt new file mode 100644 index 00000000..de4c3c93 --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/scan/QRCodeResultActivity.kt @@ -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() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/scan/QRCodeViewModel.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/scan/QRCodeViewModel.kt new file mode 100644 index 00000000..12b767c5 --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/scan/QRCodeViewModel.kt @@ -0,0 +1,151 @@ +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.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 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 { + /** + * 访问服务器登陆中 + */ + LOGIN_STATUS_NET_LOADING, + + /** + * 访问离线地图列表 + */ + LOGIN_STATUS_NET_OFFLINE_MAP, + + /** + * 初始化文件夹 + */ + LOGIN_STATUS_FOLDER_INIT, + + /** + * 创建文件夹失败 + */ + LOGIN_STATUS_FOLDER_FAILURE, + + /** + * 网络访问失败 + */ + LOGIN_STATUS_NET_FAILURE, + + /** + * 成功 + */ + LOGIN_STATUS_SUCCESS, + + /** + * 取消 + */ + LOGIN_STATUS_CANCEL, +} + +@HiltViewModel +class QRCodeViewModel @Inject constructor( + private val networkService: NetworkService +) : ViewModel() { + //用户信息 + val qrCodeBean: MutableLiveData = MutableLiveData() + + //是不是连接成功 + val qrCodeStatus: MutableLiveData = MutableLiveData() + + var jobQRCodeStatus: Job? = null; + + 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 DefaultResponse + if (defaultUserResponse.success) { + + } else { + withContext(Dispatchers.Main) { + Toast.makeText( + context, + "${defaultUserResponse.msg}", + Toast.LENGTH_SHORT + ) + .show() + } + } + + } catch (e: IOException) { + } + } + } + + 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() + } + } + + else -> {} + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt index 82b04705..5667aa16 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt @@ -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,10 @@ class PersonalCenterFragment(private var backListener: (() -> Unit?)? = null) : R.id.personal_center_menu_layer_manager -> { // 图层管理 findNavController().navigate(R.id.QsLayerManagerFragment) } + R.id.personal_center_menu_scan_qr_code -> { + //跳转二维码扫描界面 + checkPermission() + } } true } @@ -134,6 +141,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 +159,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() + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/listener/QrCodeAnalyzer.kt b/app/src/main/java/com/navinfo/omqs/ui/listener/QrCodeAnalyzer.kt new file mode 100644 index 00000000..c7216cfa --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/ui/listener/QrCodeAnalyzer.kt @@ -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, 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() } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/widget/ScanView.kt b/app/src/main/java/com/navinfo/omqs/ui/widget/ScanView.kt new file mode 100644 index 00000000..bfc487a7 --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/ui/widget/ScanView.kt @@ -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: + * date:2021/6/19 + */ +class ScanView(context: Context, attrs: AttributeSet) : View(context, attrs) { + private val circlePaint = Paint() //二维码圆圈画笔 + private var rectList: ArrayList? = 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?) { + rectList = list + rectList?.let { + if (it.isNotEmpty()) { + isShowLine = false + getAnimator().cancel() + invalidate() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/scan_light.png b/app/src/main/res/drawable-xhdpi/scan_light.png new file mode 100644 index 0000000000000000000000000000000000000000..1acef0b827092604feffad796e3f7a8669bb42b1 GIT binary patch literal 3342 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 Y51^~^wa8B(O#lD@07*qoM6N<$f|LrtR{#J2 literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_qr_code.xml b/app/src/main/res/layout/activity_qr_code.xml new file mode 100644 index 00000000..a802f372 --- /dev/null +++ b/app/src/main/res/layout/activity_qr_code.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_result.xml b/app/src/main/res/layout/activity_result.xml new file mode 100644 index 00000000..37e4275c --- /dev/null +++ b/app/src/main/res/layout/activity_result.xml @@ -0,0 +1,19 @@ + + + + + +