diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 81f1347..d106ce1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -88,6 +88,7 @@ + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 81f1347..d106ce1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -88,6 +88,7 @@ + diff --git a/app/src/main/java/com/casic/detector/common/service/NtripConnectService.kt b/app/src/main/java/com/casic/detector/common/service/NtripConnectService.kt new file mode 100644 index 0000000..62d93dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/common/service/NtripConnectService.kt @@ -0,0 +1,164 @@ +package com.casic.detector.common.service + +import android.app.Service +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.Handler +import android.os.IBinder +import android.os.Message +import android.util.Log +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.lifecycleScope +import com.casic.detector.common.extensions.convertToGPGGA +import com.casic.detector.common.utils.LocaleConstant +import com.casic.detector.common.utils.NtripAuthorizationCreator +import com.casic.detector.common.utils.RtkLocationTool +import com.casic.detector.common.utils.tcp.ConnectState +import com.casic.detector.common.utils.tcp.OnSocketConnectListener +import com.casic.detector.common.utils.tcp.SocketClient +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import io.netty.buffer.Unpooled +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import java.io.OutputStream +import java.nio.charset.StandardCharsets + +class NtripConnectService : Service(), LifecycleOwner, OnSocketConnectListener, Handler.Callback { + + companion object { + var weakReferenceHandler: WeakReferenceHandler? = null + } + + private val kTag = "NtripConnectService" + private val registry = LifecycleRegistry(this) + private var connectState = ConnectState.CLOSED + private var serialPortService: SerialPortService? = null + private var outStream: OutputStream? = null + private lateinit var socketClient: SocketClient + + override fun getLifecycle(): Lifecycle { + return registry + } + + override fun onBind(intent: Intent?): IBinder? { + return null + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == 2024082201) { + lifecycleScope.launch(Dispatchers.IO) { + connectQianXunServer() + } + } + return true + } + + override fun onCreate() { + super.onCreate() + weakReferenceHandler = WeakReferenceHandler(this) + //绑定串口通信服务 + Intent(this, SerialPortService::class.java).also { + bindService(it, serviceConnection, Context.BIND_AUTO_CREATE) + } + + RtkLocationTool.getCurrentLocation(this) { + if (connectState == ConnectState.SUCCESS) { + //连接成功就发送千寻请求报文 + val gga = it.convertToGPGGA() + Log.d(kTag, gga) + socketClient.sendData(gga) + } else { + //TODO 最好改为可以手动重连 + "千寻定位服务已断开,请重新连接".show(this) + } + } + } + + private val serviceConnection = object : ServiceConnection { + override fun onServiceConnected(name: ComponentName?, iBinder: IBinder?) { + if (iBinder is SerialPortService.ServiceBinder) { + serialPortService = iBinder.getSerialPortService() + Log.d(kTag, "onServiceConnected: 服务已绑定") + } + } + + override fun onServiceDisconnected(name: ComponentName?) { + + } + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + lifecycleScope.launch(Dispatchers.IO) { + connectQianXunServer() + } + return START_STICKY + } + + override fun onMessageResponse(data: ByteArray) { + if (data.size == 14) { + /** + * 连接成功,登录会返回 ICY 200 OK + *

+ * 0d0a0d0a -> \r\n\r\n + * */ + val result = String(data, StandardCharsets.UTF_8) + if (result.contains("ICY 200 OK")) { + "高精度定位服务连接成功".show(this) + //连接服务即打开串口 + this.outStream = serialPortService?.getOutputStream() + } + } else { + "收到千寻数据返回,长度:${data.size}".show(this) + outStream?.write(data) + outStream?.flush() + } + } + + override fun onServiceConnectStatusChanged(status: ConnectState) { + this.connectState = status + Log.d(kTag, "onServiceConnectStatusChanged: $status") + if (connectState == ConnectState.SUCCESS) { + //连接成功就发送千寻请求报文 + val account = SaveKeyValues.getValue(LocaleConstant.ACK, "qxtmcr0087663") as String + val pwd = SaveKeyValues.getValue(LocaleConstant.ACS, "1f1f9b9") as String + + // base64加密用户名和密码 + val byteArray = "$account:$pwd".toByteArray() + val base64 = android.util.Base64.encodeToString(byteArray, android.util.Base64.DEFAULT) + + val msg = NtripAuthorizationCreator().append("GET /RTCM32_GGB HTTP/1.1") + .append("Host: ${LocaleConstant.QX_RTK_HOST}").append("Ntrip-Version: Ntrip/2.0") + .append("User-Agent: NTRIP GNSSInternetRadio 2.0.10").append("Accept: */*") + .append("Connection: close").append("Accept:*/*") + .append("Authorization: Basic $base64").toString() + + val byteBuf = Unpooled.wrappedBuffer(msg.toByteArray()) + socketClient.sendData(byteBuf) + } + } + + private fun connectQianXunServer() { + //取缓存 + val remoteHost = SaveKeyValues.getValue( + LocaleConstant.RTK_SERVER, "203.107.45.154" + ) as String + val remotePort = SaveKeyValues.getValue( + LocaleConstant.RTK_PORT, "8003" + ) as String + + socketClient = SocketClient.Builder().setHostname(remoteHost).setPort(remotePort.toInt()) + .setTimeout(5000).setOnSocketListener(this).build() + socketClient.connect() + } + + override fun onDestroy() { + super.onDestroy() + unbindService(serviceConnection) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 81f1347..d106ce1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -88,6 +88,7 @@ + diff --git a/app/src/main/java/com/casic/detector/common/service/NtripConnectService.kt b/app/src/main/java/com/casic/detector/common/service/NtripConnectService.kt new file mode 100644 index 0000000..62d93dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/common/service/NtripConnectService.kt @@ -0,0 +1,164 @@ +package com.casic.detector.common.service + +import android.app.Service +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.Handler +import android.os.IBinder +import android.os.Message +import android.util.Log +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.lifecycleScope +import com.casic.detector.common.extensions.convertToGPGGA +import com.casic.detector.common.utils.LocaleConstant +import com.casic.detector.common.utils.NtripAuthorizationCreator +import com.casic.detector.common.utils.RtkLocationTool +import com.casic.detector.common.utils.tcp.ConnectState +import com.casic.detector.common.utils.tcp.OnSocketConnectListener +import com.casic.detector.common.utils.tcp.SocketClient +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import io.netty.buffer.Unpooled +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import java.io.OutputStream +import java.nio.charset.StandardCharsets + +class NtripConnectService : Service(), LifecycleOwner, OnSocketConnectListener, Handler.Callback { + + companion object { + var weakReferenceHandler: WeakReferenceHandler? = null + } + + private val kTag = "NtripConnectService" + private val registry = LifecycleRegistry(this) + private var connectState = ConnectState.CLOSED + private var serialPortService: SerialPortService? = null + private var outStream: OutputStream? = null + private lateinit var socketClient: SocketClient + + override fun getLifecycle(): Lifecycle { + return registry + } + + override fun onBind(intent: Intent?): IBinder? { + return null + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == 2024082201) { + lifecycleScope.launch(Dispatchers.IO) { + connectQianXunServer() + } + } + return true + } + + override fun onCreate() { + super.onCreate() + weakReferenceHandler = WeakReferenceHandler(this) + //绑定串口通信服务 + Intent(this, SerialPortService::class.java).also { + bindService(it, serviceConnection, Context.BIND_AUTO_CREATE) + } + + RtkLocationTool.getCurrentLocation(this) { + if (connectState == ConnectState.SUCCESS) { + //连接成功就发送千寻请求报文 + val gga = it.convertToGPGGA() + Log.d(kTag, gga) + socketClient.sendData(gga) + } else { + //TODO 最好改为可以手动重连 + "千寻定位服务已断开,请重新连接".show(this) + } + } + } + + private val serviceConnection = object : ServiceConnection { + override fun onServiceConnected(name: ComponentName?, iBinder: IBinder?) { + if (iBinder is SerialPortService.ServiceBinder) { + serialPortService = iBinder.getSerialPortService() + Log.d(kTag, "onServiceConnected: 服务已绑定") + } + } + + override fun onServiceDisconnected(name: ComponentName?) { + + } + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + lifecycleScope.launch(Dispatchers.IO) { + connectQianXunServer() + } + return START_STICKY + } + + override fun onMessageResponse(data: ByteArray) { + if (data.size == 14) { + /** + * 连接成功,登录会返回 ICY 200 OK + *

+ * 0d0a0d0a -> \r\n\r\n + * */ + val result = String(data, StandardCharsets.UTF_8) + if (result.contains("ICY 200 OK")) { + "高精度定位服务连接成功".show(this) + //连接服务即打开串口 + this.outStream = serialPortService?.getOutputStream() + } + } else { + "收到千寻数据返回,长度:${data.size}".show(this) + outStream?.write(data) + outStream?.flush() + } + } + + override fun onServiceConnectStatusChanged(status: ConnectState) { + this.connectState = status + Log.d(kTag, "onServiceConnectStatusChanged: $status") + if (connectState == ConnectState.SUCCESS) { + //连接成功就发送千寻请求报文 + val account = SaveKeyValues.getValue(LocaleConstant.ACK, "qxtmcr0087663") as String + val pwd = SaveKeyValues.getValue(LocaleConstant.ACS, "1f1f9b9") as String + + // base64加密用户名和密码 + val byteArray = "$account:$pwd".toByteArray() + val base64 = android.util.Base64.encodeToString(byteArray, android.util.Base64.DEFAULT) + + val msg = NtripAuthorizationCreator().append("GET /RTCM32_GGB HTTP/1.1") + .append("Host: ${LocaleConstant.QX_RTK_HOST}").append("Ntrip-Version: Ntrip/2.0") + .append("User-Agent: NTRIP GNSSInternetRadio 2.0.10").append("Accept: */*") + .append("Connection: close").append("Accept:*/*") + .append("Authorization: Basic $base64").toString() + + val byteBuf = Unpooled.wrappedBuffer(msg.toByteArray()) + socketClient.sendData(byteBuf) + } + } + + private fun connectQianXunServer() { + //取缓存 + val remoteHost = SaveKeyValues.getValue( + LocaleConstant.RTK_SERVER, "203.107.45.154" + ) as String + val remotePort = SaveKeyValues.getValue( + LocaleConstant.RTK_PORT, "8003" + ) as String + + socketClient = SocketClient.Builder().setHostname(remoteHost).setPort(remotePort.toInt()) + .setTimeout(5000).setOnSocketListener(this).build() + socketClient.connect() + } + + override fun onDestroy() { + super.onDestroy() + unbindService(serviceConnection) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/common/view/MainActivity.kt b/app/src/main/java/com/casic/detector/common/view/MainActivity.kt index 3d7ff95..e0c0be8 100644 --- a/app/src/main/java/com/casic/detector/common/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/common/view/MainActivity.kt @@ -1,10 +1,7 @@ package com.casic.detector.common.view import android.app.Activity -import android.content.ComponentName -import android.content.Context import android.content.Intent -import android.content.ServiceConnection import android.graphics.BitmapFactory import android.graphics.Color import android.graphics.drawable.BitmapDrawable @@ -12,7 +9,6 @@ import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle -import android.os.IBinder import android.util.Log import android.view.KeyEvent import android.view.View @@ -40,27 +36,23 @@ import com.casic.detector.common.cluster.RegionItem import com.casic.detector.common.databinding.ActivityMainBinding import com.casic.detector.common.extensions.appendDownloadUrl -import com.casic.detector.common.extensions.convertToGPGGA import com.casic.detector.common.extensions.createTaskCode import com.casic.detector.common.extensions.drawCircle +import com.casic.detector.common.extensions.handleSignalStrength import com.casic.detector.common.extensions.hexToString import com.casic.detector.common.extensions.initImmersionBar import com.casic.detector.common.extensions.isNumber import com.casic.detector.common.extensions.toHex import com.casic.detector.common.model.TaskDetailLocalModel import com.casic.detector.common.model.TaskModel +import com.casic.detector.common.service.NtripConnectService import com.casic.detector.common.service.SerialPortService import com.casic.detector.common.utils.DataBaseManager import com.casic.detector.common.utils.ExcelTool import com.casic.detector.common.utils.FileType import com.casic.detector.common.utils.LocaleConstant import com.casic.detector.common.utils.LocationTool -import com.casic.detector.common.utils.NtripAuthorizationCreator import com.casic.detector.common.utils.RouteOnMap -import com.casic.detector.common.utils.RtkLocationTool -import com.casic.detector.common.utils.tcp.ConnectState -import com.casic.detector.common.utils.tcp.OnSocketConnectListener -import com.casic.detector.common.utils.tcp.SocketClient import com.casic.detector.common.vm.TaskViewModel import com.casic.detector.common.widgets.MarkerDetailDialog import com.casic.detector.common.widgets.QueryMarkerDialog @@ -82,17 +74,13 @@ import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog import com.pengxh.kt.lite.widget.dialog.BottomActionSheet -import io.netty.buffer.Unpooled import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File import java.io.OutputStream -import java.nio.charset.StandardCharsets -import java.util.Timer -import java.util.TimerTask -class MainActivity : KotlinBaseActivity(), OnSocketConnectListener { +class MainActivity : KotlinBaseActivity(), OnSerialPortDataListener { private val kTag = "MainActivity" private val context = this @@ -112,14 +100,10 @@ private var freeTaskTitle = "" private var ids = HashSet() private var freeTaskId: String? = null - private var connectState = ConnectState.CLOSED private var serialPortService: SerialPortService? = null - private var searchMarkerTimer: Timer? = null private var soundResourceId = 0 private var isExecuteTask = false - private var outStream: OutputStream? = null private lateinit var aMap: AMap - private lateinit var socketClient: SocketClient override fun initViewBinding(): ActivityMainBinding { return ActivityMainBinding.inflate(layoutInflater) @@ -129,38 +113,11 @@ binding.rootView.initImmersionBar(this, false, R.color.themeColor) } - private val serviceConnection = object : ServiceConnection { - override fun onServiceConnected(name: ComponentName?, iBinder: IBinder?) { - if (iBinder is SerialPortService.ServiceBinder) { - serialPortService = iBinder.getSerialPortService() - Log.d(kTag, "onServiceConnected: 服务已绑定") - } - } - - override fun onServiceDisconnected(name: ComponentName?) { - - } - } - override fun initOnCreate(savedInstanceState: Bundle?) { - //绑定串口通信服务 - Intent(this, SerialPortService::class.java).also { - bindService(it, serviceConnection, Context.BIND_AUTO_CREATE) - } + startService(Intent(this, NtripConnectService::class.java)) soundResourceId = soundPool.load(this, R.raw.ring3, 1) - //连接千寻RTK服务器 - lifecycleScope.launch(Dispatchers.IO) { connectQianXunServer() } - RtkLocationTool.getCurrentLocation(this) { - if (connectState == ConnectState.SUCCESS) { - //连接成功就发送千寻请求报文 - val gga = it.convertToGPGGA() - Log.d(kTag, gga) - socketClient.sendData(gga) - } - } - //地图初始化 initMapConfig(savedInstanceState) @@ -454,7 +411,6 @@ override fun onConfirmClick() { isFreeTask = false soundPool.autoPause() - searchMarkerTimer?.cancel() serialPortService?.closeSerialPort() binding.stopFreeTaskButton.visibility = View.GONE @@ -475,28 +431,12 @@ private val rtkConfigLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == Activity.RESULT_OK) { - lifecycleScope.launch(Dispatchers.IO) { connectQianXunServer() } + val referenceHandler = NtripConnectService.weakReferenceHandler + ?: return@registerForActivityResult + referenceHandler.sendEmptyMessage(2024082201) } } - private fun connectQianXunServer() { - //取缓存 - val remoteHost = SaveKeyValues.getValue( - LocaleConstant.RTK_SERVER, "203.107.45.154" - ) as String - val remotePort = SaveKeyValues.getValue( - LocaleConstant.RTK_PORT, "8003" - ) as String - - socketClient = SocketClient.Builder() - .setHostname(remoteHost) - .setPort(remotePort.toInt()) - .setTimeout(5000) - .setOnSocketListener(this) - .build() - socketClient.connect() - } - private fun uploadTask(taskId: String, taskCode: String, state: String) { if (isNetworkConnected()) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String @@ -526,72 +466,61 @@ private fun openSerialPort() { binding.stopFreeTaskButton.visibility = View.VISIBLE isFreeTask = true - searchMarkerTimer = Timer() - serialPortService?.openSerialPort(object : OnSerialPortDataListener { - override fun write(outStream: OutputStream) { - runOnUiThread { - searchMarkerTimer?.schedule(object : TimerTask() { - override fun run() { - outStream.write('2'.code) - outStream.flush() + serialPortService?.openSerialPort(this) + } - Thread.sleep(50) + override fun write(outStream: OutputStream) { + outStream.write('2'.code) + outStream.flush() - outStream.write('6'.code) - outStream.flush() - } - }, 0, 200) + Thread.sleep(50) + + outStream.write('6'.code) + outStream.flush() + } + + override fun onDataReceived(buffer: ByteArray) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) + if (buffer.first() == 78.toByte()) { + val energy = buffer.handleSignalStrength().take(10).hexToString() + val signalStrength = energy.substring(1).toInt() + if (signalStrength <= 1500 && detailDialog.isShowing) { + detailDialog.dismiss() + } + } + + val hex = buffer.toHex() + val markerId = hex.take(20).hexToString() + if (markerId.isNumber()) { + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryMarkerById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng(bean.lat.toDouble(), bean.lng.toDouble()) + ).icon( + BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1) + ) + ) } } + ids.add(markerId) - override fun onDataReceived(buffer: ByteArray) { - val hex = buffer.toHex() - //只响一次,因为探测频率高,所以依旧是连续的报警声 - soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) - if (hex.startsWith("4E")) { - try { - val energyResponse = hex.take(10).hexToString() - val energy = energyResponse.substring(1).toInt() - if (energy <= 1500 && detailDialog.isShowing) { - detailDialog.dismiss() - } - } catch (e: NumberFormatException) { - e.printStackTrace() - } - } - - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - //添加地图Marker - if (!ids.contains(markerId)) { - //根据markerId查询标识器经纬度 - val labels = DataBaseManager.get.queryMarkerById(markerId) - if (labels.isNotEmpty()) { - val bean = labels.first() - aMap.addMarker( - MarkerOptions().position( - LatLng(bean.lat.toDouble(), bean.lng.toDouble()) - ).icon( - BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1) - ) - ) - } - } - ids.add(markerId) - - //显示标识器详细信息 - if (!detailDialog.isShowing) { - val markerBean = DataBaseManager.get.queryMarkerById(markerId).firstOrNull() - if (markerBean == null) { - "无法查询到此ID【${markerId}】的信息".show(context) - } else { - detailDialog.setMarker(markerBean) - detailDialog.show() - } - } + //显示标识器详细信息 + if (!detailDialog.isShowing) { + val markerBean = DataBaseManager.get.queryMarkerById(markerId).firstOrNull() + if (markerBean == null) { + "无法查询到此ID【${markerId}】的信息".show(context) + } else { + detailDialog.setMarker(markerBean) + detailDialog.show() } } - }) + } } override fun observeRequestState() { @@ -920,70 +849,6 @@ } } - override fun onMessageResponse(data: ByteArray) { - if (data.size == 14) { - /** - * 连接成功,登录会返回 ICY 200 OK - *

- * 0d0a0d0a -> \r\n\r\n - * */ - val result = String(data, StandardCharsets.UTF_8) - if (result.contains("ICY 200 OK")) { - "高精度定位服务连接成功".show(this) - //连接服务即打开串口 - this.outStream = serialPortService?.getOutputStream() - } - } else { - "收到千寻数据返回,长度:${data.size}".show(this) - outStream?.write(data) - outStream?.flush() - } - } - - override fun onServiceConnectStatusChanged(status: ConnectState) { - this.connectState = status - Log.d(kTag, "onServiceConnectStatusChanged: $status") - if (connectState == ConnectState.SUCCESS) { - //连接成功就发送千寻请求报文 - val account = SaveKeyValues.getValue(LocaleConstant.ACK, "qxtmcr0087663") as String - val pwd = SaveKeyValues.getValue(LocaleConstant.ACS, "1f1f9b9") as String - - // base64加密用户名和密码 - val byteArray = "$account:$pwd".toByteArray() - val base64 = android.util.Base64.encodeToString(byteArray, android.util.Base64.DEFAULT) - - val msg = NtripAuthorizationCreator() - .append("GET /RTCM32_GGB HTTP/1.1") - .append("Host: ${LocaleConstant.QX_RTK_HOST}") - .append("Ntrip-Version: Ntrip/2.0") - .append("User-Agent: NTRIP GNSSInternetRadio 2.0.10") - .append("Accept: */*") - .append("Connection: close") - .append("Accept:*/*") - .append("Authorization: Basic $base64") - .toString() - - val byteBuf = Unpooled.wrappedBuffer(msg.toByteArray()) - socketClient.sendData(byteBuf) - } else { - AlertControlDialog.Builder().setContext(context) - .setTitle("温馨提示") - .setMessage("千寻定位服务已断开,是否重连?") - .setPositiveButton("是") - .setNegativeButton("否") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - lifecycleScope.launch(Dispatchers.IO) { connectQianXunServer() } - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - override fun onPause() { super.onPause() binding.mapView.onPause() @@ -998,10 +863,8 @@ super.onDestroy() binding.mapView.onDestroy() soundPool.autoPause() - searchMarkerTimer?.cancel() serialPortService?.closeSerialPort() locationTool.stopLocation() - unbindService(serviceConnection) BaseApplication.get().closeSerialPort() } } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 81f1347..d106ce1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -88,6 +88,7 @@ + diff --git a/app/src/main/java/com/casic/detector/common/service/NtripConnectService.kt b/app/src/main/java/com/casic/detector/common/service/NtripConnectService.kt new file mode 100644 index 0000000..62d93dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/common/service/NtripConnectService.kt @@ -0,0 +1,164 @@ +package com.casic.detector.common.service + +import android.app.Service +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.Handler +import android.os.IBinder +import android.os.Message +import android.util.Log +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.lifecycleScope +import com.casic.detector.common.extensions.convertToGPGGA +import com.casic.detector.common.utils.LocaleConstant +import com.casic.detector.common.utils.NtripAuthorizationCreator +import com.casic.detector.common.utils.RtkLocationTool +import com.casic.detector.common.utils.tcp.ConnectState +import com.casic.detector.common.utils.tcp.OnSocketConnectListener +import com.casic.detector.common.utils.tcp.SocketClient +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import io.netty.buffer.Unpooled +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import java.io.OutputStream +import java.nio.charset.StandardCharsets + +class NtripConnectService : Service(), LifecycleOwner, OnSocketConnectListener, Handler.Callback { + + companion object { + var weakReferenceHandler: WeakReferenceHandler? = null + } + + private val kTag = "NtripConnectService" + private val registry = LifecycleRegistry(this) + private var connectState = ConnectState.CLOSED + private var serialPortService: SerialPortService? = null + private var outStream: OutputStream? = null + private lateinit var socketClient: SocketClient + + override fun getLifecycle(): Lifecycle { + return registry + } + + override fun onBind(intent: Intent?): IBinder? { + return null + } + + override fun handleMessage(msg: Message): Boolean { + if (msg.what == 2024082201) { + lifecycleScope.launch(Dispatchers.IO) { + connectQianXunServer() + } + } + return true + } + + override fun onCreate() { + super.onCreate() + weakReferenceHandler = WeakReferenceHandler(this) + //绑定串口通信服务 + Intent(this, SerialPortService::class.java).also { + bindService(it, serviceConnection, Context.BIND_AUTO_CREATE) + } + + RtkLocationTool.getCurrentLocation(this) { + if (connectState == ConnectState.SUCCESS) { + //连接成功就发送千寻请求报文 + val gga = it.convertToGPGGA() + Log.d(kTag, gga) + socketClient.sendData(gga) + } else { + //TODO 最好改为可以手动重连 + "千寻定位服务已断开,请重新连接".show(this) + } + } + } + + private val serviceConnection = object : ServiceConnection { + override fun onServiceConnected(name: ComponentName?, iBinder: IBinder?) { + if (iBinder is SerialPortService.ServiceBinder) { + serialPortService = iBinder.getSerialPortService() + Log.d(kTag, "onServiceConnected: 服务已绑定") + } + } + + override fun onServiceDisconnected(name: ComponentName?) { + + } + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + lifecycleScope.launch(Dispatchers.IO) { + connectQianXunServer() + } + return START_STICKY + } + + override fun onMessageResponse(data: ByteArray) { + if (data.size == 14) { + /** + * 连接成功,登录会返回 ICY 200 OK + *

+ * 0d0a0d0a -> \r\n\r\n + * */ + val result = String(data, StandardCharsets.UTF_8) + if (result.contains("ICY 200 OK")) { + "高精度定位服务连接成功".show(this) + //连接服务即打开串口 + this.outStream = serialPortService?.getOutputStream() + } + } else { + "收到千寻数据返回,长度:${data.size}".show(this) + outStream?.write(data) + outStream?.flush() + } + } + + override fun onServiceConnectStatusChanged(status: ConnectState) { + this.connectState = status + Log.d(kTag, "onServiceConnectStatusChanged: $status") + if (connectState == ConnectState.SUCCESS) { + //连接成功就发送千寻请求报文 + val account = SaveKeyValues.getValue(LocaleConstant.ACK, "qxtmcr0087663") as String + val pwd = SaveKeyValues.getValue(LocaleConstant.ACS, "1f1f9b9") as String + + // base64加密用户名和密码 + val byteArray = "$account:$pwd".toByteArray() + val base64 = android.util.Base64.encodeToString(byteArray, android.util.Base64.DEFAULT) + + val msg = NtripAuthorizationCreator().append("GET /RTCM32_GGB HTTP/1.1") + .append("Host: ${LocaleConstant.QX_RTK_HOST}").append("Ntrip-Version: Ntrip/2.0") + .append("User-Agent: NTRIP GNSSInternetRadio 2.0.10").append("Accept: */*") + .append("Connection: close").append("Accept:*/*") + .append("Authorization: Basic $base64").toString() + + val byteBuf = Unpooled.wrappedBuffer(msg.toByteArray()) + socketClient.sendData(byteBuf) + } + } + + private fun connectQianXunServer() { + //取缓存 + val remoteHost = SaveKeyValues.getValue( + LocaleConstant.RTK_SERVER, "203.107.45.154" + ) as String + val remotePort = SaveKeyValues.getValue( + LocaleConstant.RTK_PORT, "8003" + ) as String + + socketClient = SocketClient.Builder().setHostname(remoteHost).setPort(remotePort.toInt()) + .setTimeout(5000).setOnSocketListener(this).build() + socketClient.connect() + } + + override fun onDestroy() { + super.onDestroy() + unbindService(serviceConnection) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/common/view/MainActivity.kt b/app/src/main/java/com/casic/detector/common/view/MainActivity.kt index 3d7ff95..e0c0be8 100644 --- a/app/src/main/java/com/casic/detector/common/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/common/view/MainActivity.kt @@ -1,10 +1,7 @@ package com.casic.detector.common.view import android.app.Activity -import android.content.ComponentName -import android.content.Context import android.content.Intent -import android.content.ServiceConnection import android.graphics.BitmapFactory import android.graphics.Color import android.graphics.drawable.BitmapDrawable @@ -12,7 +9,6 @@ import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle -import android.os.IBinder import android.util.Log import android.view.KeyEvent import android.view.View @@ -40,27 +36,23 @@ import com.casic.detector.common.cluster.RegionItem import com.casic.detector.common.databinding.ActivityMainBinding import com.casic.detector.common.extensions.appendDownloadUrl -import com.casic.detector.common.extensions.convertToGPGGA import com.casic.detector.common.extensions.createTaskCode import com.casic.detector.common.extensions.drawCircle +import com.casic.detector.common.extensions.handleSignalStrength import com.casic.detector.common.extensions.hexToString import com.casic.detector.common.extensions.initImmersionBar import com.casic.detector.common.extensions.isNumber import com.casic.detector.common.extensions.toHex import com.casic.detector.common.model.TaskDetailLocalModel import com.casic.detector.common.model.TaskModel +import com.casic.detector.common.service.NtripConnectService import com.casic.detector.common.service.SerialPortService import com.casic.detector.common.utils.DataBaseManager import com.casic.detector.common.utils.ExcelTool import com.casic.detector.common.utils.FileType import com.casic.detector.common.utils.LocaleConstant import com.casic.detector.common.utils.LocationTool -import com.casic.detector.common.utils.NtripAuthorizationCreator import com.casic.detector.common.utils.RouteOnMap -import com.casic.detector.common.utils.RtkLocationTool -import com.casic.detector.common.utils.tcp.ConnectState -import com.casic.detector.common.utils.tcp.OnSocketConnectListener -import com.casic.detector.common.utils.tcp.SocketClient import com.casic.detector.common.vm.TaskViewModel import com.casic.detector.common.widgets.MarkerDetailDialog import com.casic.detector.common.widgets.QueryMarkerDialog @@ -82,17 +74,13 @@ import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog import com.pengxh.kt.lite.widget.dialog.BottomActionSheet -import io.netty.buffer.Unpooled import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File import java.io.OutputStream -import java.nio.charset.StandardCharsets -import java.util.Timer -import java.util.TimerTask -class MainActivity : KotlinBaseActivity(), OnSocketConnectListener { +class MainActivity : KotlinBaseActivity(), OnSerialPortDataListener { private val kTag = "MainActivity" private val context = this @@ -112,14 +100,10 @@ private var freeTaskTitle = "" private var ids = HashSet() private var freeTaskId: String? = null - private var connectState = ConnectState.CLOSED private var serialPortService: SerialPortService? = null - private var searchMarkerTimer: Timer? = null private var soundResourceId = 0 private var isExecuteTask = false - private var outStream: OutputStream? = null private lateinit var aMap: AMap - private lateinit var socketClient: SocketClient override fun initViewBinding(): ActivityMainBinding { return ActivityMainBinding.inflate(layoutInflater) @@ -129,38 +113,11 @@ binding.rootView.initImmersionBar(this, false, R.color.themeColor) } - private val serviceConnection = object : ServiceConnection { - override fun onServiceConnected(name: ComponentName?, iBinder: IBinder?) { - if (iBinder is SerialPortService.ServiceBinder) { - serialPortService = iBinder.getSerialPortService() - Log.d(kTag, "onServiceConnected: 服务已绑定") - } - } - - override fun onServiceDisconnected(name: ComponentName?) { - - } - } - override fun initOnCreate(savedInstanceState: Bundle?) { - //绑定串口通信服务 - Intent(this, SerialPortService::class.java).also { - bindService(it, serviceConnection, Context.BIND_AUTO_CREATE) - } + startService(Intent(this, NtripConnectService::class.java)) soundResourceId = soundPool.load(this, R.raw.ring3, 1) - //连接千寻RTK服务器 - lifecycleScope.launch(Dispatchers.IO) { connectQianXunServer() } - RtkLocationTool.getCurrentLocation(this) { - if (connectState == ConnectState.SUCCESS) { - //连接成功就发送千寻请求报文 - val gga = it.convertToGPGGA() - Log.d(kTag, gga) - socketClient.sendData(gga) - } - } - //地图初始化 initMapConfig(savedInstanceState) @@ -454,7 +411,6 @@ override fun onConfirmClick() { isFreeTask = false soundPool.autoPause() - searchMarkerTimer?.cancel() serialPortService?.closeSerialPort() binding.stopFreeTaskButton.visibility = View.GONE @@ -475,28 +431,12 @@ private val rtkConfigLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == Activity.RESULT_OK) { - lifecycleScope.launch(Dispatchers.IO) { connectQianXunServer() } + val referenceHandler = NtripConnectService.weakReferenceHandler + ?: return@registerForActivityResult + referenceHandler.sendEmptyMessage(2024082201) } } - private fun connectQianXunServer() { - //取缓存 - val remoteHost = SaveKeyValues.getValue( - LocaleConstant.RTK_SERVER, "203.107.45.154" - ) as String - val remotePort = SaveKeyValues.getValue( - LocaleConstant.RTK_PORT, "8003" - ) as String - - socketClient = SocketClient.Builder() - .setHostname(remoteHost) - .setPort(remotePort.toInt()) - .setTimeout(5000) - .setOnSocketListener(this) - .build() - socketClient.connect() - } - private fun uploadTask(taskId: String, taskCode: String, state: String) { if (isNetworkConnected()) { val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String @@ -526,72 +466,61 @@ private fun openSerialPort() { binding.stopFreeTaskButton.visibility = View.VISIBLE isFreeTask = true - searchMarkerTimer = Timer() - serialPortService?.openSerialPort(object : OnSerialPortDataListener { - override fun write(outStream: OutputStream) { - runOnUiThread { - searchMarkerTimer?.schedule(object : TimerTask() { - override fun run() { - outStream.write('2'.code) - outStream.flush() + serialPortService?.openSerialPort(this) + } - Thread.sleep(50) + override fun write(outStream: OutputStream) { + outStream.write('2'.code) + outStream.flush() - outStream.write('6'.code) - outStream.flush() - } - }, 0, 200) + Thread.sleep(50) + + outStream.write('6'.code) + outStream.flush() + } + + override fun onDataReceived(buffer: ByteArray) { + //只响一次,因为探测频率高,所以依旧是连续的报警声 + soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) + if (buffer.first() == 78.toByte()) { + val energy = buffer.handleSignalStrength().take(10).hexToString() + val signalStrength = energy.substring(1).toInt() + if (signalStrength <= 1500 && detailDialog.isShowing) { + detailDialog.dismiss() + } + } + + val hex = buffer.toHex() + val markerId = hex.take(20).hexToString() + if (markerId.isNumber()) { + //添加地图Marker + if (!ids.contains(markerId)) { + //根据markerId查询标识器经纬度 + val labels = DataBaseManager.get.queryMarkerById(markerId) + if (labels.isNotEmpty()) { + val bean = labels.first() + aMap.addMarker( + MarkerOptions().position( + LatLng(bean.lat.toDouble(), bean.lng.toDouble()) + ).icon( + BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1) + ) + ) } } + ids.add(markerId) - override fun onDataReceived(buffer: ByteArray) { - val hex = buffer.toHex() - //只响一次,因为探测频率高,所以依旧是连续的报警声 - soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) - if (hex.startsWith("4E")) { - try { - val energyResponse = hex.take(10).hexToString() - val energy = energyResponse.substring(1).toInt() - if (energy <= 1500 && detailDialog.isShowing) { - detailDialog.dismiss() - } - } catch (e: NumberFormatException) { - e.printStackTrace() - } - } - - val markerId = hex.take(20).hexToString() - if (markerId.isNumber()) { - //添加地图Marker - if (!ids.contains(markerId)) { - //根据markerId查询标识器经纬度 - val labels = DataBaseManager.get.queryMarkerById(markerId) - if (labels.isNotEmpty()) { - val bean = labels.first() - aMap.addMarker( - MarkerOptions().position( - LatLng(bean.lat.toDouble(), bean.lng.toDouble()) - ).icon( - BitmapDescriptorFactory.fromResource(R.mipmap.label_blue1) - ) - ) - } - } - ids.add(markerId) - - //显示标识器详细信息 - if (!detailDialog.isShowing) { - val markerBean = DataBaseManager.get.queryMarkerById(markerId).firstOrNull() - if (markerBean == null) { - "无法查询到此ID【${markerId}】的信息".show(context) - } else { - detailDialog.setMarker(markerBean) - detailDialog.show() - } - } + //显示标识器详细信息 + if (!detailDialog.isShowing) { + val markerBean = DataBaseManager.get.queryMarkerById(markerId).firstOrNull() + if (markerBean == null) { + "无法查询到此ID【${markerId}】的信息".show(context) + } else { + detailDialog.setMarker(markerBean) + detailDialog.show() } } - }) + } } override fun observeRequestState() { @@ -920,70 +849,6 @@ } } - override fun onMessageResponse(data: ByteArray) { - if (data.size == 14) { - /** - * 连接成功,登录会返回 ICY 200 OK - *

- * 0d0a0d0a -> \r\n\r\n - * */ - val result = String(data, StandardCharsets.UTF_8) - if (result.contains("ICY 200 OK")) { - "高精度定位服务连接成功".show(this) - //连接服务即打开串口 - this.outStream = serialPortService?.getOutputStream() - } - } else { - "收到千寻数据返回,长度:${data.size}".show(this) - outStream?.write(data) - outStream?.flush() - } - } - - override fun onServiceConnectStatusChanged(status: ConnectState) { - this.connectState = status - Log.d(kTag, "onServiceConnectStatusChanged: $status") - if (connectState == ConnectState.SUCCESS) { - //连接成功就发送千寻请求报文 - val account = SaveKeyValues.getValue(LocaleConstant.ACK, "qxtmcr0087663") as String - val pwd = SaveKeyValues.getValue(LocaleConstant.ACS, "1f1f9b9") as String - - // base64加密用户名和密码 - val byteArray = "$account:$pwd".toByteArray() - val base64 = android.util.Base64.encodeToString(byteArray, android.util.Base64.DEFAULT) - - val msg = NtripAuthorizationCreator() - .append("GET /RTCM32_GGB HTTP/1.1") - .append("Host: ${LocaleConstant.QX_RTK_HOST}") - .append("Ntrip-Version: Ntrip/2.0") - .append("User-Agent: NTRIP GNSSInternetRadio 2.0.10") - .append("Accept: */*") - .append("Connection: close") - .append("Accept:*/*") - .append("Authorization: Basic $base64") - .toString() - - val byteBuf = Unpooled.wrappedBuffer(msg.toByteArray()) - socketClient.sendData(byteBuf) - } else { - AlertControlDialog.Builder().setContext(context) - .setTitle("温馨提示") - .setMessage("千寻定位服务已断开,是否重连?") - .setPositiveButton("是") - .setNegativeButton("否") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - lifecycleScope.launch(Dispatchers.IO) { connectQianXunServer() } - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - override fun onPause() { super.onPause() binding.mapView.onPause() @@ -998,10 +863,8 @@ super.onDestroy() binding.mapView.onDestroy() soundPool.autoPause() - searchMarkerTimer?.cancel() serialPortService?.closeSerialPort() locationTool.stopLocation() - unbindService(serviceConnection) BaseApplication.get().closeSerialPort() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/common/view/SearchMarkerActivity.kt b/app/src/main/java/com/casic/detector/common/view/SearchMarkerActivity.kt index fbbccf0..ff661ef 100644 --- a/app/src/main/java/com/casic/detector/common/view/SearchMarkerActivity.kt +++ b/app/src/main/java/com/casic/detector/common/view/SearchMarkerActivity.kt @@ -26,6 +26,7 @@ import com.casic.detector.common.callback.OnGetLocationListener import com.casic.detector.common.callback.OnSerialPortDataListener import com.casic.detector.common.databinding.ActivitySearchMarkerBinding +import com.casic.detector.common.extensions.handleSignalStrength import com.casic.detector.common.extensions.hexToString import com.casic.detector.common.extensions.isNumber import com.casic.detector.common.extensions.toHex @@ -77,7 +78,6 @@ private var gravity: FloatArray? = null private var geomagnetic: FloatArray? = null private var serialPortService: SerialPortService? = null - private lateinit var searchMarkerTimer: Timer private lateinit var searchSignalEnergyTimer: Timer private val serviceConnection = object : ServiceConnection { @@ -272,73 +272,59 @@ * */ private suspend fun searchMarker() { delay(300) - searchMarkerTimer = Timer() serialPortService?.openSerialPort(object : OnSerialPortDataListener { override fun write(outStream: OutputStream) { - runOnUiThread { - searchMarkerTimer.schedule(object : TimerTask() { - override fun run() { - outStream.write('2'.code) - outStream.flush() + outStream.write('2'.code) + outStream.flush() - Thread.sleep(50) + Thread.sleep(100) - outStream.write('6'.code) - outStream.flush() - } - }, 0, 200) - } + outStream.write('6'.code) + outStream.flush() } override fun onDataReceived(buffer: ByteArray) { - val hex = buffer.toHex() -// Log.d(kTag, "onDataReceived: $hex") - if (hex.startsWith("4E")) { - try { - //4E转为String为N,代表能量值 - //用能量值转动表盘 - val energyResponse = hex.take(10).hexToString() - signalEnergy = energyResponse.substring(1).toInt() - if (signalEnergy >= 4000) { - soundPool.play(fastSoundResourceId, 1f, 1f, 0, 0, 1f) - } else { - soundPool.play(slowSoundResourceId, 1f, 1f, 0, 0, 1f) - } + if (buffer.first() == 78.toByte()) { + val energy = buffer.handleSignalStrength().take(10).hexToString() + signalEnergy = energy.substring(1).toInt() + if (signalEnergy >= 4000) { + soundPool.play(fastSoundResourceId, 1f, 1f, 0, 0, 1f) + } else { + soundPool.play(slowSoundResourceId, 1f, 1f, 0, 0, 1f) + } - //通过设置进度条表示能量值 - binding.energyPgBar.progress = signalEnergy - binding.energyValueView.text = "${signalEnergy}dB" + //通过设置进度条表示能量值 + binding.energyPgBar.progress = signalEnergy + binding.energyValueView.text = "${signalEnergy}dB" - //根据信号强度更新界面 - if (signalEnergy <= 700) {//18° - binding.energyTipsView.text = "信号较弱,可能距离较远" - binding.energyTipsView.setTextColor(Color.parseColor("#8D1717")) - binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_red) + //根据信号强度更新界面 + if (signalEnergy <= 700) {//18° + binding.energyTipsView.text = "信号较弱,可能距离较远" + binding.energyTipsView.setTextColor(Color.parseColor("#8D1717")) + binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_red) - binding.depthButton.isEnabled = false - binding.depthButton.setTextColor(Color.parseColor("#CCCCCC")) - binding.depthButton.setBackgroundResource(R.mipmap.left_button_disable) - binding.markerInfoButton.isEnabled = false - binding.markerInfoButton.setTextColor(Color.parseColor("#CCCCCC")) - binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_disable) + binding.depthButton.isEnabled = false + binding.depthButton.setTextColor(Color.parseColor("#CCCCCC")) + binding.depthButton.setBackgroundResource(R.mipmap.left_button_disable) + binding.markerInfoButton.isEnabled = false + binding.markerInfoButton.setTextColor(Color.parseColor("#CCCCCC")) + binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_disable) - binding.searchResultView.text = "未检测到标识器" - binding.searchResultView.setTextColor(Color.parseColor("#8D1717")) - binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_red) - } else if (signalEnergy >= 4100) { - binding.energyTipsView.text = "信号极强,接近标识器正上方" - binding.energyTipsView.setTextColor(Color.parseColor("#428d00")) - binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green) - } else { - binding.energyTipsView.text = "已靠近,请继续移动位置" - binding.energyTipsView.setTextColor(Color.parseColor("#8C5700")) - binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow) - } - } catch (e: NumberFormatException) { - e.printStackTrace() + binding.searchResultView.text = "未检测到标识器" + binding.searchResultView.setTextColor(Color.parseColor("#8D1717")) + binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_red) + } else if (signalEnergy >= 4100) { + binding.energyTipsView.text = "信号极强,接近标识器正上方" + binding.energyTipsView.setTextColor(Color.parseColor("#428d00")) + binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green) + } else { + binding.energyTipsView.text = "已靠近,请继续移动位置" + binding.energyTipsView.setTextColor(Color.parseColor("#8C5700")) + binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow) } } else { - val id = hex.take(20).hexToString() + Log.d(kTag, buffer.contentToString()) + val id = buffer.toHex().take(20).hexToString() if (id.isNumber()) { markerId = id handleMarker(markerId) @@ -350,7 +336,6 @@ private fun stopSearchMarker() { soundPool.autoPause() - searchMarkerTimer.cancel() serialPortService?.closeSerialPort() Thread.sleep(100)