diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
index 458f3fb..ca7de13 100644
--- a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
+++ b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
@@ -4,6 +4,7 @@
import com.casic.detector.common.greendao.DaoMaster
import com.casic.detector.common.greendao.DaoSession
import com.casic.detector.common.uart.SerialPort
+import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.SaveKeyValues
import java.io.File
import java.io.IOException
@@ -13,23 +14,12 @@
class BaseApplication : Application() {
private val kTag = "BaseApplication"
- private var serialPorts: ArrayList? = null
+ private var serialPorts = ArrayList()
- @Throws(SecurityException::class, IOException::class, InvalidParameterException::class)
- fun getSerialPorts(): ArrayList? {
- serialPorts = ArrayList()
- /**
- * Open the serial port
- * */
- serialPorts?.apply {
- add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
- add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
- }
- return serialPorts
- }
+ fun getSerialPorts(): ArrayList = serialPorts
fun closeSerialPort() {
- serialPorts?.forEach {
+ serialPorts.forEach {
it.closeSerialPort()
}
}
@@ -49,6 +39,22 @@
val devOpenHelper = DaoMaster.DevOpenHelper(this, "Detector_Common.db", null)
val daoMaster = DaoMaster(devOpenHelper.writableDatabase)
daoSession = daoMaster.newSession()
+
+ /**
+ * Open the serial port
+ * */
+ try {
+ serialPorts.apply {
+ add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
+ add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
+ }
+ } catch (e: SecurityException) {
+ "您没有串口的读写权限!".show(this)
+ } catch (e: IOException) {
+ "因为不明原因,串口无法打开!".show(this)
+ } catch (e: InvalidParameterException) {
+ "请检查串口!".show(this)
+ }
}
fun getDaoSession(): DaoSession {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
index 458f3fb..ca7de13 100644
--- a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
+++ b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
@@ -4,6 +4,7 @@
import com.casic.detector.common.greendao.DaoMaster
import com.casic.detector.common.greendao.DaoSession
import com.casic.detector.common.uart.SerialPort
+import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.SaveKeyValues
import java.io.File
import java.io.IOException
@@ -13,23 +14,12 @@
class BaseApplication : Application() {
private val kTag = "BaseApplication"
- private var serialPorts: ArrayList? = null
+ private var serialPorts = ArrayList()
- @Throws(SecurityException::class, IOException::class, InvalidParameterException::class)
- fun getSerialPorts(): ArrayList? {
- serialPorts = ArrayList()
- /**
- * Open the serial port
- * */
- serialPorts?.apply {
- add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
- add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
- }
- return serialPorts
- }
+ fun getSerialPorts(): ArrayList = serialPorts
fun closeSerialPort() {
- serialPorts?.forEach {
+ serialPorts.forEach {
it.closeSerialPort()
}
}
@@ -49,6 +39,22 @@
val devOpenHelper = DaoMaster.DevOpenHelper(this, "Detector_Common.db", null)
val daoMaster = DaoMaster(devOpenHelper.writableDatabase)
daoSession = daoMaster.newSession()
+
+ /**
+ * Open the serial port
+ * */
+ try {
+ serialPorts.apply {
+ add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
+ add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
+ }
+ } catch (e: SecurityException) {
+ "您没有串口的读写权限!".show(this)
+ } catch (e: IOException) {
+ "因为不明原因,串口无法打开!".show(this)
+ } catch (e: InvalidParameterException) {
+ "请检查串口!".show(this)
+ }
}
fun getDaoSession(): DaoSession {
diff --git a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt b/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
deleted file mode 100644
index 297ac02..0000000
--- a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.casic.detector.common.base
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.lifecycleScope
-import androidx.viewbinding.ViewBinding
-import com.pengxh.kt.lite.extensions.show
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.IOException
-import java.io.OutputStream
-import java.security.InvalidParameterException
-
-
-abstract class SerialPortActivity : AppCompatActivity() {
-
- protected lateinit var binding: VB
-
- lateinit var out: OutputStream
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = initViewBinding()
- setContentView(binding.root)
- setupTopBarLayout()
- initOnCreate(savedInstanceState)
- observeRequestState()
- initEvent()
-
- try {
- val serialPorts = BaseApplication.get().getSerialPorts()
- //读
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[0].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[1].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- //写
- serialPorts?.apply {
- out = this[0].outputStream
- }
- } catch (e: SecurityException) {
- "您没有串口的读写权限!".show(this)
- } catch (e: IOException) {
- "因为不明原因,串口无法打开!".show(this)
- } catch (e: InvalidParameterException) {
- "请检查串口!".show(this)
- }
- }
-
- /**
- * 初始化ViewBinding
- */
- abstract fun initViewBinding(): VB
-
- /**
- * 特定页面定制沉浸式状态栏
- */
- abstract fun setupTopBarLayout()
-
- /**
- * 初始化默认数据
- */
- abstract fun initOnCreate(savedInstanceState: Bundle?)
-
- /**
- * 数据请求状态监听
- */
- abstract fun observeRequestState()
-
- /**
- * 初始化业务逻辑
- */
- abstract fun initEvent()
-
- /**
- * 串口读数,已经切回主线程
- * */
- abstract fun onDataReceived(buffer: ByteArray)
-
- override fun onDestroy() {
- super.onDestroy()
- BaseApplication.get().closeSerialPort()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
index 458f3fb..ca7de13 100644
--- a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
+++ b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
@@ -4,6 +4,7 @@
import com.casic.detector.common.greendao.DaoMaster
import com.casic.detector.common.greendao.DaoSession
import com.casic.detector.common.uart.SerialPort
+import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.SaveKeyValues
import java.io.File
import java.io.IOException
@@ -13,23 +14,12 @@
class BaseApplication : Application() {
private val kTag = "BaseApplication"
- private var serialPorts: ArrayList? = null
+ private var serialPorts = ArrayList()
- @Throws(SecurityException::class, IOException::class, InvalidParameterException::class)
- fun getSerialPorts(): ArrayList? {
- serialPorts = ArrayList()
- /**
- * Open the serial port
- * */
- serialPorts?.apply {
- add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
- add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
- }
- return serialPorts
- }
+ fun getSerialPorts(): ArrayList = serialPorts
fun closeSerialPort() {
- serialPorts?.forEach {
+ serialPorts.forEach {
it.closeSerialPort()
}
}
@@ -49,6 +39,22 @@
val devOpenHelper = DaoMaster.DevOpenHelper(this, "Detector_Common.db", null)
val daoMaster = DaoMaster(devOpenHelper.writableDatabase)
daoSession = daoMaster.newSession()
+
+ /**
+ * Open the serial port
+ * */
+ try {
+ serialPorts.apply {
+ add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
+ add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
+ }
+ } catch (e: SecurityException) {
+ "您没有串口的读写权限!".show(this)
+ } catch (e: IOException) {
+ "因为不明原因,串口无法打开!".show(this)
+ } catch (e: InvalidParameterException) {
+ "请检查串口!".show(this)
+ }
}
fun getDaoSession(): DaoSession {
diff --git a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt b/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
deleted file mode 100644
index 297ac02..0000000
--- a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.casic.detector.common.base
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.lifecycleScope
-import androidx.viewbinding.ViewBinding
-import com.pengxh.kt.lite.extensions.show
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.IOException
-import java.io.OutputStream
-import java.security.InvalidParameterException
-
-
-abstract class SerialPortActivity : AppCompatActivity() {
-
- protected lateinit var binding: VB
-
- lateinit var out: OutputStream
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = initViewBinding()
- setContentView(binding.root)
- setupTopBarLayout()
- initOnCreate(savedInstanceState)
- observeRequestState()
- initEvent()
-
- try {
- val serialPorts = BaseApplication.get().getSerialPorts()
- //读
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[0].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[1].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- //写
- serialPorts?.apply {
- out = this[0].outputStream
- }
- } catch (e: SecurityException) {
- "您没有串口的读写权限!".show(this)
- } catch (e: IOException) {
- "因为不明原因,串口无法打开!".show(this)
- } catch (e: InvalidParameterException) {
- "请检查串口!".show(this)
- }
- }
-
- /**
- * 初始化ViewBinding
- */
- abstract fun initViewBinding(): VB
-
- /**
- * 特定页面定制沉浸式状态栏
- */
- abstract fun setupTopBarLayout()
-
- /**
- * 初始化默认数据
- */
- abstract fun initOnCreate(savedInstanceState: Bundle?)
-
- /**
- * 数据请求状态监听
- */
- abstract fun observeRequestState()
-
- /**
- * 初始化业务逻辑
- */
- abstract fun initEvent()
-
- /**
- * 串口读数,已经切回主线程
- * */
- abstract fun onDataReceived(buffer: ByteArray)
-
- override fun onDestroy() {
- super.onDestroy()
- BaseApplication.get().closeSerialPort()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
new file mode 100644
index 0000000..b06a068
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
@@ -0,0 +1,9 @@
+package com.casic.detector.common.callback
+
+import java.io.OutputStream
+
+interface OnSerialPortDataListener {
+ fun write(outStream: OutputStream)
+
+ fun onDataReceived(buffer: ByteArray)
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
index 458f3fb..ca7de13 100644
--- a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
+++ b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
@@ -4,6 +4,7 @@
import com.casic.detector.common.greendao.DaoMaster
import com.casic.detector.common.greendao.DaoSession
import com.casic.detector.common.uart.SerialPort
+import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.SaveKeyValues
import java.io.File
import java.io.IOException
@@ -13,23 +14,12 @@
class BaseApplication : Application() {
private val kTag = "BaseApplication"
- private var serialPorts: ArrayList? = null
+ private var serialPorts = ArrayList()
- @Throws(SecurityException::class, IOException::class, InvalidParameterException::class)
- fun getSerialPorts(): ArrayList? {
- serialPorts = ArrayList()
- /**
- * Open the serial port
- * */
- serialPorts?.apply {
- add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
- add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
- }
- return serialPorts
- }
+ fun getSerialPorts(): ArrayList = serialPorts
fun closeSerialPort() {
- serialPorts?.forEach {
+ serialPorts.forEach {
it.closeSerialPort()
}
}
@@ -49,6 +39,22 @@
val devOpenHelper = DaoMaster.DevOpenHelper(this, "Detector_Common.db", null)
val daoMaster = DaoMaster(devOpenHelper.writableDatabase)
daoSession = daoMaster.newSession()
+
+ /**
+ * Open the serial port
+ * */
+ try {
+ serialPorts.apply {
+ add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
+ add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
+ }
+ } catch (e: SecurityException) {
+ "您没有串口的读写权限!".show(this)
+ } catch (e: IOException) {
+ "因为不明原因,串口无法打开!".show(this)
+ } catch (e: InvalidParameterException) {
+ "请检查串口!".show(this)
+ }
}
fun getDaoSession(): DaoSession {
diff --git a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt b/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
deleted file mode 100644
index 297ac02..0000000
--- a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.casic.detector.common.base
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.lifecycleScope
-import androidx.viewbinding.ViewBinding
-import com.pengxh.kt.lite.extensions.show
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.IOException
-import java.io.OutputStream
-import java.security.InvalidParameterException
-
-
-abstract class SerialPortActivity : AppCompatActivity() {
-
- protected lateinit var binding: VB
-
- lateinit var out: OutputStream
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = initViewBinding()
- setContentView(binding.root)
- setupTopBarLayout()
- initOnCreate(savedInstanceState)
- observeRequestState()
- initEvent()
-
- try {
- val serialPorts = BaseApplication.get().getSerialPorts()
- //读
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[0].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[1].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- //写
- serialPorts?.apply {
- out = this[0].outputStream
- }
- } catch (e: SecurityException) {
- "您没有串口的读写权限!".show(this)
- } catch (e: IOException) {
- "因为不明原因,串口无法打开!".show(this)
- } catch (e: InvalidParameterException) {
- "请检查串口!".show(this)
- }
- }
-
- /**
- * 初始化ViewBinding
- */
- abstract fun initViewBinding(): VB
-
- /**
- * 特定页面定制沉浸式状态栏
- */
- abstract fun setupTopBarLayout()
-
- /**
- * 初始化默认数据
- */
- abstract fun initOnCreate(savedInstanceState: Bundle?)
-
- /**
- * 数据请求状态监听
- */
- abstract fun observeRequestState()
-
- /**
- * 初始化业务逻辑
- */
- abstract fun initEvent()
-
- /**
- * 串口读数,已经切回主线程
- * */
- abstract fun onDataReceived(buffer: ByteArray)
-
- override fun onDestroy() {
- super.onDestroy()
- BaseApplication.get().closeSerialPort()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
new file mode 100644
index 0000000..b06a068
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
@@ -0,0 +1,9 @@
+package com.casic.detector.common.callback
+
+import java.io.OutputStream
+
+interface OnSerialPortDataListener {
+ fun write(outStream: OutputStream)
+
+ fun onDataReceived(buffer: ByteArray)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
new file mode 100644
index 0000000..b1685d5
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
@@ -0,0 +1,6 @@
+package com.casic.detector.common.model
+
+/**
+ * 标识器与当前定位的数据
+ * */
+data class MarkerDistanceData(var markerId: String, var distance: Float)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
index 458f3fb..ca7de13 100644
--- a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
+++ b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
@@ -4,6 +4,7 @@
import com.casic.detector.common.greendao.DaoMaster
import com.casic.detector.common.greendao.DaoSession
import com.casic.detector.common.uart.SerialPort
+import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.SaveKeyValues
import java.io.File
import java.io.IOException
@@ -13,23 +14,12 @@
class BaseApplication : Application() {
private val kTag = "BaseApplication"
- private var serialPorts: ArrayList? = null
+ private var serialPorts = ArrayList()
- @Throws(SecurityException::class, IOException::class, InvalidParameterException::class)
- fun getSerialPorts(): ArrayList? {
- serialPorts = ArrayList()
- /**
- * Open the serial port
- * */
- serialPorts?.apply {
- add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
- add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
- }
- return serialPorts
- }
+ fun getSerialPorts(): ArrayList = serialPorts
fun closeSerialPort() {
- serialPorts?.forEach {
+ serialPorts.forEach {
it.closeSerialPort()
}
}
@@ -49,6 +39,22 @@
val devOpenHelper = DaoMaster.DevOpenHelper(this, "Detector_Common.db", null)
val daoMaster = DaoMaster(devOpenHelper.writableDatabase)
daoSession = daoMaster.newSession()
+
+ /**
+ * Open the serial port
+ * */
+ try {
+ serialPorts.apply {
+ add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
+ add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
+ }
+ } catch (e: SecurityException) {
+ "您没有串口的读写权限!".show(this)
+ } catch (e: IOException) {
+ "因为不明原因,串口无法打开!".show(this)
+ } catch (e: InvalidParameterException) {
+ "请检查串口!".show(this)
+ }
}
fun getDaoSession(): DaoSession {
diff --git a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt b/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
deleted file mode 100644
index 297ac02..0000000
--- a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.casic.detector.common.base
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.lifecycleScope
-import androidx.viewbinding.ViewBinding
-import com.pengxh.kt.lite.extensions.show
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.IOException
-import java.io.OutputStream
-import java.security.InvalidParameterException
-
-
-abstract class SerialPortActivity : AppCompatActivity() {
-
- protected lateinit var binding: VB
-
- lateinit var out: OutputStream
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = initViewBinding()
- setContentView(binding.root)
- setupTopBarLayout()
- initOnCreate(savedInstanceState)
- observeRequestState()
- initEvent()
-
- try {
- val serialPorts = BaseApplication.get().getSerialPorts()
- //读
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[0].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[1].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- //写
- serialPorts?.apply {
- out = this[0].outputStream
- }
- } catch (e: SecurityException) {
- "您没有串口的读写权限!".show(this)
- } catch (e: IOException) {
- "因为不明原因,串口无法打开!".show(this)
- } catch (e: InvalidParameterException) {
- "请检查串口!".show(this)
- }
- }
-
- /**
- * 初始化ViewBinding
- */
- abstract fun initViewBinding(): VB
-
- /**
- * 特定页面定制沉浸式状态栏
- */
- abstract fun setupTopBarLayout()
-
- /**
- * 初始化默认数据
- */
- abstract fun initOnCreate(savedInstanceState: Bundle?)
-
- /**
- * 数据请求状态监听
- */
- abstract fun observeRequestState()
-
- /**
- * 初始化业务逻辑
- */
- abstract fun initEvent()
-
- /**
- * 串口读数,已经切回主线程
- * */
- abstract fun onDataReceived(buffer: ByteArray)
-
- override fun onDestroy() {
- super.onDestroy()
- BaseApplication.get().closeSerialPort()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
new file mode 100644
index 0000000..b06a068
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
@@ -0,0 +1,9 @@
+package com.casic.detector.common.callback
+
+import java.io.OutputStream
+
+interface OnSerialPortDataListener {
+ fun write(outStream: OutputStream)
+
+ fun onDataReceived(buffer: ByteArray)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
new file mode 100644
index 0000000..b1685d5
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
@@ -0,0 +1,6 @@
+package com.casic.detector.common.model
+
+/**
+ * 标识器与当前定位的数据
+ * */
+data class MarkerDistanceData(var markerId: String, var distance: Float)
diff --git a/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
new file mode 100644
index 0000000..090f604
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
@@ -0,0 +1,104 @@
+package com.casic.detector.common.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+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.base.BaseApplication
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.utils.GpioManager
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.IOException
+
+class SerialPortService : Service(), LifecycleOwner {
+
+ private val kTag = "SerialPortService"
+ private val registry = LifecycleRegistry(this)
+ private val gpioManager by lazy { GpioManager() }
+ private val serialPorts by lazy { BaseApplication.get().getSerialPorts() }
+ private var gpioState = ""
+
+ override fun getLifecycle(): Lifecycle {
+ return registry
+ }
+
+ override fun onBind(intent: Intent?): IBinder {
+ return ServiceBinder()
+ }
+
+ inner class ServiceBinder : Binder() {
+ fun getSerialPortService(): SerialPortService {
+ return this@SerialPortService
+ }
+ }
+
+ fun openSerialPort(listener: OnSerialPortDataListener) {
+ //调高串口电位
+ gpioManager.setGpioHigh("18")
+ gpioState = "1"
+ Log.d(kTag, "openSerialPort: 调高串口电位")
+
+ Thread.sleep(100)
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ //写
+ listener.write(this[0].outputStream)
+ val stream = this[0].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ val stream = this[1].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+ }
+
+ fun closeSerialPort() {
+ //降低串口电位
+ gpioManager.setGpioLow("18")
+ gpioState = "0"
+ Log.d(kTag, "closeSerialPort: 降低串口电位")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
index 458f3fb..ca7de13 100644
--- a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
+++ b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
@@ -4,6 +4,7 @@
import com.casic.detector.common.greendao.DaoMaster
import com.casic.detector.common.greendao.DaoSession
import com.casic.detector.common.uart.SerialPort
+import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.SaveKeyValues
import java.io.File
import java.io.IOException
@@ -13,23 +14,12 @@
class BaseApplication : Application() {
private val kTag = "BaseApplication"
- private var serialPorts: ArrayList? = null
+ private var serialPorts = ArrayList()
- @Throws(SecurityException::class, IOException::class, InvalidParameterException::class)
- fun getSerialPorts(): ArrayList? {
- serialPorts = ArrayList()
- /**
- * Open the serial port
- * */
- serialPorts?.apply {
- add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
- add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
- }
- return serialPorts
- }
+ fun getSerialPorts(): ArrayList = serialPorts
fun closeSerialPort() {
- serialPorts?.forEach {
+ serialPorts.forEach {
it.closeSerialPort()
}
}
@@ -49,6 +39,22 @@
val devOpenHelper = DaoMaster.DevOpenHelper(this, "Detector_Common.db", null)
val daoMaster = DaoMaster(devOpenHelper.writableDatabase)
daoSession = daoMaster.newSession()
+
+ /**
+ * Open the serial port
+ * */
+ try {
+ serialPorts.apply {
+ add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
+ add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
+ }
+ } catch (e: SecurityException) {
+ "您没有串口的读写权限!".show(this)
+ } catch (e: IOException) {
+ "因为不明原因,串口无法打开!".show(this)
+ } catch (e: InvalidParameterException) {
+ "请检查串口!".show(this)
+ }
}
fun getDaoSession(): DaoSession {
diff --git a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt b/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
deleted file mode 100644
index 297ac02..0000000
--- a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.casic.detector.common.base
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.lifecycleScope
-import androidx.viewbinding.ViewBinding
-import com.pengxh.kt.lite.extensions.show
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.IOException
-import java.io.OutputStream
-import java.security.InvalidParameterException
-
-
-abstract class SerialPortActivity : AppCompatActivity() {
-
- protected lateinit var binding: VB
-
- lateinit var out: OutputStream
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = initViewBinding()
- setContentView(binding.root)
- setupTopBarLayout()
- initOnCreate(savedInstanceState)
- observeRequestState()
- initEvent()
-
- try {
- val serialPorts = BaseApplication.get().getSerialPorts()
- //读
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[0].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[1].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- //写
- serialPorts?.apply {
- out = this[0].outputStream
- }
- } catch (e: SecurityException) {
- "您没有串口的读写权限!".show(this)
- } catch (e: IOException) {
- "因为不明原因,串口无法打开!".show(this)
- } catch (e: InvalidParameterException) {
- "请检查串口!".show(this)
- }
- }
-
- /**
- * 初始化ViewBinding
- */
- abstract fun initViewBinding(): VB
-
- /**
- * 特定页面定制沉浸式状态栏
- */
- abstract fun setupTopBarLayout()
-
- /**
- * 初始化默认数据
- */
- abstract fun initOnCreate(savedInstanceState: Bundle?)
-
- /**
- * 数据请求状态监听
- */
- abstract fun observeRequestState()
-
- /**
- * 初始化业务逻辑
- */
- abstract fun initEvent()
-
- /**
- * 串口读数,已经切回主线程
- * */
- abstract fun onDataReceived(buffer: ByteArray)
-
- override fun onDestroy() {
- super.onDestroy()
- BaseApplication.get().closeSerialPort()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
new file mode 100644
index 0000000..b06a068
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
@@ -0,0 +1,9 @@
+package com.casic.detector.common.callback
+
+import java.io.OutputStream
+
+interface OnSerialPortDataListener {
+ fun write(outStream: OutputStream)
+
+ fun onDataReceived(buffer: ByteArray)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
new file mode 100644
index 0000000..b1685d5
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
@@ -0,0 +1,6 @@
+package com.casic.detector.common.model
+
+/**
+ * 标识器与当前定位的数据
+ * */
+data class MarkerDistanceData(var markerId: String, var distance: Float)
diff --git a/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
new file mode 100644
index 0000000..090f604
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
@@ -0,0 +1,104 @@
+package com.casic.detector.common.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+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.base.BaseApplication
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.utils.GpioManager
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.IOException
+
+class SerialPortService : Service(), LifecycleOwner {
+
+ private val kTag = "SerialPortService"
+ private val registry = LifecycleRegistry(this)
+ private val gpioManager by lazy { GpioManager() }
+ private val serialPorts by lazy { BaseApplication.get().getSerialPorts() }
+ private var gpioState = ""
+
+ override fun getLifecycle(): Lifecycle {
+ return registry
+ }
+
+ override fun onBind(intent: Intent?): IBinder {
+ return ServiceBinder()
+ }
+
+ inner class ServiceBinder : Binder() {
+ fun getSerialPortService(): SerialPortService {
+ return this@SerialPortService
+ }
+ }
+
+ fun openSerialPort(listener: OnSerialPortDataListener) {
+ //调高串口电位
+ gpioManager.setGpioHigh("18")
+ gpioState = "1"
+ Log.d(kTag, "openSerialPort: 调高串口电位")
+
+ Thread.sleep(100)
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ //写
+ listener.write(this[0].outputStream)
+ val stream = this[0].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ val stream = this[1].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+ }
+
+ fun closeSerialPort() {
+ //降低串口电位
+ gpioManager.setGpioLow("18")
+ gpioState = "0"
+ Log.d(kTag, "closeSerialPort: 降低串口电位")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
new file mode 100644
index 0000000..b50aaaf
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
@@ -0,0 +1,548 @@
+package com.casic.detector.common.view
+
+import android.app.DatePickerDialog
+import android.content.ComponentName
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
+import android.media.AudioAttributes
+import android.media.SoundPool
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.IBinder
+import android.util.Log
+import android.view.View
+import android.widget.AdapterView
+import androidx.lifecycle.ViewModelProvider
+import com.amap.api.location.AMapLocation
+import com.casic.detector.common.R
+import com.casic.detector.common.adapter.EditableImageAdapter
+import com.casic.detector.common.bean.MarkerLocalBean
+import com.casic.detector.common.callback.OnGetLocationListener
+import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.databinding.ActivityInstallMarkerBinding
+import com.casic.detector.common.extensions.compressImage
+import com.casic.detector.common.extensions.getDefaultValue
+import com.casic.detector.common.extensions.hexToString
+import com.casic.detector.common.extensions.isNumber
+import com.casic.detector.common.extensions.setDefaultValue
+import com.casic.detector.common.extensions.show
+import com.casic.detector.common.extensions.toColor
+import com.casic.detector.common.extensions.toHex
+import com.casic.detector.common.extensions.toObjectType
+import com.casic.detector.common.service.SerialPortService
+import com.casic.detector.common.utils.DataBaseManager
+import com.casic.detector.common.utils.LocaleConstant
+import com.casic.detector.common.utils.LocationTool
+import com.casic.detector.common.vm.TaskViewModel
+import com.luck.picture.lib.basic.PictureSelector
+import com.luck.picture.lib.config.SelectMimeType
+import com.luck.picture.lib.entity.LocalMedia
+import com.luck.picture.lib.interfaces.OnResultCallbackListener
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.appendZero
+import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.extensions.dateToTimestamp
+import com.pengxh.kt.lite.extensions.navigatePageTo
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.extensions.timestampToCompleteDate
+import com.pengxh.kt.lite.extensions.timestampToTime
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.LoadState
+import com.pengxh.kt.lite.utils.LoadingDialogHub
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import java.io.File
+import java.io.OutputStream
+import java.util.Calendar
+import java.util.Date
+
+class InstallMarkerActivity : KotlinBaseActivity() {
+
+ private val kTag = "InstallMarkerActivity"
+ private val context = this
+ private val calendar by lazy { Calendar.getInstance() }
+ private val locationTool by lazy { LocationTool(this) }
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val realPaths = ArrayList() //真实图片路径
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var soundResourceId = 0
+ private var serialPortService: SerialPortService? = null
+ private lateinit var imageAdapter: EditableImageAdapter
+
+ override fun initEvent() {
+ //返回
+ binding.titleInclude.leftBackView.setOnClickListener {
+ soundPool.autoPause()
+ finish()
+ }
+
+ binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
+ object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(
+ parent: AdapterView<*>?, view: View?, position: Int, id: Long
+ ) {
+ when (position) {
+ 0 -> {
+ //显示管线属性
+ binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 1 -> {
+ //显示管线附属物属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 2 -> {
+ //显示管线特征点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 3 -> {
+ //显示交叉穿越点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.VISIBLE
+ }
+ }
+ }
+
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+
+ }
+ }
+
+ //安装
+ binding.installButton.setOnClickListener {
+ val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+ if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
+ when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
+ "管线" -> "请输入管线种类!".show(this)
+ "管线附属物" -> "请输入附属物名称!".show(this)
+ "管线特征管点" -> "请输入特征管点!".show(this)
+ "交叉穿越点" -> "请输入上层管种类!".show(this)
+ }
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
+ if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
+ "请输入管径".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
+ "请输入埋深".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
+ if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
+ "请输入下层管管径".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.areaView.text.isNullOrBlank()) {
+ "请输入所属区域".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.lineView.text.isNullOrBlank()) {
+ "请输入所属线路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.roadView.text.isNullOrBlank()) {
+ "请输入所属道路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
+ "请选择建设年代".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
+ "请输入权属单位".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
+ "请先读取标识器获取ID".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
+ "请输入标识器埋深".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
+ "请输入标识器安装部门".show(this)
+ return@setOnClickListener
+ }
+
+ //先存本地再上传服务器
+ saveMarkerInLocal()
+
+ taskViewModel.installLabel(
+ this, companyId,
+ binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
+ binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
+ "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.areaView.text.toString(),
+ binding.objectInclude.lineView.text.toString(),
+ binding.objectInclude.roadView.text.toString(),
+ binding.objectInclude.constructDateView.text.toString(),
+ binding.objectInclude.ownerView.text.toString(),
+ objectId,
+ binding.identifierInclude.identifierIdView.text.toString(),
+ binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
+ "${binding.identifierInclude.identifierDeepView.text}mm",
+ binding.identifierInclude.personDeptView.text.toString(),
+ binding.identifierInclude.installTimeView.text.toString(),
+ binding.identifierInclude.lngView.text.toString(),
+ binding.identifierInclude.latView.text.toString(),
+ binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
+ binding.remarkView.text.toString(),
+ realPaths
+ )
+
+ //保存默认值
+ "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
+ "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
+ "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
+ "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
+ "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
+ "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
+ "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
+ "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
+ "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
+ "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
+ "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
+ }
+
+ //读标识器
+ binding.readMarkerButton.setOnClickListener {
+ LoadingDialogHub.show(this, "标识器读取中,请稍后...")
+ countDownTimer.start()
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ outStream.write('2'.code)
+ outStream.flush()
+
+ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
+ binding.readMarkerButton.isEnabled = false
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ Log.d(kTag, hex)
+ val markerId = hex.take(20).hexToString()
+ if (markerId.isNumber()) {
+ countDownTimer.cancel()
+ cancelLoadingView()
+ binding.readMarkerButton.isEnabled = true
+ binding.identifierInclude.identifierIdView.text = markerId
+ }
+ }
+ })
+ }
+ }
+
+ /**
+ * 搜索标识器超时倒计时
+ * */
+ private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
+ override fun onTick(millisUntilFinished: Long) {
+
+ }
+
+ override fun onFinish() {
+ cancelLoadingView()
+ "读取此标识器ID超时,请重试".show(context)
+ binding.readMarkerButton.isEnabled = true
+ }
+ }
+
+ private fun cancelLoadingView() {
+ LoadingDialogHub.dismiss()
+ soundPool.autoPause()
+ serialPortService?.closeSerialPort()
+ }
+
+ private fun saveMarkerInLocal() {
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+
+ val marker = MarkerLocalBean()
+ marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
+ marker.pipelineType = binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
+ marker.pipelineMaterial =
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
+ marker.pipelineDiameter = "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
+ marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
+ marker.underlyingPipelineType =
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
+ marker.underlyingPipelineMaterial =
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
+ marker.underlyingPipelineDiameter =
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
+ marker.underlyingPipelineDepth =
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
+ marker.buryMethod =
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
+ marker.area = binding.objectInclude.areaView.text.toString()
+ marker.line = binding.objectInclude.lineView.text.toString()
+ marker.road = binding.objectInclude.roadView.text.toString()
+ marker.constructTime = binding.objectInclude.constructDateView.text.toString()
+ marker.owner = binding.objectInclude.ownerView.text.toString()
+ marker.objectId = objectId
+ marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
+ marker.markerType = binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
+ marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
+ marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
+ marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
+ marker.lng = binding.identifierInclude.lngView.text.toString()
+ marker.lat = binding.identifierInclude.latView.text.toString()
+ marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
+ marker.remark = binding.remarkView.text.toString()
+ marker.imagePath = realPaths.toJson()
+
+ DataBaseManager.get.saveMarkerInLocale(marker)
+ }
+
+ private fun takePicture() {
+ PictureSelector.create(this).openCamera(SelectMimeType.ofImage())
+ .forResult(object : OnResultCallbackListener {
+ override fun onResult(result: ArrayList?) {
+ if (result == null) {
+ "拍照失败,请重试".show(context)
+ return
+ }
+ analyticalSelectResults(result[0])
+ }
+
+ override fun onCancel() {
+
+ }
+ })
+ }
+
+ private fun analyticalSelectResults(result: LocalMedia) {
+ //压缩图片
+ result.realPath.compressImage(context, object : OnImageCompressListener {
+ override fun onSuccess(file: File) {
+ realPaths.add(file.absolutePath)
+ imageAdapter.setupImage(realPaths)
+ }
+
+ override fun onError(e: Throwable) {
+ e.printStackTrace()
+ }
+ })
+ }
+
+ 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?) {
+ //在连接正常关闭的情况下不会被调用, 只在Service被破坏了或者被杀死的时候调用
+ }
+ }
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ //绑定串口通信服务
+ Intent(this, SerialPortService::class.java).also {
+ bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
+ }
+
+ locationTool.getCurrentLocation(true, object : OnGetLocationListener {
+ override fun onAMapLocationGet(location: AMapLocation?) {
+ if (location != null) {
+ binding.identifierInclude.lngView.text = location.longitude.toString()
+ binding.identifierInclude.latView.text = location.latitude.toString()
+ } else {
+ "当前位置信号差,无法获取定位".show(context)
+ }
+ }
+ })
+ soundResourceId = soundPool.load(this, R.raw.ring3, 1)
+
+ //初始化数据
+ initDefaultData()
+ }
+
+ override fun initViewBinding(): ActivityInstallMarkerBinding {
+ return ActivityInstallMarkerBinding.inflate(layoutInflater)
+ }
+
+ override fun observeRequestState() {
+ taskViewModel.loadState.observe(this) {
+ when (it) {
+ LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...")
+
+ LoadState.Success -> {
+ LoadingDialogHub.dismiss()
+ clearDefaultData()
+ "安装成功".show(this)
+ }
+
+ else -> LoadingDialogHub.dismiss()
+ }
+ }
+ }
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ private fun initDefaultData() {
+ binding.titleInclude.titleView.text = "安装新标识器"
+ binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
+
+ imageAdapter = EditableImageAdapter(this, 3, 3)
+ binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
+
+ //设置默认值
+ binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
+ binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
+ binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
+ binding.objectInclude.areaView.setText("areaView".getDefaultValue())
+ binding.objectInclude.lineView.setText("lineView".getDefaultValue())
+ binding.objectInclude.roadView.setText("roadView".getDefaultValue())
+ binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
+ binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
+ binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
+
+ /**************************************************************************************/
+ binding.objectInclude.objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0)
+ binding.objectInclude.pipeInclude.materialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeAttachInclude.attachSpinner.show(
+ this, LocaleConstant.ATTACH_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
+ this, LocaleConstant.FEATURE_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeInclude.buryTypeSpinner.show(
+ this, LocaleConstant.BURY_METHOD_ARRAY, 0
+ )
+ binding.objectInclude.constructDateView.setOnClickListener {
+ val datePicker = DatePickerDialog(
+ this, null,
+ calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH),
+ calendar.get(Calendar.DAY_OF_MONTH)
+ )
+ datePicker.show()
+
+ datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
+ val year = datePicker.datePicker.year
+ val month = datePicker.datePicker.month + 1
+ val day = datePicker.datePicker.dayOfMonth
+ val selectedDate = String.format(
+ "%s-%s-%s", year, month.appendZero(), day.appendZero()
+ )
+
+ //当前时间
+ val current = System.currentTimeMillis().timestampToTime()
+ val today = "$selectedDate $current".dateToTimestamp()
+ if (Date(today).after(Date())) {
+ "建设年代不能早于当前日期".show(context)
+ } else {
+ datePicker.dismiss()
+ binding.objectInclude.constructDateView.text = selectedDate
+ }
+ }
+ }
+ binding.identifierInclude.identifierTypeSpinner.show(
+ this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
+ )
+ binding.identifierInclude.installTimeView.text =
+ System.currentTimeMillis().timestampToCompleteDate()
+ binding.identifierInclude.colorSpinner.show(this, LocaleConstant.COLOR_ARRAY, 0)
+
+ imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
+ override fun onAddImageClick() {
+ takePicture()
+ }
+
+ override fun onItemClick(position: Int) {
+ if (realPaths[position].isEmpty()) {
+ "图片加载失败,无法查看大图".show(context)
+ } else {
+ navigatePageTo(position, realPaths)
+ }
+ }
+
+ override fun onItemLongClick(view: View?, position: Int) {
+ imageAdapter.deleteImage(position)
+ }
+ })
+ }
+
+ //清除默认数据
+ private fun clearDefaultData() {
+ "markerObjectTypeView".setDefaultValue("")
+ "pipelineDiameterView".setDefaultValue("")
+ "buryDeepView".setDefaultValue("")
+ "bottomPipeDiameterView".setDefaultValue("")
+ "bottomPointDeepView".setDefaultValue("")
+ "areaView".setDefaultValue("")
+ "lineView".setDefaultValue("")
+ "roadView".setDefaultValue("")
+ "ownerView".setDefaultValue("")
+ "identifierDeepView".setDefaultValue("")
+ "personDeptView".setDefaultValue("")
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ soundPool.autoPause()
+ locationTool.stopLocation()
+ unbindService(serviceConnection)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
index 458f3fb..ca7de13 100644
--- a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
+++ b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
@@ -4,6 +4,7 @@
import com.casic.detector.common.greendao.DaoMaster
import com.casic.detector.common.greendao.DaoSession
import com.casic.detector.common.uart.SerialPort
+import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.SaveKeyValues
import java.io.File
import java.io.IOException
@@ -13,23 +14,12 @@
class BaseApplication : Application() {
private val kTag = "BaseApplication"
- private var serialPorts: ArrayList? = null
+ private var serialPorts = ArrayList()
- @Throws(SecurityException::class, IOException::class, InvalidParameterException::class)
- fun getSerialPorts(): ArrayList? {
- serialPorts = ArrayList()
- /**
- * Open the serial port
- * */
- serialPorts?.apply {
- add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
- add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
- }
- return serialPorts
- }
+ fun getSerialPorts(): ArrayList = serialPorts
fun closeSerialPort() {
- serialPorts?.forEach {
+ serialPorts.forEach {
it.closeSerialPort()
}
}
@@ -49,6 +39,22 @@
val devOpenHelper = DaoMaster.DevOpenHelper(this, "Detector_Common.db", null)
val daoMaster = DaoMaster(devOpenHelper.writableDatabase)
daoSession = daoMaster.newSession()
+
+ /**
+ * Open the serial port
+ * */
+ try {
+ serialPorts.apply {
+ add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
+ add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
+ }
+ } catch (e: SecurityException) {
+ "您没有串口的读写权限!".show(this)
+ } catch (e: IOException) {
+ "因为不明原因,串口无法打开!".show(this)
+ } catch (e: InvalidParameterException) {
+ "请检查串口!".show(this)
+ }
}
fun getDaoSession(): DaoSession {
diff --git a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt b/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
deleted file mode 100644
index 297ac02..0000000
--- a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.casic.detector.common.base
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.lifecycleScope
-import androidx.viewbinding.ViewBinding
-import com.pengxh.kt.lite.extensions.show
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.IOException
-import java.io.OutputStream
-import java.security.InvalidParameterException
-
-
-abstract class SerialPortActivity : AppCompatActivity() {
-
- protected lateinit var binding: VB
-
- lateinit var out: OutputStream
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = initViewBinding()
- setContentView(binding.root)
- setupTopBarLayout()
- initOnCreate(savedInstanceState)
- observeRequestState()
- initEvent()
-
- try {
- val serialPorts = BaseApplication.get().getSerialPorts()
- //读
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[0].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[1].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- //写
- serialPorts?.apply {
- out = this[0].outputStream
- }
- } catch (e: SecurityException) {
- "您没有串口的读写权限!".show(this)
- } catch (e: IOException) {
- "因为不明原因,串口无法打开!".show(this)
- } catch (e: InvalidParameterException) {
- "请检查串口!".show(this)
- }
- }
-
- /**
- * 初始化ViewBinding
- */
- abstract fun initViewBinding(): VB
-
- /**
- * 特定页面定制沉浸式状态栏
- */
- abstract fun setupTopBarLayout()
-
- /**
- * 初始化默认数据
- */
- abstract fun initOnCreate(savedInstanceState: Bundle?)
-
- /**
- * 数据请求状态监听
- */
- abstract fun observeRequestState()
-
- /**
- * 初始化业务逻辑
- */
- abstract fun initEvent()
-
- /**
- * 串口读数,已经切回主线程
- * */
- abstract fun onDataReceived(buffer: ByteArray)
-
- override fun onDestroy() {
- super.onDestroy()
- BaseApplication.get().closeSerialPort()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
new file mode 100644
index 0000000..b06a068
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
@@ -0,0 +1,9 @@
+package com.casic.detector.common.callback
+
+import java.io.OutputStream
+
+interface OnSerialPortDataListener {
+ fun write(outStream: OutputStream)
+
+ fun onDataReceived(buffer: ByteArray)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
new file mode 100644
index 0000000..b1685d5
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
@@ -0,0 +1,6 @@
+package com.casic.detector.common.model
+
+/**
+ * 标识器与当前定位的数据
+ * */
+data class MarkerDistanceData(var markerId: String, var distance: Float)
diff --git a/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
new file mode 100644
index 0000000..090f604
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
@@ -0,0 +1,104 @@
+package com.casic.detector.common.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+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.base.BaseApplication
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.utils.GpioManager
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.IOException
+
+class SerialPortService : Service(), LifecycleOwner {
+
+ private val kTag = "SerialPortService"
+ private val registry = LifecycleRegistry(this)
+ private val gpioManager by lazy { GpioManager() }
+ private val serialPorts by lazy { BaseApplication.get().getSerialPorts() }
+ private var gpioState = ""
+
+ override fun getLifecycle(): Lifecycle {
+ return registry
+ }
+
+ override fun onBind(intent: Intent?): IBinder {
+ return ServiceBinder()
+ }
+
+ inner class ServiceBinder : Binder() {
+ fun getSerialPortService(): SerialPortService {
+ return this@SerialPortService
+ }
+ }
+
+ fun openSerialPort(listener: OnSerialPortDataListener) {
+ //调高串口电位
+ gpioManager.setGpioHigh("18")
+ gpioState = "1"
+ Log.d(kTag, "openSerialPort: 调高串口电位")
+
+ Thread.sleep(100)
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ //写
+ listener.write(this[0].outputStream)
+ val stream = this[0].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ val stream = this[1].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+ }
+
+ fun closeSerialPort() {
+ //降低串口电位
+ gpioManager.setGpioLow("18")
+ gpioState = "0"
+ Log.d(kTag, "closeSerialPort: 降低串口电位")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
new file mode 100644
index 0000000..b50aaaf
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
@@ -0,0 +1,548 @@
+package com.casic.detector.common.view
+
+import android.app.DatePickerDialog
+import android.content.ComponentName
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
+import android.media.AudioAttributes
+import android.media.SoundPool
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.IBinder
+import android.util.Log
+import android.view.View
+import android.widget.AdapterView
+import androidx.lifecycle.ViewModelProvider
+import com.amap.api.location.AMapLocation
+import com.casic.detector.common.R
+import com.casic.detector.common.adapter.EditableImageAdapter
+import com.casic.detector.common.bean.MarkerLocalBean
+import com.casic.detector.common.callback.OnGetLocationListener
+import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.databinding.ActivityInstallMarkerBinding
+import com.casic.detector.common.extensions.compressImage
+import com.casic.detector.common.extensions.getDefaultValue
+import com.casic.detector.common.extensions.hexToString
+import com.casic.detector.common.extensions.isNumber
+import com.casic.detector.common.extensions.setDefaultValue
+import com.casic.detector.common.extensions.show
+import com.casic.detector.common.extensions.toColor
+import com.casic.detector.common.extensions.toHex
+import com.casic.detector.common.extensions.toObjectType
+import com.casic.detector.common.service.SerialPortService
+import com.casic.detector.common.utils.DataBaseManager
+import com.casic.detector.common.utils.LocaleConstant
+import com.casic.detector.common.utils.LocationTool
+import com.casic.detector.common.vm.TaskViewModel
+import com.luck.picture.lib.basic.PictureSelector
+import com.luck.picture.lib.config.SelectMimeType
+import com.luck.picture.lib.entity.LocalMedia
+import com.luck.picture.lib.interfaces.OnResultCallbackListener
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.appendZero
+import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.extensions.dateToTimestamp
+import com.pengxh.kt.lite.extensions.navigatePageTo
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.extensions.timestampToCompleteDate
+import com.pengxh.kt.lite.extensions.timestampToTime
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.LoadState
+import com.pengxh.kt.lite.utils.LoadingDialogHub
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import java.io.File
+import java.io.OutputStream
+import java.util.Calendar
+import java.util.Date
+
+class InstallMarkerActivity : KotlinBaseActivity() {
+
+ private val kTag = "InstallMarkerActivity"
+ private val context = this
+ private val calendar by lazy { Calendar.getInstance() }
+ private val locationTool by lazy { LocationTool(this) }
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val realPaths = ArrayList() //真实图片路径
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var soundResourceId = 0
+ private var serialPortService: SerialPortService? = null
+ private lateinit var imageAdapter: EditableImageAdapter
+
+ override fun initEvent() {
+ //返回
+ binding.titleInclude.leftBackView.setOnClickListener {
+ soundPool.autoPause()
+ finish()
+ }
+
+ binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
+ object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(
+ parent: AdapterView<*>?, view: View?, position: Int, id: Long
+ ) {
+ when (position) {
+ 0 -> {
+ //显示管线属性
+ binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 1 -> {
+ //显示管线附属物属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 2 -> {
+ //显示管线特征点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 3 -> {
+ //显示交叉穿越点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.VISIBLE
+ }
+ }
+ }
+
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+
+ }
+ }
+
+ //安装
+ binding.installButton.setOnClickListener {
+ val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+ if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
+ when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
+ "管线" -> "请输入管线种类!".show(this)
+ "管线附属物" -> "请输入附属物名称!".show(this)
+ "管线特征管点" -> "请输入特征管点!".show(this)
+ "交叉穿越点" -> "请输入上层管种类!".show(this)
+ }
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
+ if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
+ "请输入管径".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
+ "请输入埋深".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
+ if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
+ "请输入下层管管径".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.areaView.text.isNullOrBlank()) {
+ "请输入所属区域".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.lineView.text.isNullOrBlank()) {
+ "请输入所属线路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.roadView.text.isNullOrBlank()) {
+ "请输入所属道路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
+ "请选择建设年代".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
+ "请输入权属单位".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
+ "请先读取标识器获取ID".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
+ "请输入标识器埋深".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
+ "请输入标识器安装部门".show(this)
+ return@setOnClickListener
+ }
+
+ //先存本地再上传服务器
+ saveMarkerInLocal()
+
+ taskViewModel.installLabel(
+ this, companyId,
+ binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
+ binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
+ "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.areaView.text.toString(),
+ binding.objectInclude.lineView.text.toString(),
+ binding.objectInclude.roadView.text.toString(),
+ binding.objectInclude.constructDateView.text.toString(),
+ binding.objectInclude.ownerView.text.toString(),
+ objectId,
+ binding.identifierInclude.identifierIdView.text.toString(),
+ binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
+ "${binding.identifierInclude.identifierDeepView.text}mm",
+ binding.identifierInclude.personDeptView.text.toString(),
+ binding.identifierInclude.installTimeView.text.toString(),
+ binding.identifierInclude.lngView.text.toString(),
+ binding.identifierInclude.latView.text.toString(),
+ binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
+ binding.remarkView.text.toString(),
+ realPaths
+ )
+
+ //保存默认值
+ "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
+ "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
+ "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
+ "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
+ "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
+ "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
+ "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
+ "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
+ "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
+ "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
+ "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
+ }
+
+ //读标识器
+ binding.readMarkerButton.setOnClickListener {
+ LoadingDialogHub.show(this, "标识器读取中,请稍后...")
+ countDownTimer.start()
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ outStream.write('2'.code)
+ outStream.flush()
+
+ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
+ binding.readMarkerButton.isEnabled = false
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ Log.d(kTag, hex)
+ val markerId = hex.take(20).hexToString()
+ if (markerId.isNumber()) {
+ countDownTimer.cancel()
+ cancelLoadingView()
+ binding.readMarkerButton.isEnabled = true
+ binding.identifierInclude.identifierIdView.text = markerId
+ }
+ }
+ })
+ }
+ }
+
+ /**
+ * 搜索标识器超时倒计时
+ * */
+ private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
+ override fun onTick(millisUntilFinished: Long) {
+
+ }
+
+ override fun onFinish() {
+ cancelLoadingView()
+ "读取此标识器ID超时,请重试".show(context)
+ binding.readMarkerButton.isEnabled = true
+ }
+ }
+
+ private fun cancelLoadingView() {
+ LoadingDialogHub.dismiss()
+ soundPool.autoPause()
+ serialPortService?.closeSerialPort()
+ }
+
+ private fun saveMarkerInLocal() {
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+
+ val marker = MarkerLocalBean()
+ marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
+ marker.pipelineType = binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
+ marker.pipelineMaterial =
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
+ marker.pipelineDiameter = "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
+ marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
+ marker.underlyingPipelineType =
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
+ marker.underlyingPipelineMaterial =
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
+ marker.underlyingPipelineDiameter =
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
+ marker.underlyingPipelineDepth =
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
+ marker.buryMethod =
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
+ marker.area = binding.objectInclude.areaView.text.toString()
+ marker.line = binding.objectInclude.lineView.text.toString()
+ marker.road = binding.objectInclude.roadView.text.toString()
+ marker.constructTime = binding.objectInclude.constructDateView.text.toString()
+ marker.owner = binding.objectInclude.ownerView.text.toString()
+ marker.objectId = objectId
+ marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
+ marker.markerType = binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
+ marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
+ marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
+ marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
+ marker.lng = binding.identifierInclude.lngView.text.toString()
+ marker.lat = binding.identifierInclude.latView.text.toString()
+ marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
+ marker.remark = binding.remarkView.text.toString()
+ marker.imagePath = realPaths.toJson()
+
+ DataBaseManager.get.saveMarkerInLocale(marker)
+ }
+
+ private fun takePicture() {
+ PictureSelector.create(this).openCamera(SelectMimeType.ofImage())
+ .forResult(object : OnResultCallbackListener {
+ override fun onResult(result: ArrayList?) {
+ if (result == null) {
+ "拍照失败,请重试".show(context)
+ return
+ }
+ analyticalSelectResults(result[0])
+ }
+
+ override fun onCancel() {
+
+ }
+ })
+ }
+
+ private fun analyticalSelectResults(result: LocalMedia) {
+ //压缩图片
+ result.realPath.compressImage(context, object : OnImageCompressListener {
+ override fun onSuccess(file: File) {
+ realPaths.add(file.absolutePath)
+ imageAdapter.setupImage(realPaths)
+ }
+
+ override fun onError(e: Throwable) {
+ e.printStackTrace()
+ }
+ })
+ }
+
+ 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?) {
+ //在连接正常关闭的情况下不会被调用, 只在Service被破坏了或者被杀死的时候调用
+ }
+ }
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ //绑定串口通信服务
+ Intent(this, SerialPortService::class.java).also {
+ bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
+ }
+
+ locationTool.getCurrentLocation(true, object : OnGetLocationListener {
+ override fun onAMapLocationGet(location: AMapLocation?) {
+ if (location != null) {
+ binding.identifierInclude.lngView.text = location.longitude.toString()
+ binding.identifierInclude.latView.text = location.latitude.toString()
+ } else {
+ "当前位置信号差,无法获取定位".show(context)
+ }
+ }
+ })
+ soundResourceId = soundPool.load(this, R.raw.ring3, 1)
+
+ //初始化数据
+ initDefaultData()
+ }
+
+ override fun initViewBinding(): ActivityInstallMarkerBinding {
+ return ActivityInstallMarkerBinding.inflate(layoutInflater)
+ }
+
+ override fun observeRequestState() {
+ taskViewModel.loadState.observe(this) {
+ when (it) {
+ LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...")
+
+ LoadState.Success -> {
+ LoadingDialogHub.dismiss()
+ clearDefaultData()
+ "安装成功".show(this)
+ }
+
+ else -> LoadingDialogHub.dismiss()
+ }
+ }
+ }
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ private fun initDefaultData() {
+ binding.titleInclude.titleView.text = "安装新标识器"
+ binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
+
+ imageAdapter = EditableImageAdapter(this, 3, 3)
+ binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
+
+ //设置默认值
+ binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
+ binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
+ binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
+ binding.objectInclude.areaView.setText("areaView".getDefaultValue())
+ binding.objectInclude.lineView.setText("lineView".getDefaultValue())
+ binding.objectInclude.roadView.setText("roadView".getDefaultValue())
+ binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
+ binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
+ binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
+
+ /**************************************************************************************/
+ binding.objectInclude.objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0)
+ binding.objectInclude.pipeInclude.materialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeAttachInclude.attachSpinner.show(
+ this, LocaleConstant.ATTACH_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
+ this, LocaleConstant.FEATURE_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeInclude.buryTypeSpinner.show(
+ this, LocaleConstant.BURY_METHOD_ARRAY, 0
+ )
+ binding.objectInclude.constructDateView.setOnClickListener {
+ val datePicker = DatePickerDialog(
+ this, null,
+ calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH),
+ calendar.get(Calendar.DAY_OF_MONTH)
+ )
+ datePicker.show()
+
+ datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
+ val year = datePicker.datePicker.year
+ val month = datePicker.datePicker.month + 1
+ val day = datePicker.datePicker.dayOfMonth
+ val selectedDate = String.format(
+ "%s-%s-%s", year, month.appendZero(), day.appendZero()
+ )
+
+ //当前时间
+ val current = System.currentTimeMillis().timestampToTime()
+ val today = "$selectedDate $current".dateToTimestamp()
+ if (Date(today).after(Date())) {
+ "建设年代不能早于当前日期".show(context)
+ } else {
+ datePicker.dismiss()
+ binding.objectInclude.constructDateView.text = selectedDate
+ }
+ }
+ }
+ binding.identifierInclude.identifierTypeSpinner.show(
+ this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
+ )
+ binding.identifierInclude.installTimeView.text =
+ System.currentTimeMillis().timestampToCompleteDate()
+ binding.identifierInclude.colorSpinner.show(this, LocaleConstant.COLOR_ARRAY, 0)
+
+ imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
+ override fun onAddImageClick() {
+ takePicture()
+ }
+
+ override fun onItemClick(position: Int) {
+ if (realPaths[position].isEmpty()) {
+ "图片加载失败,无法查看大图".show(context)
+ } else {
+ navigatePageTo(position, realPaths)
+ }
+ }
+
+ override fun onItemLongClick(view: View?, position: Int) {
+ imageAdapter.deleteImage(position)
+ }
+ })
+ }
+
+ //清除默认数据
+ private fun clearDefaultData() {
+ "markerObjectTypeView".setDefaultValue("")
+ "pipelineDiameterView".setDefaultValue("")
+ "buryDeepView".setDefaultValue("")
+ "bottomPipeDiameterView".setDefaultValue("")
+ "bottomPointDeepView".setDefaultValue("")
+ "areaView".setDefaultValue("")
+ "lineView".setDefaultValue("")
+ "roadView".setDefaultValue("")
+ "ownerView".setDefaultValue("")
+ "identifierDeepView".setDefaultValue("")
+ "personDeptView".setDefaultValue("")
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ soundPool.autoPause()
+ locationTool.stopLocation()
+ 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 1dac658..f949269 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,31 +1,25 @@
package com.casic.detector.common.view
-import android.app.DatePickerDialog
-import android.app.Dialog
+import android.content.ComponentName
import android.content.Context
-import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
-import android.hardware.Sensor
-import android.hardware.SensorEvent
-import android.hardware.SensorEventListener
-import android.hardware.SensorManager
import android.media.AudioAttributes
import android.media.SoundPool
import android.os.Bundle
-import android.os.CountDownTimer
+import android.os.IBinder
import android.util.Log
import android.view.KeyEvent
import android.view.View
-import android.widget.AdapterView
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.amap.api.location.AMapLocation
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
-import com.amap.api.maps.AMapUtils
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.CoordinateConverter
import com.amap.api.maps.model.BitmapDescriptorFactory
@@ -34,38 +28,29 @@
import com.amap.api.maps.model.MarkerOptions
import com.amap.api.maps.model.MyLocationStyle
import com.casic.detector.common.R
-import com.casic.detector.common.adapter.EditableImageAdapter
-import com.casic.detector.common.base.SerialPortActivity
+import com.casic.detector.common.base.BaseApplication
import com.casic.detector.common.bean.MarkerLocalBean
import com.casic.detector.common.bean.TaskLocalBean
import com.casic.detector.common.callback.OnGetLocationListener
-import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
import com.casic.detector.common.cluster.ClusterItem
import com.casic.detector.common.cluster.ClusterOverlay
import com.casic.detector.common.cluster.RegionItem
import com.casic.detector.common.databinding.ActivityMainBinding
-import com.casic.detector.common.databinding.DialogInstallMarkerBinding
-import com.casic.detector.common.databinding.DialogSearchMarkerNewBinding
import com.casic.detector.common.extensions.appendDownloadUrl
-import com.casic.detector.common.extensions.compressImage
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.getDefaultValue
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.setDefaultValue
-import com.casic.detector.common.extensions.show
-import com.casic.detector.common.extensions.toColor
import com.casic.detector.common.extensions.toHex
-import com.casic.detector.common.extensions.toObjectType
import com.casic.detector.common.model.TaskDetailLocalModel
import com.casic.detector.common.model.TaskModel
+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.GpioManager
import com.casic.detector.common.utils.LocaleConstant
import com.casic.detector.common.utils.LocationTool
import com.casic.detector.common.utils.NtripAuthorizationCreator
@@ -77,26 +62,15 @@
import com.casic.detector.common.vm.TaskViewModel
import com.casic.detector.common.widgets.MarkerDetailDialog
import com.casic.detector.common.widgets.QueryMarkerDialog
-import com.casic.detector.common.widgets.RadarScanView
import com.casic.detector.common.widgets.SamplePopupWindow
-import com.luck.picture.lib.basic.PictureSelector
-import com.luck.picture.lib.config.SelectMimeType
-import com.luck.picture.lib.entity.LocalMedia
-import com.luck.picture.lib.interfaces.OnResultCallbackListener
-import com.pengxh.kt.lite.extensions.appendZero
-import com.pengxh.kt.lite.extensions.binding
-import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertDrawable
import com.pengxh.kt.lite.extensions.createDownloadFileDir
-import com.pengxh.kt.lite.extensions.dateToTimestamp
import com.pengxh.kt.lite.extensions.dp2px
-import com.pengxh.kt.lite.extensions.getSystemService
-import com.pengxh.kt.lite.extensions.initDialogLayoutParams
import com.pengxh.kt.lite.extensions.isNetworkConnected
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.extensions.timestampToCompleteDate
-import com.pengxh.kt.lite.extensions.timestampToTime
import com.pengxh.kt.lite.extensions.toJson
import com.pengxh.kt.lite.utils.FileDownloadManager
import com.pengxh.kt.lite.utils.LoadState
@@ -108,60 +82,41 @@
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
import io.netty.buffer.Unpooled
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
+import java.io.OutputStream
import java.nio.charset.StandardCharsets
-import java.util.Calendar
-import java.util.Date
import java.util.Timer
import java.util.TimerTask
-import kotlin.math.atan2
-class MainActivity : SerialPortActivity(), SensorEventListener,
- OnSocketConnectListener {
+class MainActivity : KotlinBaseActivity(), OnSocketConnectListener {
private val kTag = "MainActivity"
private val context = this
private val samplePopupWindow by lazy { SamplePopupWindow(this) }
private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) }
private val backDrawables by lazy { HashMap() }
- private val installDialog by lazy { InstallMarkerDialog(this) }
- private val searchNewDialog by lazy { SearchMarkerNewDialog(this) }
private val detailDialog by lazy { MarkerDetailDialog(this) }
private val locationTool by lazy { LocationTool(this) }
- private val rotationMatrix = FloatArray(9)//旋转矩阵缓存
- private val valueArray = FloatArray(3)//方位角数值
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
private var clickTime: Long = 0
private var markers = ArrayList()
private var clusterOverlay: ClusterOverlay? = null
private var isFreeTask = false
private var freeTaskTitle = ""
private var ids = HashSet()
- private var signalTask: TimerTask? = null
- private var energyTask: TimerTask? = null
- private var searchMarkerTimer: Timer? = null
private var freeTaskId: String? = null
- private var gravity: FloatArray? = null
- private var geomagnetic: FloatArray? = null
private var connectState = ConnectState.CLOSED
private var socketClient: SocketClient? = null
- private lateinit var aMap: AMap
- private lateinit var sensorManager: SensorManager
-
- /***inner class 需要用到*****start*/
- private val gpioManager by lazy { GpioManager() }
- private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
- private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
- .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
- private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var serialPortService: SerialPortService? = null
+ private var searchMarkerTimer: Timer? = null
private var soundResourceId = 0
- private var slowSoundResourceId = 0
- private var fastSoundResourceId = 0
private var isExecuteTask = false
-
- /***inner class 需要用到*****end*/
+ private lateinit var aMap: AMap
override fun initViewBinding(): ActivityMainBinding {
return ActivityMainBinding.inflate(layoutInflater)
@@ -171,10 +126,26 @@
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)
+ }
+
soundResourceId = soundPool.load(this, R.raw.ring3, 1)
- slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
- fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)
RtkLocationTool.getCurrentLocation(this) {
if (connectState == ConnectState.SUCCESS) {
@@ -192,8 +163,6 @@
samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES)
samplePopupWindow.setBackgroundDrawable(null)
- sensorManager = getSystemService()!!
-
//task网络请求监听
taskViewModel.markerFileResult.observe(this) {
if (it.isSuccess) {
@@ -316,9 +285,6 @@
//安装。上传,然后存入本地库
binding.installButton.setOnClickListener {
- /**
- * 改为Dialog方式,避免频繁打开/关闭串口
- * */
if (isFreeTask) {
AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示")
.setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能")
@@ -329,7 +295,7 @@
}
}).build().show()
} else {
- installDialog.show()
+ navigatePageTo()
}
}
@@ -449,8 +415,6 @@
//探测
binding.detectionButton.setOnClickListener {
/**
- * 改为Dialog方式,避免频繁打开/关闭串口
- *
* 如果开启自由巡检就不让探测
* */
if (isFreeTask) {
@@ -463,7 +427,12 @@
}
}).build().show()
} else {
- searchNewDialog.show()
+ val flag = if (isExecuteTask) {
+ "1"
+ } else {
+ "0"
+ }
+ navigatePageTo(flag)
}
}
@@ -476,14 +445,8 @@
override fun onConfirmClick() {
isFreeTask = false
soundPool.autoPause()
-
- //停止信号和ID搜索定时器
- signalTask?.cancel()
- energyTask?.cancel()
searchMarkerTimer?.cancel()
-
- //降低串口电位
- gpioManager.setGpioLow("18")
+ serialPortService?.closeSerialPort()
binding.stopFreeTaskButton.visibility = View.GONE
if (freeTaskId.isNullOrBlank()) {
@@ -527,110 +490,79 @@
}
private fun openSerialPort() {
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- isFreeTask = true
- //自由巡检
- signalTask = object : TimerTask() {
- override fun run() {
- out.write('2'.code)
- out.flush()
- }
- }
-
- energyTask = object : TimerTask() {
- override fun run() {
- out.write('6'.code)
- out.flush()
- }
- }
-
- searchMarkerTimer = Timer()
- searchMarkerTimer?.apply {
- schedule(signalTask, 0, 200)
- schedule(energyTask, 0, 251)
- }
-
binding.stopFreeTaskButton.visibility = View.VISIBLE
- }
+ isFreeTask = true
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ searchMarkerTimer = Timer()
+ searchMarkerTimer?.schedule(object : TimerTask() {
+ override fun run() {
+ outStream.write('2'.code)
+ outStream.flush()
- override fun onDataReceived(buffer: ByteArray) {
- val hex = buffer.toHex()
-// Log.d(kTag, "$kTag => $hex")
- if (searchNewDialog.isDetectMarker) {
- searchNewDialog.bindingValue(hex)
- } else if (installDialog.isReadMarker) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- installDialog.bindingValue(markerId)
+ Thread.sleep(50)
+
+ outStream.write('6'.code)
+ outStream.flush()
+ }
+ }, 0, 200)
}
- } else if (isFreeTask) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- //只响一次,因为探测频率高,所以依旧是连续的报警声
- soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
- //添加地图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))
- )
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ if (hex.startsWith("4E")) {
+ //只响一次,因为探测频率高,所以依旧是连续的报警声
+ soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
+
+ 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()
}
}
- 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()
+ 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 (hex.startsWith("4E")) {
- val energyResponse = hex.take(10).hexToString()
- try {
- val energy = energyResponse.substring(1).toInt()
- if (energy <= 500 && detailDialog.isShowing) {
- detailDialog.dismiss()
- }
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- }
- }
+ })
}
override fun observeRequestState() {
taskViewModel.loadState.observe(this) {
when (it) {
- LoadState.Loading -> {
- if (installDialog.isInstallMarker) {
- LoadingDialogHub.show(this, "标识器安装中,请稍后...")
- } else {
- LoadingDialogHub.show(this, "提交工单中,请稍后")
- }
- }
-
- LoadState.Success -> {
- if (installDialog.isInstallMarker) {
- installDialog.clearDefaultData()
- installDialog.dismiss()
- "${installDialog.markerId}安装成功".show(this)
- }
- LoadingDialogHub.dismiss()
- }
+ LoadState.Loading -> LoadingDialogHub.show(this, "提交工单中,请稍后")
else -> LoadingDialogHub.dismiss()
}
@@ -939,32 +871,6 @@
} else super.onKeyDown(keyCode, event)
}
- override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
- //精度发生变化时触发
- }
-
- override fun onSensorChanged(event: SensorEvent?) {
- //值发生变化时触发
- val type = event?.sensor?.type
-
- if (type == Sensor.TYPE_ACCELEROMETER) {
- gravity = event.values
- } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
- geomagnetic = event.values
- }
-
- if (gravity == null || geomagnetic == null) {
- return
- }
-
- if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
- SensorManager.getOrientation(rotationMatrix, valueArray)
-
- val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt()
- searchNewDialog.updateDegreeValue(degree)
- }
- }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
@@ -978,14 +884,6 @@
showLabelsOnMap()
}
- //注册加速度传感器监听
- val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
- sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)
-
- //注册磁场传感器监听
- val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
- sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL)
-
//取缓存
val remoteHost = SaveKeyValues.getValue(
LocaleConstant.RTK_SERVER, "203.107.45.154"
@@ -995,20 +893,20 @@
) as String
//连接千寻RTK服务器
- lifecycleScope.launch(Dispatchers.IO) {
- if (socketClient != null) {
- socketClient?.disconnect()
- delay(3000)
- }
-
- socketClient = SocketClient.Builder()
- .setHostname(remoteHost)
- .setPort(remotePort.toInt())
- .setTimeout(5000)
- .setOnSocketListener(this@MainActivity)
- .build()
- socketClient?.connect()
- }
+// lifecycleScope.launch(Dispatchers.IO) {
+// if (socketClient != null) {
+// socketClient?.disconnect()
+// delay(3000)
+// }
+//
+// socketClient = SocketClient.Builder()
+// .setHostname(remoteHost)
+// .setPort(remotePort.toInt())
+// .setTimeout(5000)
+// .setOnSocketListener(this@MainActivity)
+// .build()
+// socketClient?.connect()
+// }
}
override fun onMessageResponse(data: ByteArray) {
@@ -1021,12 +919,12 @@
val result = String(data, StandardCharsets.UTF_8)
Log.d(kTag, "onMessageResponse: $result")
if (result.contains("ICY 200 OK")) {
- "高精度定位服务器连接成功".show(this)
+ "高精度定位服务连接成功".show(this)
}
} else {
"收到千寻数据返回,长度:${data.size}".show(this)
- out.write(data)
- out.flush()
+// out.write(data)
+// out.flush()
}
}
@@ -1061,7 +959,6 @@
override fun onPause() {
super.onPause()
binding.mapView.onPause()
- sensorManager.unregisterListener(this)
}
override fun onSaveInstanceState(outState: Bundle) {
@@ -1072,794 +969,11 @@
override fun onDestroy() {
super.onDestroy()
binding.mapView.onDestroy()
- soundPool.release()
+ soundPool.autoPause()
+ searchMarkerTimer?.cancel()
+ serialPortService?.closeSerialPort()
locationTool.stopLocation()
- //降低串口电位
- gpioManager.setGpioLow("18")
+ unbindService(serviceConnection)
+ BaseApplication.get().closeSerialPort()
}
-
- /**安装标识器对话框******************************************************************************/
- inner class InstallMarkerDialog(private val context: Context) : Dialog(context) {
-
- private val binding: DialogInstallMarkerBinding by binding()
- private val calendar by lazy { Calendar.getInstance() }
- private val realPaths = ArrayList() //真实图片路径
- private lateinit var imageAdapter: EditableImageAdapter
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
-
- var isReadMarker = false
- var isInstallMarker = false
- var markerId = ""
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
-
- //初始化数据
- initDefaultData()
-
- //返回
- binding.titleInclude.leftBackView.setOnClickListener {
- soundPool.autoPause()
- dismiss()
- }
-
- binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
- object : AdapterView.OnItemSelectedListener {
- override fun onItemSelected(
- parent: AdapterView<*>?, view: View?, position: Int, id: Long
- ) {
- when (position) {
- 0 -> {
- //显示管线属性
- binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 1 -> {
- //显示管线附属物属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 2 -> {
- //显示管线特征点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 3 -> {
- //显示交叉穿越点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility =
- View.VISIBLE
- }
- }
- }
-
- override fun onNothingSelected(parent: AdapterView<*>?) {
-
- }
- }
-
- //安装
- binding.installButton.setOnClickListener {
- val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
- if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
- when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
- "管线" -> "请输入管线种类!".show(context)
- "管线附属物" -> "请输入附属物名称!".show(context)
- "管线特征管点" -> "请输入特征管点!".show(context)
- "交叉穿越点" -> "请输入上层管种类!".show(context)
- }
- return@setOnClickListener
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
- if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
- "请输入管径".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
- "请输入埋深".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
- if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
- "请输入下层管管径".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.areaView.text.isNullOrBlank()) {
- "请输入所属区域".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.lineView.text.isNullOrBlank()) {
- "请输入所属线路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.roadView.text.isNullOrBlank()) {
- "请输入所属道路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
- "请选择建设年代".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
- "请输入权属单位".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
- "请先读取标识器获取ID".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
- "请输入标识器埋深".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
- "请输入标识器安装部门".show(context)
- return@setOnClickListener
- }
-
- //先存本地再上传服务器
- saveMarkerInLocal()
-
- isInstallMarker = true
- taskViewModel.installLabel(
- context,
- companyId,
- binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
- "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
- binding.objectInclude.areaView.text.toString(),
- binding.objectInclude.lineView.text.toString(),
- binding.objectInclude.roadView.text.toString(),
- binding.objectInclude.constructDateView.text.toString(),
- binding.objectInclude.ownerView.text.toString(),
- objectId,
- binding.identifierInclude.identifierIdView.text.toString(),
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
- "${binding.identifierInclude.identifierDeepView.text}mm",
- binding.identifierInclude.personDeptView.text.toString(),
- binding.identifierInclude.installTimeView.text.toString(),
- binding.identifierInclude.lngView.text.toString(),
- binding.identifierInclude.latView.text.toString(),
- binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
- binding.remarkView.text.toString(),
- realPaths
- )
-
- //保存默认值
- "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
- "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
- "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
- "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
- "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
- "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
- "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
- "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
- "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
- "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
- "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
- }
-
- //读标识器
- binding.readMarkerButton.setOnClickListener {
- LoadingDialogHub.show(this@MainActivity, "标识器读取中,请稍后...")
- binding.readMarkerButton.isEnabled = false
-
- isReadMarker = true
-
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
-
- out.write('2'.code)
- out.flush()
-
- countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- "读取此标识器ID超时,请退出应用再试".show(context)
- }
- }
- countDownTimer.start()
- }
- }
-
- override fun show() {
- super.show()
- locationTool = LocationTool(context)
- locationTool.getCurrentLocation(true, object : OnGetLocationListener {
- override fun onAMapLocationGet(location: AMapLocation?) {
- if (location != null) {
- binding.identifierInclude.lngView.text = location.longitude.toString()
- binding.identifierInclude.latView.text = location.latitude.toString()
- } else {
- "当前位置信号差,无法获取定位".show(context)
- }
- }
- })
- }
-
- fun bindingValue(markerId: String) {
- this.markerId = markerId
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- countDownTimer.cancel()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- binding.identifierInclude.identifierIdView.text = markerId
- }
-
- override fun dismiss() {
- //降低串口电位
- gpioManager.setGpioLow("18")
- soundPool.autoPause()
- isInstallMarker = false
- locationTool.stopLocation()
- super.dismiss()
- }
-
- private fun initDefaultData() {
- binding.titleInclude.titleView.text = "安装新标识器"
- binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
-
- imageAdapter = EditableImageAdapter(context, 3, 3)
- binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
-
- //设置默认值
- binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
- binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
- binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
- binding.objectInclude.areaView.setText("areaView".getDefaultValue())
- binding.objectInclude.lineView.setText("lineView".getDefaultValue())
- binding.objectInclude.roadView.setText("roadView".getDefaultValue())
- binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
- binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
- binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
-
- /**************************************************************************************/
- binding.objectInclude.objectTypeSpinner.show(
- this@MainActivity, LocaleConstant.POINT_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.materialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeAttachInclude.attachSpinner.show(
- this@MainActivity, LocaleConstant.ATTACH_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
- this@MainActivity, LocaleConstant.FEATURE_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.buryTypeSpinner.show(
- this@MainActivity, LocaleConstant.BURY_METHOD_ARRAY, 0
- )
-
- binding.objectInclude.constructDateView.setOnClickListener {
- val datePicker = DatePickerDialog(
- context,
- null,
- calendar.get(Calendar.YEAR),
- calendar.get(Calendar.MONTH),
- calendar.get(Calendar.DAY_OF_MONTH)
- )
- datePicker.show()
-
- datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
- val year = datePicker.datePicker.year
- val month = datePicker.datePicker.month + 1
- val day = datePicker.datePicker.dayOfMonth
- val selectedDate = String.format(
- "%s-%s-%s", year, month.appendZero(), day.appendZero()
- )
-
- //当前时间
- val current = System.currentTimeMillis().timestampToTime()
- val today = "$selectedDate $current".dateToTimestamp()
- if (Date(today).after(Date())) {
- "建设年代不能早于当前日期".show(context)
- } else {
- datePicker.dismiss()
- binding.objectInclude.constructDateView.text = selectedDate
- }
- }
- }
-
- binding.identifierInclude.identifierTypeSpinner.show(
- this@MainActivity, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
- )
-
- binding.identifierInclude.installTimeView.text =
- System.currentTimeMillis().timestampToCompleteDate()
-
- binding.identifierInclude.colorSpinner.show(
- this@MainActivity, LocaleConstant.COLOR_ARRAY, 0
- )
-
- imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
- override fun onAddImageClick() {
- takePicture()
- }
-
- override fun onItemClick(position: Int) {
- if (realPaths[position].isEmpty()) {
- "图片加载失败,无法查看大图".show(context)
- } else {
- context.navigatePageTo(position, realPaths)
- }
- }
-
- override fun onItemLongClick(view: View?, position: Int) {
- imageAdapter.deleteImage(position)
- }
- })
- /**************************************************************************************/
- }
-
- //清除默认数据
- fun clearDefaultData() {
- "markerObjectTypeView".setDefaultValue("")
- "pipelineDiameterView".setDefaultValue("")
- "buryDeepView".setDefaultValue("")
- "bottomPipeDiameterView".setDefaultValue("")
- "bottomPointDeepView".setDefaultValue("")
- "areaView".setDefaultValue("")
- "lineView".setDefaultValue("")
- "roadView".setDefaultValue("")
- "ownerView".setDefaultValue("")
- "identifierDeepView".setDefaultValue("")
- "personDeptView".setDefaultValue("")
- }
-
- private fun saveMarkerInLocal() {
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
-
- val marker = MarkerLocalBean()
- marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
- marker.pipelineType =
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
- marker.pipelineMaterial =
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
- marker.pipelineDiameter =
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
- marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
- marker.underlyingPipelineType =
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
- marker.underlyingPipelineMaterial =
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
- marker.underlyingPipelineDiameter =
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
- marker.underlyingPipelineDepth =
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
- marker.buryMethod =
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
- marker.area = binding.objectInclude.areaView.text.toString()
- marker.line = binding.objectInclude.lineView.text.toString()
- marker.road = binding.objectInclude.roadView.text.toString()
- marker.constructTime = binding.objectInclude.constructDateView.text.toString()
- marker.owner = binding.objectInclude.ownerView.text.toString()
- marker.objectId = objectId
- marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
- marker.markerType =
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
- marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
- marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
- marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
- marker.lng = binding.identifierInclude.lngView.text.toString()
- marker.lat = binding.identifierInclude.latView.text.toString()
- marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
- marker.remark = binding.remarkView.text.toString()
- marker.imagePath = realPaths.toJson()
-
- DataBaseManager.get.saveMarkerInLocale(marker)
- }
-
- private fun takePicture() {
- PictureSelector.create(this@MainActivity).openCamera(SelectMimeType.ofImage())
- .forResult(object : OnResultCallbackListener {
- override fun onResult(result: java.util.ArrayList?) {
- if (result == null) {
- "拍照失败,请重试".show(context)
- return
- }
- analyticalSelectResults(result[0])
- }
-
- override fun onCancel() {
-
- }
- })
- }
-
- private fun analyticalSelectResults(result: LocalMedia) {
- //压缩图片
- result.realPath.compressImage(context, object : OnImageCompressListener {
- override fun onSuccess(file: File) {
- realPaths.add(file.absolutePath)
- imageAdapter.setupImage(realPaths)
- }
-
- override fun onError(e: Throwable) {
- e.printStackTrace()
- }
- })
- }
- }
-
- /**探测标识器新对话框****************************************************************************/
- inner class SearchMarkerNewDialog(private val context: Context) : Dialog(context) {
-
- private val taskId by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
- }
- private val taskCode by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_CODE, "") as String
- }
- private val markerPoints by lazy { ArrayList() }
- private val binding: DialogSearchMarkerNewBinding by binding()
- private var markerId = ""//实际探测出来的标识器ID
- private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID
- private lateinit var searchMarkerTimer: Timer
- private lateinit var signalTask: TimerTask
- private lateinit var energyTask: TimerTask
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
- var isDetectMarker = false
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
- binding.depthButton.setOnClickListener {
- signalTask.cancel()
- energyTask.cancel()
- searchMarkerTimer.cancel()
-
- out.write('3'.code)
- val result = DataBaseManager.get.queryMarkerById(markerId)
- if (result.isNotEmpty()) {
- val tag = when (result.first().markerType) {
- "EM30" -> '7'
- "EM50" -> '8'
- "EM14" -> '9'
- else -> '1'
- }
- if (tag == '1') {
- "此标识器无法读取埋深!".show(context)
- initTimer()
- } else {
- // 发送读取标识器埋设深度指令
- LoadingDialogHub.show(this@MainActivity, "正在测距,请稍后...")
- out.write(tag.code)
- out.flush()
- countDownTimer = object : CountDownTimer(15 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- "探测此标识器深度超时,请重试".show(context)
- initTimer()
- }
- }
- countDownTimer.start()
- }
- } else {
- "标识器未安装,安装成功后才可读取埋深!".show(context)
- initTimer()
- }
- }
-
- binding.markerInfoButton.setOnClickListener {
- val id = if (markerId == "") {
- nearestMarkerId
- } else {
- markerId
- }
- //查库
- val result = DataBaseManager.get.queryMarkerById(id)
- if (result.isNotEmpty()) {
- context.navigatePageTo(result.first().toJson())
- } else {
- context.navigatePageTo(id)
- }
- //查看完就把ID置空,便于下次查看最新的ID
- markerId = ""
- }
- }
-
- override fun show() {
- super.show()
- locationTool = LocationTool(context)
- //点位渲染,每次定位都计算当前位置与符合条件的点距离
- locationTool.getCurrentLocation(false, object : OnGetLocationListener {
- override fun onAMapLocationGet(location: AMapLocation?) {
- location?.apply {
- renderDataPoint(this)
- }
- }
- })
- }
-
- /**
- * 计算并渲染数据点。点太多采用协程计算,不然会有点卡顿
- * @param location 定位点(RTK获取)
- * */
- private fun renderDataPoint(location: AMapLocation) {
- val longitude = location.longitude
- val latitude = location.latitude
- lifecycleScope.launch(Dispatchers.IO) {
- val dataPoints = ArrayList()
- DataBaseManager.get.loadMarkers().forEach {
- val distance = AMapUtils.calculateLineDistance(
- LatLng(it.lat.toDouble(), it.lng.toDouble()), LatLng(latitude, longitude)
- )
- val formatDistance = "%.2f".format(distance).toFloat()
-
- markerPoints.add(MarkerDistanceData(it.markerId, formatDistance))
-
- if (formatDistance <= LocaleConstant.MAX_DISTANCE) {
- val angle = atan2(
- (it.lat.toDouble() - latitude), (it.lng.toDouble() - longitude)
- ) + Math.PI
- val formatAngle = "%.2f".format(angle).toDouble()
- dataPoints.add(
- RadarScanView.DataPoint(formatAngle, formatDistance)
- )
- }
- }
- withContext(Dispatchers.Main) {
- binding.radarScanView.renderPointData(dataPoints,
- object : RadarScanView.OnGetNearestPointCallback {
- override fun getNearestPoint(point: RadarScanView.DataPoint?) {
- if (point == null) {
- binding.distanceValueView.text = "大于5.5m"
- binding.distancePgBar.progress = 100
- } else {
- binding.distanceValueView.text = "${point.distance}m"
- val progress =
- if (point.distance > LocaleConstant.MAX_DISTANCE) {
- 100
- } else {
- (point.distance / LocaleConstant.MAX_DISTANCE) * 100
- }
- binding.distancePgBar.progress = progress.toInt()
- }
- }
- })
- }
- }
- }
-
- override fun onStart() {
- super.onStart()
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- initTimer()
-
- isDetectMarker = true
-
- if (isExecuteTask) {
- binding.taskStateView.visibility = View.GONE
- binding.taskStateView.isSelected = false
- } else {
- binding.taskStateView.visibility = View.VISIBLE
- binding.taskStateView.isSelected = true
- }
- }
-
- fun bindingValue(hex: String) {
- if (hex.startsWith("4E")) {
- try {
- //4E转为String为N,代表能量值
- //用能量值转动表盘
- val energyResponse = hex.take(10).hexToString()
- val energy = energyResponse.substring(1).toInt()
- if (energy >= 4000) {
- soundPool.play(fastSoundResourceId, 1f, 1f, 0, 0, 1f)
- } else {
- soundPool.play(slowSoundResourceId, 1f, 1f, 0, 0, 1f)
- }
-
- //通过设置进度条表示能量值
- binding.energyPgBar.progress = energy
- binding.energyValueView.text = "${energy}dB"
-
- if (energy <= 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.searchResultView.text = "未检测到标识器"
- binding.searchResultView.setTextColor(Color.parseColor("#8D1717"))
- binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_red)
- } else if (energy >= 4100) {
- binding.energyTipsView.text = "信号极强,接近标识器正上方"
- binding.energyTipsView.setTextColor(Color.parseColor("#428d00"))
- binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green)
-
- if (markerPoints.isEmpty()) {
- Log.d(kTag, "bindingValue: markerPoints.isEmpty()")
- return
- }
-
- //需要转一下,不然会有并发问题
- val temp = ArrayList()
- temp.addAll(markerPoints)
- temp.sortBy(MarkerDistanceData::distance)
- val nearestPoint = temp.first()
- nearestMarkerId = nearestPoint.markerId
- handleMarker(nearestMarkerId)
- } else {
- binding.energyTipsView.text = "已靠近,请继续移动位置"
- binding.energyTipsView.setTextColor(Color.parseColor("#8C5700"))
- binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow)
- }
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- } else if (hex.startsWith("53")) {
- LoadingDialogHub.dismiss()
- countDownTimer.cancel()
- try {
- val depthResponse = hex.take(10).hexToString()
- val depth = depthResponse.drop(2).toInt()
- AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示")
- .setMessage("标识器埋深:${depth}厘米").setPositiveButton("知道了")
- .setOnDialogButtonClickListener(object :
- AlertMessageDialog.OnDialogButtonClickListener {
- override fun onConfirmClick() {
- initTimer()
- }
- }).build().show()
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- } else {
- val id = hex.take(20).hexToString()
- if (id.isNumber()) {
- markerId = id
- handleMarker(markerId)
- }
- }
- }
-
- private fun handleMarker(id: String) {
- binding.depthButton.isEnabled = true
- binding.depthButton.setTextColor(Color.WHITE)
- binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
- binding.markerInfoButton.isEnabled = true
- binding.markerInfoButton.setTextColor(Color.WHITE)
- binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)
-
- binding.searchResultView.text = "已检测到标识器"
- binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
- binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)
-
- //自动上传标识器
- if (isExecuteTask) {
- val taskMarkerLocalBean = DataBaseManager.get.queryTaskMarkerById(
- taskId, taskCode, id, "0"
- )
- taskMarkerLocalBean?.apply {
- taskViewModel.uploadMarker(context, this)
- }
- }
- }
-
- //更新罗盘角度
- fun updateDegreeValue(degree: Int) {
- binding.radarScanView.setDegreeValue(degree)
- }
-
- private fun initTimer() {
- searchMarkerTimer = Timer()
-
- signalTask = object : TimerTask() {
- override fun run() {
- out.write('2'.code)
- out.flush()
- }
- }
-
- energyTask = object : TimerTask() {
- override fun run() {
- out.write('6'.code)
- out.flush()
- }
- }
-
- //错开信号和能量定时器
- searchMarkerTimer.schedule(signalTask, 0, 201)
- searchMarkerTimer.schedule(energyTask, 0, 251)
- }
-
- override fun dismiss() {
- signalTask.cancel()
- energyTask.cancel()
- searchMarkerTimer.cancel()
- //降低串口电位
- gpioManager.setGpioLow("18")
- isDetectMarker = false
- soundPool.autoPause()
- locationTool.stopLocation()
- super.dismiss()
- }
- }
-
- /**
- * 标识器与当前定位的数据
- * */
- data class MarkerDistanceData(var markerId: String, var distance: Float)
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
index 458f3fb..ca7de13 100644
--- a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
+++ b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
@@ -4,6 +4,7 @@
import com.casic.detector.common.greendao.DaoMaster
import com.casic.detector.common.greendao.DaoSession
import com.casic.detector.common.uart.SerialPort
+import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.SaveKeyValues
import java.io.File
import java.io.IOException
@@ -13,23 +14,12 @@
class BaseApplication : Application() {
private val kTag = "BaseApplication"
- private var serialPorts: ArrayList? = null
+ private var serialPorts = ArrayList()
- @Throws(SecurityException::class, IOException::class, InvalidParameterException::class)
- fun getSerialPorts(): ArrayList? {
- serialPorts = ArrayList()
- /**
- * Open the serial port
- * */
- serialPorts?.apply {
- add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
- add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
- }
- return serialPorts
- }
+ fun getSerialPorts(): ArrayList = serialPorts
fun closeSerialPort() {
- serialPorts?.forEach {
+ serialPorts.forEach {
it.closeSerialPort()
}
}
@@ -49,6 +39,22 @@
val devOpenHelper = DaoMaster.DevOpenHelper(this, "Detector_Common.db", null)
val daoMaster = DaoMaster(devOpenHelper.writableDatabase)
daoSession = daoMaster.newSession()
+
+ /**
+ * Open the serial port
+ * */
+ try {
+ serialPorts.apply {
+ add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
+ add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
+ }
+ } catch (e: SecurityException) {
+ "您没有串口的读写权限!".show(this)
+ } catch (e: IOException) {
+ "因为不明原因,串口无法打开!".show(this)
+ } catch (e: InvalidParameterException) {
+ "请检查串口!".show(this)
+ }
}
fun getDaoSession(): DaoSession {
diff --git a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt b/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
deleted file mode 100644
index 297ac02..0000000
--- a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.casic.detector.common.base
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.lifecycleScope
-import androidx.viewbinding.ViewBinding
-import com.pengxh.kt.lite.extensions.show
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.IOException
-import java.io.OutputStream
-import java.security.InvalidParameterException
-
-
-abstract class SerialPortActivity : AppCompatActivity() {
-
- protected lateinit var binding: VB
-
- lateinit var out: OutputStream
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = initViewBinding()
- setContentView(binding.root)
- setupTopBarLayout()
- initOnCreate(savedInstanceState)
- observeRequestState()
- initEvent()
-
- try {
- val serialPorts = BaseApplication.get().getSerialPorts()
- //读
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[0].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[1].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- //写
- serialPorts?.apply {
- out = this[0].outputStream
- }
- } catch (e: SecurityException) {
- "您没有串口的读写权限!".show(this)
- } catch (e: IOException) {
- "因为不明原因,串口无法打开!".show(this)
- } catch (e: InvalidParameterException) {
- "请检查串口!".show(this)
- }
- }
-
- /**
- * 初始化ViewBinding
- */
- abstract fun initViewBinding(): VB
-
- /**
- * 特定页面定制沉浸式状态栏
- */
- abstract fun setupTopBarLayout()
-
- /**
- * 初始化默认数据
- */
- abstract fun initOnCreate(savedInstanceState: Bundle?)
-
- /**
- * 数据请求状态监听
- */
- abstract fun observeRequestState()
-
- /**
- * 初始化业务逻辑
- */
- abstract fun initEvent()
-
- /**
- * 串口读数,已经切回主线程
- * */
- abstract fun onDataReceived(buffer: ByteArray)
-
- override fun onDestroy() {
- super.onDestroy()
- BaseApplication.get().closeSerialPort()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
new file mode 100644
index 0000000..b06a068
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
@@ -0,0 +1,9 @@
+package com.casic.detector.common.callback
+
+import java.io.OutputStream
+
+interface OnSerialPortDataListener {
+ fun write(outStream: OutputStream)
+
+ fun onDataReceived(buffer: ByteArray)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
new file mode 100644
index 0000000..b1685d5
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
@@ -0,0 +1,6 @@
+package com.casic.detector.common.model
+
+/**
+ * 标识器与当前定位的数据
+ * */
+data class MarkerDistanceData(var markerId: String, var distance: Float)
diff --git a/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
new file mode 100644
index 0000000..090f604
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
@@ -0,0 +1,104 @@
+package com.casic.detector.common.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+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.base.BaseApplication
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.utils.GpioManager
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.IOException
+
+class SerialPortService : Service(), LifecycleOwner {
+
+ private val kTag = "SerialPortService"
+ private val registry = LifecycleRegistry(this)
+ private val gpioManager by lazy { GpioManager() }
+ private val serialPorts by lazy { BaseApplication.get().getSerialPorts() }
+ private var gpioState = ""
+
+ override fun getLifecycle(): Lifecycle {
+ return registry
+ }
+
+ override fun onBind(intent: Intent?): IBinder {
+ return ServiceBinder()
+ }
+
+ inner class ServiceBinder : Binder() {
+ fun getSerialPortService(): SerialPortService {
+ return this@SerialPortService
+ }
+ }
+
+ fun openSerialPort(listener: OnSerialPortDataListener) {
+ //调高串口电位
+ gpioManager.setGpioHigh("18")
+ gpioState = "1"
+ Log.d(kTag, "openSerialPort: 调高串口电位")
+
+ Thread.sleep(100)
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ //写
+ listener.write(this[0].outputStream)
+ val stream = this[0].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ val stream = this[1].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+ }
+
+ fun closeSerialPort() {
+ //降低串口电位
+ gpioManager.setGpioLow("18")
+ gpioState = "0"
+ Log.d(kTag, "closeSerialPort: 降低串口电位")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
new file mode 100644
index 0000000..b50aaaf
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
@@ -0,0 +1,548 @@
+package com.casic.detector.common.view
+
+import android.app.DatePickerDialog
+import android.content.ComponentName
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
+import android.media.AudioAttributes
+import android.media.SoundPool
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.IBinder
+import android.util.Log
+import android.view.View
+import android.widget.AdapterView
+import androidx.lifecycle.ViewModelProvider
+import com.amap.api.location.AMapLocation
+import com.casic.detector.common.R
+import com.casic.detector.common.adapter.EditableImageAdapter
+import com.casic.detector.common.bean.MarkerLocalBean
+import com.casic.detector.common.callback.OnGetLocationListener
+import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.databinding.ActivityInstallMarkerBinding
+import com.casic.detector.common.extensions.compressImage
+import com.casic.detector.common.extensions.getDefaultValue
+import com.casic.detector.common.extensions.hexToString
+import com.casic.detector.common.extensions.isNumber
+import com.casic.detector.common.extensions.setDefaultValue
+import com.casic.detector.common.extensions.show
+import com.casic.detector.common.extensions.toColor
+import com.casic.detector.common.extensions.toHex
+import com.casic.detector.common.extensions.toObjectType
+import com.casic.detector.common.service.SerialPortService
+import com.casic.detector.common.utils.DataBaseManager
+import com.casic.detector.common.utils.LocaleConstant
+import com.casic.detector.common.utils.LocationTool
+import com.casic.detector.common.vm.TaskViewModel
+import com.luck.picture.lib.basic.PictureSelector
+import com.luck.picture.lib.config.SelectMimeType
+import com.luck.picture.lib.entity.LocalMedia
+import com.luck.picture.lib.interfaces.OnResultCallbackListener
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.appendZero
+import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.extensions.dateToTimestamp
+import com.pengxh.kt.lite.extensions.navigatePageTo
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.extensions.timestampToCompleteDate
+import com.pengxh.kt.lite.extensions.timestampToTime
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.LoadState
+import com.pengxh.kt.lite.utils.LoadingDialogHub
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import java.io.File
+import java.io.OutputStream
+import java.util.Calendar
+import java.util.Date
+
+class InstallMarkerActivity : KotlinBaseActivity() {
+
+ private val kTag = "InstallMarkerActivity"
+ private val context = this
+ private val calendar by lazy { Calendar.getInstance() }
+ private val locationTool by lazy { LocationTool(this) }
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val realPaths = ArrayList() //真实图片路径
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var soundResourceId = 0
+ private var serialPortService: SerialPortService? = null
+ private lateinit var imageAdapter: EditableImageAdapter
+
+ override fun initEvent() {
+ //返回
+ binding.titleInclude.leftBackView.setOnClickListener {
+ soundPool.autoPause()
+ finish()
+ }
+
+ binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
+ object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(
+ parent: AdapterView<*>?, view: View?, position: Int, id: Long
+ ) {
+ when (position) {
+ 0 -> {
+ //显示管线属性
+ binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 1 -> {
+ //显示管线附属物属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 2 -> {
+ //显示管线特征点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 3 -> {
+ //显示交叉穿越点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.VISIBLE
+ }
+ }
+ }
+
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+
+ }
+ }
+
+ //安装
+ binding.installButton.setOnClickListener {
+ val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+ if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
+ when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
+ "管线" -> "请输入管线种类!".show(this)
+ "管线附属物" -> "请输入附属物名称!".show(this)
+ "管线特征管点" -> "请输入特征管点!".show(this)
+ "交叉穿越点" -> "请输入上层管种类!".show(this)
+ }
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
+ if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
+ "请输入管径".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
+ "请输入埋深".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
+ if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
+ "请输入下层管管径".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.areaView.text.isNullOrBlank()) {
+ "请输入所属区域".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.lineView.text.isNullOrBlank()) {
+ "请输入所属线路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.roadView.text.isNullOrBlank()) {
+ "请输入所属道路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
+ "请选择建设年代".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
+ "请输入权属单位".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
+ "请先读取标识器获取ID".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
+ "请输入标识器埋深".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
+ "请输入标识器安装部门".show(this)
+ return@setOnClickListener
+ }
+
+ //先存本地再上传服务器
+ saveMarkerInLocal()
+
+ taskViewModel.installLabel(
+ this, companyId,
+ binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
+ binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
+ "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.areaView.text.toString(),
+ binding.objectInclude.lineView.text.toString(),
+ binding.objectInclude.roadView.text.toString(),
+ binding.objectInclude.constructDateView.text.toString(),
+ binding.objectInclude.ownerView.text.toString(),
+ objectId,
+ binding.identifierInclude.identifierIdView.text.toString(),
+ binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
+ "${binding.identifierInclude.identifierDeepView.text}mm",
+ binding.identifierInclude.personDeptView.text.toString(),
+ binding.identifierInclude.installTimeView.text.toString(),
+ binding.identifierInclude.lngView.text.toString(),
+ binding.identifierInclude.latView.text.toString(),
+ binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
+ binding.remarkView.text.toString(),
+ realPaths
+ )
+
+ //保存默认值
+ "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
+ "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
+ "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
+ "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
+ "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
+ "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
+ "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
+ "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
+ "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
+ "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
+ "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
+ }
+
+ //读标识器
+ binding.readMarkerButton.setOnClickListener {
+ LoadingDialogHub.show(this, "标识器读取中,请稍后...")
+ countDownTimer.start()
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ outStream.write('2'.code)
+ outStream.flush()
+
+ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
+ binding.readMarkerButton.isEnabled = false
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ Log.d(kTag, hex)
+ val markerId = hex.take(20).hexToString()
+ if (markerId.isNumber()) {
+ countDownTimer.cancel()
+ cancelLoadingView()
+ binding.readMarkerButton.isEnabled = true
+ binding.identifierInclude.identifierIdView.text = markerId
+ }
+ }
+ })
+ }
+ }
+
+ /**
+ * 搜索标识器超时倒计时
+ * */
+ private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
+ override fun onTick(millisUntilFinished: Long) {
+
+ }
+
+ override fun onFinish() {
+ cancelLoadingView()
+ "读取此标识器ID超时,请重试".show(context)
+ binding.readMarkerButton.isEnabled = true
+ }
+ }
+
+ private fun cancelLoadingView() {
+ LoadingDialogHub.dismiss()
+ soundPool.autoPause()
+ serialPortService?.closeSerialPort()
+ }
+
+ private fun saveMarkerInLocal() {
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+
+ val marker = MarkerLocalBean()
+ marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
+ marker.pipelineType = binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
+ marker.pipelineMaterial =
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
+ marker.pipelineDiameter = "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
+ marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
+ marker.underlyingPipelineType =
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
+ marker.underlyingPipelineMaterial =
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
+ marker.underlyingPipelineDiameter =
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
+ marker.underlyingPipelineDepth =
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
+ marker.buryMethod =
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
+ marker.area = binding.objectInclude.areaView.text.toString()
+ marker.line = binding.objectInclude.lineView.text.toString()
+ marker.road = binding.objectInclude.roadView.text.toString()
+ marker.constructTime = binding.objectInclude.constructDateView.text.toString()
+ marker.owner = binding.objectInclude.ownerView.text.toString()
+ marker.objectId = objectId
+ marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
+ marker.markerType = binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
+ marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
+ marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
+ marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
+ marker.lng = binding.identifierInclude.lngView.text.toString()
+ marker.lat = binding.identifierInclude.latView.text.toString()
+ marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
+ marker.remark = binding.remarkView.text.toString()
+ marker.imagePath = realPaths.toJson()
+
+ DataBaseManager.get.saveMarkerInLocale(marker)
+ }
+
+ private fun takePicture() {
+ PictureSelector.create(this).openCamera(SelectMimeType.ofImage())
+ .forResult(object : OnResultCallbackListener {
+ override fun onResult(result: ArrayList?) {
+ if (result == null) {
+ "拍照失败,请重试".show(context)
+ return
+ }
+ analyticalSelectResults(result[0])
+ }
+
+ override fun onCancel() {
+
+ }
+ })
+ }
+
+ private fun analyticalSelectResults(result: LocalMedia) {
+ //压缩图片
+ result.realPath.compressImage(context, object : OnImageCompressListener {
+ override fun onSuccess(file: File) {
+ realPaths.add(file.absolutePath)
+ imageAdapter.setupImage(realPaths)
+ }
+
+ override fun onError(e: Throwable) {
+ e.printStackTrace()
+ }
+ })
+ }
+
+ 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?) {
+ //在连接正常关闭的情况下不会被调用, 只在Service被破坏了或者被杀死的时候调用
+ }
+ }
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ //绑定串口通信服务
+ Intent(this, SerialPortService::class.java).also {
+ bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
+ }
+
+ locationTool.getCurrentLocation(true, object : OnGetLocationListener {
+ override fun onAMapLocationGet(location: AMapLocation?) {
+ if (location != null) {
+ binding.identifierInclude.lngView.text = location.longitude.toString()
+ binding.identifierInclude.latView.text = location.latitude.toString()
+ } else {
+ "当前位置信号差,无法获取定位".show(context)
+ }
+ }
+ })
+ soundResourceId = soundPool.load(this, R.raw.ring3, 1)
+
+ //初始化数据
+ initDefaultData()
+ }
+
+ override fun initViewBinding(): ActivityInstallMarkerBinding {
+ return ActivityInstallMarkerBinding.inflate(layoutInflater)
+ }
+
+ override fun observeRequestState() {
+ taskViewModel.loadState.observe(this) {
+ when (it) {
+ LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...")
+
+ LoadState.Success -> {
+ LoadingDialogHub.dismiss()
+ clearDefaultData()
+ "安装成功".show(this)
+ }
+
+ else -> LoadingDialogHub.dismiss()
+ }
+ }
+ }
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ private fun initDefaultData() {
+ binding.titleInclude.titleView.text = "安装新标识器"
+ binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
+
+ imageAdapter = EditableImageAdapter(this, 3, 3)
+ binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
+
+ //设置默认值
+ binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
+ binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
+ binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
+ binding.objectInclude.areaView.setText("areaView".getDefaultValue())
+ binding.objectInclude.lineView.setText("lineView".getDefaultValue())
+ binding.objectInclude.roadView.setText("roadView".getDefaultValue())
+ binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
+ binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
+ binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
+
+ /**************************************************************************************/
+ binding.objectInclude.objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0)
+ binding.objectInclude.pipeInclude.materialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeAttachInclude.attachSpinner.show(
+ this, LocaleConstant.ATTACH_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
+ this, LocaleConstant.FEATURE_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeInclude.buryTypeSpinner.show(
+ this, LocaleConstant.BURY_METHOD_ARRAY, 0
+ )
+ binding.objectInclude.constructDateView.setOnClickListener {
+ val datePicker = DatePickerDialog(
+ this, null,
+ calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH),
+ calendar.get(Calendar.DAY_OF_MONTH)
+ )
+ datePicker.show()
+
+ datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
+ val year = datePicker.datePicker.year
+ val month = datePicker.datePicker.month + 1
+ val day = datePicker.datePicker.dayOfMonth
+ val selectedDate = String.format(
+ "%s-%s-%s", year, month.appendZero(), day.appendZero()
+ )
+
+ //当前时间
+ val current = System.currentTimeMillis().timestampToTime()
+ val today = "$selectedDate $current".dateToTimestamp()
+ if (Date(today).after(Date())) {
+ "建设年代不能早于当前日期".show(context)
+ } else {
+ datePicker.dismiss()
+ binding.objectInclude.constructDateView.text = selectedDate
+ }
+ }
+ }
+ binding.identifierInclude.identifierTypeSpinner.show(
+ this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
+ )
+ binding.identifierInclude.installTimeView.text =
+ System.currentTimeMillis().timestampToCompleteDate()
+ binding.identifierInclude.colorSpinner.show(this, LocaleConstant.COLOR_ARRAY, 0)
+
+ imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
+ override fun onAddImageClick() {
+ takePicture()
+ }
+
+ override fun onItemClick(position: Int) {
+ if (realPaths[position].isEmpty()) {
+ "图片加载失败,无法查看大图".show(context)
+ } else {
+ navigatePageTo(position, realPaths)
+ }
+ }
+
+ override fun onItemLongClick(view: View?, position: Int) {
+ imageAdapter.deleteImage(position)
+ }
+ })
+ }
+
+ //清除默认数据
+ private fun clearDefaultData() {
+ "markerObjectTypeView".setDefaultValue("")
+ "pipelineDiameterView".setDefaultValue("")
+ "buryDeepView".setDefaultValue("")
+ "bottomPipeDiameterView".setDefaultValue("")
+ "bottomPointDeepView".setDefaultValue("")
+ "areaView".setDefaultValue("")
+ "lineView".setDefaultValue("")
+ "roadView".setDefaultValue("")
+ "ownerView".setDefaultValue("")
+ "identifierDeepView".setDefaultValue("")
+ "personDeptView".setDefaultValue("")
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ soundPool.autoPause()
+ locationTool.stopLocation()
+ 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 1dac658..f949269 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,31 +1,25 @@
package com.casic.detector.common.view
-import android.app.DatePickerDialog
-import android.app.Dialog
+import android.content.ComponentName
import android.content.Context
-import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
-import android.hardware.Sensor
-import android.hardware.SensorEvent
-import android.hardware.SensorEventListener
-import android.hardware.SensorManager
import android.media.AudioAttributes
import android.media.SoundPool
import android.os.Bundle
-import android.os.CountDownTimer
+import android.os.IBinder
import android.util.Log
import android.view.KeyEvent
import android.view.View
-import android.widget.AdapterView
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.amap.api.location.AMapLocation
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
-import com.amap.api.maps.AMapUtils
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.CoordinateConverter
import com.amap.api.maps.model.BitmapDescriptorFactory
@@ -34,38 +28,29 @@
import com.amap.api.maps.model.MarkerOptions
import com.amap.api.maps.model.MyLocationStyle
import com.casic.detector.common.R
-import com.casic.detector.common.adapter.EditableImageAdapter
-import com.casic.detector.common.base.SerialPortActivity
+import com.casic.detector.common.base.BaseApplication
import com.casic.detector.common.bean.MarkerLocalBean
import com.casic.detector.common.bean.TaskLocalBean
import com.casic.detector.common.callback.OnGetLocationListener
-import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
import com.casic.detector.common.cluster.ClusterItem
import com.casic.detector.common.cluster.ClusterOverlay
import com.casic.detector.common.cluster.RegionItem
import com.casic.detector.common.databinding.ActivityMainBinding
-import com.casic.detector.common.databinding.DialogInstallMarkerBinding
-import com.casic.detector.common.databinding.DialogSearchMarkerNewBinding
import com.casic.detector.common.extensions.appendDownloadUrl
-import com.casic.detector.common.extensions.compressImage
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.getDefaultValue
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.setDefaultValue
-import com.casic.detector.common.extensions.show
-import com.casic.detector.common.extensions.toColor
import com.casic.detector.common.extensions.toHex
-import com.casic.detector.common.extensions.toObjectType
import com.casic.detector.common.model.TaskDetailLocalModel
import com.casic.detector.common.model.TaskModel
+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.GpioManager
import com.casic.detector.common.utils.LocaleConstant
import com.casic.detector.common.utils.LocationTool
import com.casic.detector.common.utils.NtripAuthorizationCreator
@@ -77,26 +62,15 @@
import com.casic.detector.common.vm.TaskViewModel
import com.casic.detector.common.widgets.MarkerDetailDialog
import com.casic.detector.common.widgets.QueryMarkerDialog
-import com.casic.detector.common.widgets.RadarScanView
import com.casic.detector.common.widgets.SamplePopupWindow
-import com.luck.picture.lib.basic.PictureSelector
-import com.luck.picture.lib.config.SelectMimeType
-import com.luck.picture.lib.entity.LocalMedia
-import com.luck.picture.lib.interfaces.OnResultCallbackListener
-import com.pengxh.kt.lite.extensions.appendZero
-import com.pengxh.kt.lite.extensions.binding
-import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertDrawable
import com.pengxh.kt.lite.extensions.createDownloadFileDir
-import com.pengxh.kt.lite.extensions.dateToTimestamp
import com.pengxh.kt.lite.extensions.dp2px
-import com.pengxh.kt.lite.extensions.getSystemService
-import com.pengxh.kt.lite.extensions.initDialogLayoutParams
import com.pengxh.kt.lite.extensions.isNetworkConnected
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.extensions.timestampToCompleteDate
-import com.pengxh.kt.lite.extensions.timestampToTime
import com.pengxh.kt.lite.extensions.toJson
import com.pengxh.kt.lite.utils.FileDownloadManager
import com.pengxh.kt.lite.utils.LoadState
@@ -108,60 +82,41 @@
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
import io.netty.buffer.Unpooled
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
+import java.io.OutputStream
import java.nio.charset.StandardCharsets
-import java.util.Calendar
-import java.util.Date
import java.util.Timer
import java.util.TimerTask
-import kotlin.math.atan2
-class MainActivity : SerialPortActivity(), SensorEventListener,
- OnSocketConnectListener {
+class MainActivity : KotlinBaseActivity(), OnSocketConnectListener {
private val kTag = "MainActivity"
private val context = this
private val samplePopupWindow by lazy { SamplePopupWindow(this) }
private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) }
private val backDrawables by lazy { HashMap() }
- private val installDialog by lazy { InstallMarkerDialog(this) }
- private val searchNewDialog by lazy { SearchMarkerNewDialog(this) }
private val detailDialog by lazy { MarkerDetailDialog(this) }
private val locationTool by lazy { LocationTool(this) }
- private val rotationMatrix = FloatArray(9)//旋转矩阵缓存
- private val valueArray = FloatArray(3)//方位角数值
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
private var clickTime: Long = 0
private var markers = ArrayList()
private var clusterOverlay: ClusterOverlay? = null
private var isFreeTask = false
private var freeTaskTitle = ""
private var ids = HashSet()
- private var signalTask: TimerTask? = null
- private var energyTask: TimerTask? = null
- private var searchMarkerTimer: Timer? = null
private var freeTaskId: String? = null
- private var gravity: FloatArray? = null
- private var geomagnetic: FloatArray? = null
private var connectState = ConnectState.CLOSED
private var socketClient: SocketClient? = null
- private lateinit var aMap: AMap
- private lateinit var sensorManager: SensorManager
-
- /***inner class 需要用到*****start*/
- private val gpioManager by lazy { GpioManager() }
- private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
- private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
- .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
- private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var serialPortService: SerialPortService? = null
+ private var searchMarkerTimer: Timer? = null
private var soundResourceId = 0
- private var slowSoundResourceId = 0
- private var fastSoundResourceId = 0
private var isExecuteTask = false
-
- /***inner class 需要用到*****end*/
+ private lateinit var aMap: AMap
override fun initViewBinding(): ActivityMainBinding {
return ActivityMainBinding.inflate(layoutInflater)
@@ -171,10 +126,26 @@
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)
+ }
+
soundResourceId = soundPool.load(this, R.raw.ring3, 1)
- slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
- fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)
RtkLocationTool.getCurrentLocation(this) {
if (connectState == ConnectState.SUCCESS) {
@@ -192,8 +163,6 @@
samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES)
samplePopupWindow.setBackgroundDrawable(null)
- sensorManager = getSystemService()!!
-
//task网络请求监听
taskViewModel.markerFileResult.observe(this) {
if (it.isSuccess) {
@@ -316,9 +285,6 @@
//安装。上传,然后存入本地库
binding.installButton.setOnClickListener {
- /**
- * 改为Dialog方式,避免频繁打开/关闭串口
- * */
if (isFreeTask) {
AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示")
.setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能")
@@ -329,7 +295,7 @@
}
}).build().show()
} else {
- installDialog.show()
+ navigatePageTo()
}
}
@@ -449,8 +415,6 @@
//探测
binding.detectionButton.setOnClickListener {
/**
- * 改为Dialog方式,避免频繁打开/关闭串口
- *
* 如果开启自由巡检就不让探测
* */
if (isFreeTask) {
@@ -463,7 +427,12 @@
}
}).build().show()
} else {
- searchNewDialog.show()
+ val flag = if (isExecuteTask) {
+ "1"
+ } else {
+ "0"
+ }
+ navigatePageTo(flag)
}
}
@@ -476,14 +445,8 @@
override fun onConfirmClick() {
isFreeTask = false
soundPool.autoPause()
-
- //停止信号和ID搜索定时器
- signalTask?.cancel()
- energyTask?.cancel()
searchMarkerTimer?.cancel()
-
- //降低串口电位
- gpioManager.setGpioLow("18")
+ serialPortService?.closeSerialPort()
binding.stopFreeTaskButton.visibility = View.GONE
if (freeTaskId.isNullOrBlank()) {
@@ -527,110 +490,79 @@
}
private fun openSerialPort() {
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- isFreeTask = true
- //自由巡检
- signalTask = object : TimerTask() {
- override fun run() {
- out.write('2'.code)
- out.flush()
- }
- }
-
- energyTask = object : TimerTask() {
- override fun run() {
- out.write('6'.code)
- out.flush()
- }
- }
-
- searchMarkerTimer = Timer()
- searchMarkerTimer?.apply {
- schedule(signalTask, 0, 200)
- schedule(energyTask, 0, 251)
- }
-
binding.stopFreeTaskButton.visibility = View.VISIBLE
- }
+ isFreeTask = true
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ searchMarkerTimer = Timer()
+ searchMarkerTimer?.schedule(object : TimerTask() {
+ override fun run() {
+ outStream.write('2'.code)
+ outStream.flush()
- override fun onDataReceived(buffer: ByteArray) {
- val hex = buffer.toHex()
-// Log.d(kTag, "$kTag => $hex")
- if (searchNewDialog.isDetectMarker) {
- searchNewDialog.bindingValue(hex)
- } else if (installDialog.isReadMarker) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- installDialog.bindingValue(markerId)
+ Thread.sleep(50)
+
+ outStream.write('6'.code)
+ outStream.flush()
+ }
+ }, 0, 200)
}
- } else if (isFreeTask) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- //只响一次,因为探测频率高,所以依旧是连续的报警声
- soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
- //添加地图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))
- )
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ if (hex.startsWith("4E")) {
+ //只响一次,因为探测频率高,所以依旧是连续的报警声
+ soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
+
+ 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()
}
}
- 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()
+ 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 (hex.startsWith("4E")) {
- val energyResponse = hex.take(10).hexToString()
- try {
- val energy = energyResponse.substring(1).toInt()
- if (energy <= 500 && detailDialog.isShowing) {
- detailDialog.dismiss()
- }
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- }
- }
+ })
}
override fun observeRequestState() {
taskViewModel.loadState.observe(this) {
when (it) {
- LoadState.Loading -> {
- if (installDialog.isInstallMarker) {
- LoadingDialogHub.show(this, "标识器安装中,请稍后...")
- } else {
- LoadingDialogHub.show(this, "提交工单中,请稍后")
- }
- }
-
- LoadState.Success -> {
- if (installDialog.isInstallMarker) {
- installDialog.clearDefaultData()
- installDialog.dismiss()
- "${installDialog.markerId}安装成功".show(this)
- }
- LoadingDialogHub.dismiss()
- }
+ LoadState.Loading -> LoadingDialogHub.show(this, "提交工单中,请稍后")
else -> LoadingDialogHub.dismiss()
}
@@ -939,32 +871,6 @@
} else super.onKeyDown(keyCode, event)
}
- override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
- //精度发生变化时触发
- }
-
- override fun onSensorChanged(event: SensorEvent?) {
- //值发生变化时触发
- val type = event?.sensor?.type
-
- if (type == Sensor.TYPE_ACCELEROMETER) {
- gravity = event.values
- } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
- geomagnetic = event.values
- }
-
- if (gravity == null || geomagnetic == null) {
- return
- }
-
- if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
- SensorManager.getOrientation(rotationMatrix, valueArray)
-
- val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt()
- searchNewDialog.updateDegreeValue(degree)
- }
- }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
@@ -978,14 +884,6 @@
showLabelsOnMap()
}
- //注册加速度传感器监听
- val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
- sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)
-
- //注册磁场传感器监听
- val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
- sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL)
-
//取缓存
val remoteHost = SaveKeyValues.getValue(
LocaleConstant.RTK_SERVER, "203.107.45.154"
@@ -995,20 +893,20 @@
) as String
//连接千寻RTK服务器
- lifecycleScope.launch(Dispatchers.IO) {
- if (socketClient != null) {
- socketClient?.disconnect()
- delay(3000)
- }
-
- socketClient = SocketClient.Builder()
- .setHostname(remoteHost)
- .setPort(remotePort.toInt())
- .setTimeout(5000)
- .setOnSocketListener(this@MainActivity)
- .build()
- socketClient?.connect()
- }
+// lifecycleScope.launch(Dispatchers.IO) {
+// if (socketClient != null) {
+// socketClient?.disconnect()
+// delay(3000)
+// }
+//
+// socketClient = SocketClient.Builder()
+// .setHostname(remoteHost)
+// .setPort(remotePort.toInt())
+// .setTimeout(5000)
+// .setOnSocketListener(this@MainActivity)
+// .build()
+// socketClient?.connect()
+// }
}
override fun onMessageResponse(data: ByteArray) {
@@ -1021,12 +919,12 @@
val result = String(data, StandardCharsets.UTF_8)
Log.d(kTag, "onMessageResponse: $result")
if (result.contains("ICY 200 OK")) {
- "高精度定位服务器连接成功".show(this)
+ "高精度定位服务连接成功".show(this)
}
} else {
"收到千寻数据返回,长度:${data.size}".show(this)
- out.write(data)
- out.flush()
+// out.write(data)
+// out.flush()
}
}
@@ -1061,7 +959,6 @@
override fun onPause() {
super.onPause()
binding.mapView.onPause()
- sensorManager.unregisterListener(this)
}
override fun onSaveInstanceState(outState: Bundle) {
@@ -1072,794 +969,11 @@
override fun onDestroy() {
super.onDestroy()
binding.mapView.onDestroy()
- soundPool.release()
+ soundPool.autoPause()
+ searchMarkerTimer?.cancel()
+ serialPortService?.closeSerialPort()
locationTool.stopLocation()
- //降低串口电位
- gpioManager.setGpioLow("18")
+ unbindService(serviceConnection)
+ BaseApplication.get().closeSerialPort()
}
-
- /**安装标识器对话框******************************************************************************/
- inner class InstallMarkerDialog(private val context: Context) : Dialog(context) {
-
- private val binding: DialogInstallMarkerBinding by binding()
- private val calendar by lazy { Calendar.getInstance() }
- private val realPaths = ArrayList() //真实图片路径
- private lateinit var imageAdapter: EditableImageAdapter
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
-
- var isReadMarker = false
- var isInstallMarker = false
- var markerId = ""
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
-
- //初始化数据
- initDefaultData()
-
- //返回
- binding.titleInclude.leftBackView.setOnClickListener {
- soundPool.autoPause()
- dismiss()
- }
-
- binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
- object : AdapterView.OnItemSelectedListener {
- override fun onItemSelected(
- parent: AdapterView<*>?, view: View?, position: Int, id: Long
- ) {
- when (position) {
- 0 -> {
- //显示管线属性
- binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 1 -> {
- //显示管线附属物属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 2 -> {
- //显示管线特征点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 3 -> {
- //显示交叉穿越点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility =
- View.VISIBLE
- }
- }
- }
-
- override fun onNothingSelected(parent: AdapterView<*>?) {
-
- }
- }
-
- //安装
- binding.installButton.setOnClickListener {
- val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
- if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
- when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
- "管线" -> "请输入管线种类!".show(context)
- "管线附属物" -> "请输入附属物名称!".show(context)
- "管线特征管点" -> "请输入特征管点!".show(context)
- "交叉穿越点" -> "请输入上层管种类!".show(context)
- }
- return@setOnClickListener
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
- if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
- "请输入管径".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
- "请输入埋深".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
- if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
- "请输入下层管管径".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.areaView.text.isNullOrBlank()) {
- "请输入所属区域".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.lineView.text.isNullOrBlank()) {
- "请输入所属线路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.roadView.text.isNullOrBlank()) {
- "请输入所属道路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
- "请选择建设年代".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
- "请输入权属单位".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
- "请先读取标识器获取ID".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
- "请输入标识器埋深".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
- "请输入标识器安装部门".show(context)
- return@setOnClickListener
- }
-
- //先存本地再上传服务器
- saveMarkerInLocal()
-
- isInstallMarker = true
- taskViewModel.installLabel(
- context,
- companyId,
- binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
- "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
- binding.objectInclude.areaView.text.toString(),
- binding.objectInclude.lineView.text.toString(),
- binding.objectInclude.roadView.text.toString(),
- binding.objectInclude.constructDateView.text.toString(),
- binding.objectInclude.ownerView.text.toString(),
- objectId,
- binding.identifierInclude.identifierIdView.text.toString(),
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
- "${binding.identifierInclude.identifierDeepView.text}mm",
- binding.identifierInclude.personDeptView.text.toString(),
- binding.identifierInclude.installTimeView.text.toString(),
- binding.identifierInclude.lngView.text.toString(),
- binding.identifierInclude.latView.text.toString(),
- binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
- binding.remarkView.text.toString(),
- realPaths
- )
-
- //保存默认值
- "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
- "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
- "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
- "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
- "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
- "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
- "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
- "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
- "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
- "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
- "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
- }
-
- //读标识器
- binding.readMarkerButton.setOnClickListener {
- LoadingDialogHub.show(this@MainActivity, "标识器读取中,请稍后...")
- binding.readMarkerButton.isEnabled = false
-
- isReadMarker = true
-
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
-
- out.write('2'.code)
- out.flush()
-
- countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- "读取此标识器ID超时,请退出应用再试".show(context)
- }
- }
- countDownTimer.start()
- }
- }
-
- override fun show() {
- super.show()
- locationTool = LocationTool(context)
- locationTool.getCurrentLocation(true, object : OnGetLocationListener {
- override fun onAMapLocationGet(location: AMapLocation?) {
- if (location != null) {
- binding.identifierInclude.lngView.text = location.longitude.toString()
- binding.identifierInclude.latView.text = location.latitude.toString()
- } else {
- "当前位置信号差,无法获取定位".show(context)
- }
- }
- })
- }
-
- fun bindingValue(markerId: String) {
- this.markerId = markerId
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- countDownTimer.cancel()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- binding.identifierInclude.identifierIdView.text = markerId
- }
-
- override fun dismiss() {
- //降低串口电位
- gpioManager.setGpioLow("18")
- soundPool.autoPause()
- isInstallMarker = false
- locationTool.stopLocation()
- super.dismiss()
- }
-
- private fun initDefaultData() {
- binding.titleInclude.titleView.text = "安装新标识器"
- binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
-
- imageAdapter = EditableImageAdapter(context, 3, 3)
- binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
-
- //设置默认值
- binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
- binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
- binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
- binding.objectInclude.areaView.setText("areaView".getDefaultValue())
- binding.objectInclude.lineView.setText("lineView".getDefaultValue())
- binding.objectInclude.roadView.setText("roadView".getDefaultValue())
- binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
- binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
- binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
-
- /**************************************************************************************/
- binding.objectInclude.objectTypeSpinner.show(
- this@MainActivity, LocaleConstant.POINT_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.materialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeAttachInclude.attachSpinner.show(
- this@MainActivity, LocaleConstant.ATTACH_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
- this@MainActivity, LocaleConstant.FEATURE_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.buryTypeSpinner.show(
- this@MainActivity, LocaleConstant.BURY_METHOD_ARRAY, 0
- )
-
- binding.objectInclude.constructDateView.setOnClickListener {
- val datePicker = DatePickerDialog(
- context,
- null,
- calendar.get(Calendar.YEAR),
- calendar.get(Calendar.MONTH),
- calendar.get(Calendar.DAY_OF_MONTH)
- )
- datePicker.show()
-
- datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
- val year = datePicker.datePicker.year
- val month = datePicker.datePicker.month + 1
- val day = datePicker.datePicker.dayOfMonth
- val selectedDate = String.format(
- "%s-%s-%s", year, month.appendZero(), day.appendZero()
- )
-
- //当前时间
- val current = System.currentTimeMillis().timestampToTime()
- val today = "$selectedDate $current".dateToTimestamp()
- if (Date(today).after(Date())) {
- "建设年代不能早于当前日期".show(context)
- } else {
- datePicker.dismiss()
- binding.objectInclude.constructDateView.text = selectedDate
- }
- }
- }
-
- binding.identifierInclude.identifierTypeSpinner.show(
- this@MainActivity, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
- )
-
- binding.identifierInclude.installTimeView.text =
- System.currentTimeMillis().timestampToCompleteDate()
-
- binding.identifierInclude.colorSpinner.show(
- this@MainActivity, LocaleConstant.COLOR_ARRAY, 0
- )
-
- imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
- override fun onAddImageClick() {
- takePicture()
- }
-
- override fun onItemClick(position: Int) {
- if (realPaths[position].isEmpty()) {
- "图片加载失败,无法查看大图".show(context)
- } else {
- context.navigatePageTo(position, realPaths)
- }
- }
-
- override fun onItemLongClick(view: View?, position: Int) {
- imageAdapter.deleteImage(position)
- }
- })
- /**************************************************************************************/
- }
-
- //清除默认数据
- fun clearDefaultData() {
- "markerObjectTypeView".setDefaultValue("")
- "pipelineDiameterView".setDefaultValue("")
- "buryDeepView".setDefaultValue("")
- "bottomPipeDiameterView".setDefaultValue("")
- "bottomPointDeepView".setDefaultValue("")
- "areaView".setDefaultValue("")
- "lineView".setDefaultValue("")
- "roadView".setDefaultValue("")
- "ownerView".setDefaultValue("")
- "identifierDeepView".setDefaultValue("")
- "personDeptView".setDefaultValue("")
- }
-
- private fun saveMarkerInLocal() {
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
-
- val marker = MarkerLocalBean()
- marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
- marker.pipelineType =
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
- marker.pipelineMaterial =
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
- marker.pipelineDiameter =
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
- marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
- marker.underlyingPipelineType =
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
- marker.underlyingPipelineMaterial =
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
- marker.underlyingPipelineDiameter =
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
- marker.underlyingPipelineDepth =
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
- marker.buryMethod =
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
- marker.area = binding.objectInclude.areaView.text.toString()
- marker.line = binding.objectInclude.lineView.text.toString()
- marker.road = binding.objectInclude.roadView.text.toString()
- marker.constructTime = binding.objectInclude.constructDateView.text.toString()
- marker.owner = binding.objectInclude.ownerView.text.toString()
- marker.objectId = objectId
- marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
- marker.markerType =
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
- marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
- marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
- marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
- marker.lng = binding.identifierInclude.lngView.text.toString()
- marker.lat = binding.identifierInclude.latView.text.toString()
- marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
- marker.remark = binding.remarkView.text.toString()
- marker.imagePath = realPaths.toJson()
-
- DataBaseManager.get.saveMarkerInLocale(marker)
- }
-
- private fun takePicture() {
- PictureSelector.create(this@MainActivity).openCamera(SelectMimeType.ofImage())
- .forResult(object : OnResultCallbackListener {
- override fun onResult(result: java.util.ArrayList?) {
- if (result == null) {
- "拍照失败,请重试".show(context)
- return
- }
- analyticalSelectResults(result[0])
- }
-
- override fun onCancel() {
-
- }
- })
- }
-
- private fun analyticalSelectResults(result: LocalMedia) {
- //压缩图片
- result.realPath.compressImage(context, object : OnImageCompressListener {
- override fun onSuccess(file: File) {
- realPaths.add(file.absolutePath)
- imageAdapter.setupImage(realPaths)
- }
-
- override fun onError(e: Throwable) {
- e.printStackTrace()
- }
- })
- }
- }
-
- /**探测标识器新对话框****************************************************************************/
- inner class SearchMarkerNewDialog(private val context: Context) : Dialog(context) {
-
- private val taskId by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
- }
- private val taskCode by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_CODE, "") as String
- }
- private val markerPoints by lazy { ArrayList() }
- private val binding: DialogSearchMarkerNewBinding by binding()
- private var markerId = ""//实际探测出来的标识器ID
- private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID
- private lateinit var searchMarkerTimer: Timer
- private lateinit var signalTask: TimerTask
- private lateinit var energyTask: TimerTask
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
- var isDetectMarker = false
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
- binding.depthButton.setOnClickListener {
- signalTask.cancel()
- energyTask.cancel()
- searchMarkerTimer.cancel()
-
- out.write('3'.code)
- val result = DataBaseManager.get.queryMarkerById(markerId)
- if (result.isNotEmpty()) {
- val tag = when (result.first().markerType) {
- "EM30" -> '7'
- "EM50" -> '8'
- "EM14" -> '9'
- else -> '1'
- }
- if (tag == '1') {
- "此标识器无法读取埋深!".show(context)
- initTimer()
- } else {
- // 发送读取标识器埋设深度指令
- LoadingDialogHub.show(this@MainActivity, "正在测距,请稍后...")
- out.write(tag.code)
- out.flush()
- countDownTimer = object : CountDownTimer(15 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- "探测此标识器深度超时,请重试".show(context)
- initTimer()
- }
- }
- countDownTimer.start()
- }
- } else {
- "标识器未安装,安装成功后才可读取埋深!".show(context)
- initTimer()
- }
- }
-
- binding.markerInfoButton.setOnClickListener {
- val id = if (markerId == "") {
- nearestMarkerId
- } else {
- markerId
- }
- //查库
- val result = DataBaseManager.get.queryMarkerById(id)
- if (result.isNotEmpty()) {
- context.navigatePageTo(result.first().toJson())
- } else {
- context.navigatePageTo(id)
- }
- //查看完就把ID置空,便于下次查看最新的ID
- markerId = ""
- }
- }
-
- override fun show() {
- super.show()
- locationTool = LocationTool(context)
- //点位渲染,每次定位都计算当前位置与符合条件的点距离
- locationTool.getCurrentLocation(false, object : OnGetLocationListener {
- override fun onAMapLocationGet(location: AMapLocation?) {
- location?.apply {
- renderDataPoint(this)
- }
- }
- })
- }
-
- /**
- * 计算并渲染数据点。点太多采用协程计算,不然会有点卡顿
- * @param location 定位点(RTK获取)
- * */
- private fun renderDataPoint(location: AMapLocation) {
- val longitude = location.longitude
- val latitude = location.latitude
- lifecycleScope.launch(Dispatchers.IO) {
- val dataPoints = ArrayList()
- DataBaseManager.get.loadMarkers().forEach {
- val distance = AMapUtils.calculateLineDistance(
- LatLng(it.lat.toDouble(), it.lng.toDouble()), LatLng(latitude, longitude)
- )
- val formatDistance = "%.2f".format(distance).toFloat()
-
- markerPoints.add(MarkerDistanceData(it.markerId, formatDistance))
-
- if (formatDistance <= LocaleConstant.MAX_DISTANCE) {
- val angle = atan2(
- (it.lat.toDouble() - latitude), (it.lng.toDouble() - longitude)
- ) + Math.PI
- val formatAngle = "%.2f".format(angle).toDouble()
- dataPoints.add(
- RadarScanView.DataPoint(formatAngle, formatDistance)
- )
- }
- }
- withContext(Dispatchers.Main) {
- binding.radarScanView.renderPointData(dataPoints,
- object : RadarScanView.OnGetNearestPointCallback {
- override fun getNearestPoint(point: RadarScanView.DataPoint?) {
- if (point == null) {
- binding.distanceValueView.text = "大于5.5m"
- binding.distancePgBar.progress = 100
- } else {
- binding.distanceValueView.text = "${point.distance}m"
- val progress =
- if (point.distance > LocaleConstant.MAX_DISTANCE) {
- 100
- } else {
- (point.distance / LocaleConstant.MAX_DISTANCE) * 100
- }
- binding.distancePgBar.progress = progress.toInt()
- }
- }
- })
- }
- }
- }
-
- override fun onStart() {
- super.onStart()
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- initTimer()
-
- isDetectMarker = true
-
- if (isExecuteTask) {
- binding.taskStateView.visibility = View.GONE
- binding.taskStateView.isSelected = false
- } else {
- binding.taskStateView.visibility = View.VISIBLE
- binding.taskStateView.isSelected = true
- }
- }
-
- fun bindingValue(hex: String) {
- if (hex.startsWith("4E")) {
- try {
- //4E转为String为N,代表能量值
- //用能量值转动表盘
- val energyResponse = hex.take(10).hexToString()
- val energy = energyResponse.substring(1).toInt()
- if (energy >= 4000) {
- soundPool.play(fastSoundResourceId, 1f, 1f, 0, 0, 1f)
- } else {
- soundPool.play(slowSoundResourceId, 1f, 1f, 0, 0, 1f)
- }
-
- //通过设置进度条表示能量值
- binding.energyPgBar.progress = energy
- binding.energyValueView.text = "${energy}dB"
-
- if (energy <= 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.searchResultView.text = "未检测到标识器"
- binding.searchResultView.setTextColor(Color.parseColor("#8D1717"))
- binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_red)
- } else if (energy >= 4100) {
- binding.energyTipsView.text = "信号极强,接近标识器正上方"
- binding.energyTipsView.setTextColor(Color.parseColor("#428d00"))
- binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green)
-
- if (markerPoints.isEmpty()) {
- Log.d(kTag, "bindingValue: markerPoints.isEmpty()")
- return
- }
-
- //需要转一下,不然会有并发问题
- val temp = ArrayList()
- temp.addAll(markerPoints)
- temp.sortBy(MarkerDistanceData::distance)
- val nearestPoint = temp.first()
- nearestMarkerId = nearestPoint.markerId
- handleMarker(nearestMarkerId)
- } else {
- binding.energyTipsView.text = "已靠近,请继续移动位置"
- binding.energyTipsView.setTextColor(Color.parseColor("#8C5700"))
- binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow)
- }
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- } else if (hex.startsWith("53")) {
- LoadingDialogHub.dismiss()
- countDownTimer.cancel()
- try {
- val depthResponse = hex.take(10).hexToString()
- val depth = depthResponse.drop(2).toInt()
- AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示")
- .setMessage("标识器埋深:${depth}厘米").setPositiveButton("知道了")
- .setOnDialogButtonClickListener(object :
- AlertMessageDialog.OnDialogButtonClickListener {
- override fun onConfirmClick() {
- initTimer()
- }
- }).build().show()
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- } else {
- val id = hex.take(20).hexToString()
- if (id.isNumber()) {
- markerId = id
- handleMarker(markerId)
- }
- }
- }
-
- private fun handleMarker(id: String) {
- binding.depthButton.isEnabled = true
- binding.depthButton.setTextColor(Color.WHITE)
- binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
- binding.markerInfoButton.isEnabled = true
- binding.markerInfoButton.setTextColor(Color.WHITE)
- binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)
-
- binding.searchResultView.text = "已检测到标识器"
- binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
- binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)
-
- //自动上传标识器
- if (isExecuteTask) {
- val taskMarkerLocalBean = DataBaseManager.get.queryTaskMarkerById(
- taskId, taskCode, id, "0"
- )
- taskMarkerLocalBean?.apply {
- taskViewModel.uploadMarker(context, this)
- }
- }
- }
-
- //更新罗盘角度
- fun updateDegreeValue(degree: Int) {
- binding.radarScanView.setDegreeValue(degree)
- }
-
- private fun initTimer() {
- searchMarkerTimer = Timer()
-
- signalTask = object : TimerTask() {
- override fun run() {
- out.write('2'.code)
- out.flush()
- }
- }
-
- energyTask = object : TimerTask() {
- override fun run() {
- out.write('6'.code)
- out.flush()
- }
- }
-
- //错开信号和能量定时器
- searchMarkerTimer.schedule(signalTask, 0, 201)
- searchMarkerTimer.schedule(energyTask, 0, 251)
- }
-
- override fun dismiss() {
- signalTask.cancel()
- energyTask.cancel()
- searchMarkerTimer.cancel()
- //降低串口电位
- gpioManager.setGpioLow("18")
- isDetectMarker = false
- soundPool.autoPause()
- locationTool.stopLocation()
- super.dismiss()
- }
- }
-
- /**
- * 标识器与当前定位的数据
- * */
- data class MarkerDistanceData(var markerId: String, var distance: Float)
}
\ 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
new file mode 100644
index 0000000..14fe667
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/view/SearchMarkerActivity.kt
@@ -0,0 +1,462 @@
+package com.casic.detector.common.view
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.graphics.Color
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import android.media.AudioAttributes
+import android.media.SoundPool
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.IBinder
+import android.util.Log
+import android.view.View
+import android.view.WindowManager
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMapUtils
+import com.amap.api.maps.model.LatLng
+import com.casic.detector.common.R
+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.hexToString
+import com.casic.detector.common.extensions.isNumber
+import com.casic.detector.common.extensions.toHex
+import com.casic.detector.common.model.MarkerDistanceData
+import com.casic.detector.common.service.SerialPortService
+import com.casic.detector.common.utils.DataBaseManager
+import com.casic.detector.common.utils.LocaleConstant
+import com.casic.detector.common.utils.LocationTool
+import com.casic.detector.common.vm.TaskViewModel
+import com.casic.detector.common.widgets.RadarScanView
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.Constant
+import com.pengxh.kt.lite.utils.LoadingDialogHub
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.OutputStream
+import java.util.Timer
+import java.util.TimerTask
+import kotlin.math.atan2
+
+class SearchMarkerActivity : KotlinBaseActivity(),
+ SensorEventListener {
+
+ private val kTag = "SearchMarkerActivity"
+ private val context = this
+ private val locationTool by lazy { LocationTool(this) }
+ private val markerPoints by lazy { ArrayList() }
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val sensorManager by lazy { getSystemService()!! }
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private val rotationMatrix = FloatArray(9)//旋转矩阵缓存
+ private val valueArray = FloatArray(3)//方位角数值
+ private var slowSoundResourceId = 0
+ private var fastSoundResourceId = 0
+ private var markerId = ""//实际探测出来的标识器ID
+ private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID
+ private var isExecuteTask = false
+ private var signalEnergy = 0 //标识器信号强度
+ 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 {
+ override fun onServiceConnected(name: ComponentName?, iBinder: IBinder?) {
+ if (iBinder is SerialPortService.ServiceBinder) {
+ serialPortService = iBinder.getSerialPortService()
+ Log.d(kTag, "onServiceConnected: 服务已绑定")
+ searchMarker()
+ }
+ }
+
+ override fun onServiceDisconnected(name: ComponentName?) {
+
+ }
+ }
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ val flag = intent.getStringExtra(Constant.INTENT_PARAM) as String
+ isExecuteTask = flag != "0"
+
+ //绑定串口通信服务
+ Intent(this, SerialPortService::class.java).also {
+ bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
+ }
+
+ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
+ fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)
+
+ //点位渲染,每次定位都计算当前位置与符合条件的点距离
+ locationTool.getCurrentLocation(false, object : OnGetLocationListener {
+ override fun onAMapLocationGet(location: AMapLocation?) {
+ location?.apply {
+ renderDataPoint(this)
+ }
+ }
+ })
+
+ if (isExecuteTask) {
+ binding.taskStateView.visibility = View.GONE
+ binding.taskStateView.isSelected = false
+ } else {
+ binding.taskStateView.visibility = View.VISIBLE
+ binding.taskStateView.isSelected = true
+ }
+
+ //在标识器信号强度很强的时候,从数据库中计算出距离最近的点,以防出现探测不到ID的情况
+ searchSignalEnergyTimer = Timer()
+ searchSignalEnergyTimer.schedule(object : TimerTask() {
+ override fun run() {
+ //markerId为空,说明没有通过探测得到标识器ID,那么就需要通过计算得到近似的标识器
+ if (signalEnergy >= 4100 && markerPoints.isNotEmpty()) {
+ try {
+ //需要转一下,不然会有并发问题
+ val temp = ArrayList()
+ temp.addAll(markerPoints)
+ temp.sortBy(MarkerDistanceData::distance)
+ val nearestPoint = temp.first()
+ nearestMarkerId = nearestPoint.markerId
+ runOnUiThread {
+ handleMarker(nearestMarkerId)
+ }
+ markerPoints.clear()
+ } catch (e: NullPointerException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }, 0, 2000)
+ }
+
+ private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
+ override fun onTick(millisUntilFinished: Long) {
+
+ }
+
+ override fun onFinish() {
+ LoadingDialogHub.dismiss()
+ serialPortService?.closeSerialPort()
+ "标识器深度探测超时,请移动位置重试".show(context)
+ searchMarker()
+ }
+ }
+
+ override fun initEvent() {
+ binding.depthButton.setOnClickListener {
+ stopSearchMarker()
+ val result = DataBaseManager.get.queryMarkerById(markerId)
+ if (result.isNotEmpty()) {
+ val tag = when (result.first().markerType) {
+ "EM30" -> '7'
+ "EM50" -> '8'
+ "EM14" -> '9'
+ else -> '1'
+ }
+ if (tag == '1') {
+ "此标识器无法读取埋深!".show(this)
+ searchMarker()
+ } else {
+ LoadingDialogHub.show(this, "正在探测标识器埋深,请稍后...")
+ countDownTimer.start()
+ // 发送读取标识器埋设深度指令
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ // 发送读取标识器埋设深度指令
+ outStream.write(tag.code)
+ outStream.flush()
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ if (hex.startsWith("53")) {
+ LoadingDialogHub.dismiss()
+ countDownTimer.cancel()
+ try {
+ val depthResponse = hex.take(10).hexToString()
+ val depth = depthResponse.drop(2).toInt()
+ AlertMessageDialog.Builder().setContext(context)
+ .setTitle("温馨提示")
+ .setMessage("标识器埋深:${depth}厘米")
+ .setPositiveButton("知道了")
+ .setOnDialogButtonClickListener(object :
+ AlertMessageDialog.OnDialogButtonClickListener {
+ override fun onConfirmClick() {
+ serialPortService?.closeSerialPort()
+ searchMarker()
+ }
+ }).build().show()
+ } catch (e: WindowManager.BadTokenException) {
+ e.printStackTrace()
+ } catch (e: NumberFormatException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ })
+ }
+ } else {
+ LoadingDialogHub.dismiss()
+ "标识器未安装,安装成功后才可读取埋深!".show(this)
+ searchMarker()
+ }
+ }
+
+ binding.markerInfoButton.setOnClickListener {
+ val id = if (markerId == "") {
+ nearestMarkerId
+ } else {
+ markerId
+ }
+ //查库
+ val result = DataBaseManager.get.queryMarkerById(id)
+ if (result.isNotEmpty()) {
+ navigatePageTo(result.first().toJson())
+ } else {
+ navigatePageTo(id)
+ }
+ //查看完就把ID置空,便于下次查看最新的ID
+ markerId = ""
+ }
+ }
+
+ /**
+ * 搜索标识器
+ * */
+ private fun searchMarker() {
+ Thread.sleep(100)
+
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ searchMarkerTimer = Timer()
+ searchMarkerTimer.schedule(object : TimerTask() {
+ override fun run() {
+ outStream.write('2'.code)
+ outStream.flush()
+
+ Thread.sleep(50)
+
+ outStream.write('6'.code)
+ outStream.flush()
+ }
+ }, 0, 200)
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ 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)
+ }
+
+ //通过设置进度条表示能量值
+ 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)
+
+ 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()
+ }
+ } else {
+ val id = hex.take(20).hexToString()
+ if (id.isNumber()) {
+ markerId = id
+ handleMarker(markerId)
+ }
+ }
+ }
+ })
+ }
+
+ private fun stopSearchMarker() {
+ soundPool.autoPause()
+ searchMarkerTimer.cancel()
+ serialPortService?.closeSerialPort()
+
+ Thread.sleep(100)
+ }
+
+ /**
+ * 计算并渲染数据点。点太多采用协程计算,不然会有点卡顿。默认2s计算一次
+ * @param location 定位点(RTK获取)
+ * */
+ private fun renderDataPoint(location: AMapLocation) {
+ val longitude = location.longitude
+ val latitude = location.latitude
+ lifecycleScope.launch(Dispatchers.IO) {
+ val dataPoints = ArrayList()
+ DataBaseManager.get.loadMarkers().forEach {
+ val distance = AMapUtils.calculateLineDistance(
+ LatLng(it.lat.toDouble(), it.lng.toDouble()), LatLng(latitude, longitude)
+ )
+ val formatDistance = "%.2f".format(distance).toFloat()
+ markerPoints.add(MarkerDistanceData(it.markerId, formatDistance))
+
+ if (formatDistance <= LocaleConstant.MAX_DISTANCE) {
+ val angle = atan2(
+ (it.lat.toDouble() - latitude), (it.lng.toDouble() - longitude)
+ ) + Math.PI
+ val formatAngle = "%.2f".format(angle).toDouble()
+
+ dataPoints.add(RadarScanView.DataPoint(formatAngle, formatDistance))
+ }
+ }
+ withContext(Dispatchers.Main) {
+ binding.radarScanView.renderPointData(dataPoints,
+ object : RadarScanView.OnGetNearestPointCallback {
+ override fun getNearestPoint(point: RadarScanView.DataPoint?) {
+ if (point == null) {
+ binding.distanceValueView.text = "大于5.5m"
+ binding.distancePgBar.progress = 100
+ } else {
+ binding.distanceValueView.text = "${point.distance}m"
+ val progress = if (point.distance > LocaleConstant.MAX_DISTANCE) {
+ 100
+ } else {
+ (point.distance / LocaleConstant.MAX_DISTANCE) * 100
+ }
+ binding.distancePgBar.progress = progress.toInt()
+ }
+ }
+ }
+ )
+ }
+ }
+ }
+
+ override fun initViewBinding(): ActivitySearchMarkerBinding {
+ return ActivitySearchMarkerBinding.inflate(layoutInflater)
+ }
+
+ override fun observeRequestState() {
+
+ }
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ private fun handleMarker(id: String) {
+ binding.depthButton.isEnabled = true
+ binding.depthButton.setTextColor(Color.WHITE)
+ binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
+ binding.markerInfoButton.isEnabled = true
+ binding.markerInfoButton.setTextColor(Color.WHITE)
+ binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)
+
+ binding.searchResultView.text = "已检测到标识器"
+ binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
+ binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)
+
+ //自动上传标识器
+ if (isExecuteTask) {
+ val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
+ val taskCode = SaveKeyValues.getValue(LocaleConstant.TASK_CODE, "") as String
+ val taskMarkerLocalBean = DataBaseManager.get.queryTaskMarkerById(
+ taskId, taskCode, id, "0"
+ )
+ taskMarkerLocalBean?.apply {
+ taskViewModel.uploadMarker(context, this)
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ //注册加速度传感器监听
+ val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
+ sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)
+
+ //注册磁场传感器监听
+ val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
+ sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL)
+ }
+
+ override fun onPause() {
+ super.onPause()
+ sensorManager.unregisterListener(this)
+ }
+
+ override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
+ //精度发生变化时触发
+ }
+
+ override fun onSensorChanged(event: SensorEvent?) {
+ //值发生变化时触发
+ val type = event?.sensor?.type
+
+ if (type == Sensor.TYPE_ACCELEROMETER) {
+ gravity = event.values
+ } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
+ geomagnetic = event.values
+ }
+
+ if (gravity == null || geomagnetic == null) {
+ return
+ }
+
+ if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
+ SensorManager.getOrientation(rotationMatrix, valueArray)
+
+ val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt()
+ //更新罗盘角度
+ binding.radarScanView.setDegreeValue(degree)
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ stopSearchMarker()
+ locationTool.stopLocation()
+ unbindService(serviceConnection)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
index 458f3fb..ca7de13 100644
--- a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
+++ b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
@@ -4,6 +4,7 @@
import com.casic.detector.common.greendao.DaoMaster
import com.casic.detector.common.greendao.DaoSession
import com.casic.detector.common.uart.SerialPort
+import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.SaveKeyValues
import java.io.File
import java.io.IOException
@@ -13,23 +14,12 @@
class BaseApplication : Application() {
private val kTag = "BaseApplication"
- private var serialPorts: ArrayList? = null
+ private var serialPorts = ArrayList()
- @Throws(SecurityException::class, IOException::class, InvalidParameterException::class)
- fun getSerialPorts(): ArrayList? {
- serialPorts = ArrayList()
- /**
- * Open the serial port
- * */
- serialPorts?.apply {
- add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
- add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
- }
- return serialPorts
- }
+ fun getSerialPorts(): ArrayList = serialPorts
fun closeSerialPort() {
- serialPorts?.forEach {
+ serialPorts.forEach {
it.closeSerialPort()
}
}
@@ -49,6 +39,22 @@
val devOpenHelper = DaoMaster.DevOpenHelper(this, "Detector_Common.db", null)
val daoMaster = DaoMaster(devOpenHelper.writableDatabase)
daoSession = daoMaster.newSession()
+
+ /**
+ * Open the serial port
+ * */
+ try {
+ serialPorts.apply {
+ add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
+ add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
+ }
+ } catch (e: SecurityException) {
+ "您没有串口的读写权限!".show(this)
+ } catch (e: IOException) {
+ "因为不明原因,串口无法打开!".show(this)
+ } catch (e: InvalidParameterException) {
+ "请检查串口!".show(this)
+ }
}
fun getDaoSession(): DaoSession {
diff --git a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt b/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
deleted file mode 100644
index 297ac02..0000000
--- a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.casic.detector.common.base
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.lifecycleScope
-import androidx.viewbinding.ViewBinding
-import com.pengxh.kt.lite.extensions.show
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.IOException
-import java.io.OutputStream
-import java.security.InvalidParameterException
-
-
-abstract class SerialPortActivity : AppCompatActivity() {
-
- protected lateinit var binding: VB
-
- lateinit var out: OutputStream
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = initViewBinding()
- setContentView(binding.root)
- setupTopBarLayout()
- initOnCreate(savedInstanceState)
- observeRequestState()
- initEvent()
-
- try {
- val serialPorts = BaseApplication.get().getSerialPorts()
- //读
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[0].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[1].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- //写
- serialPorts?.apply {
- out = this[0].outputStream
- }
- } catch (e: SecurityException) {
- "您没有串口的读写权限!".show(this)
- } catch (e: IOException) {
- "因为不明原因,串口无法打开!".show(this)
- } catch (e: InvalidParameterException) {
- "请检查串口!".show(this)
- }
- }
-
- /**
- * 初始化ViewBinding
- */
- abstract fun initViewBinding(): VB
-
- /**
- * 特定页面定制沉浸式状态栏
- */
- abstract fun setupTopBarLayout()
-
- /**
- * 初始化默认数据
- */
- abstract fun initOnCreate(savedInstanceState: Bundle?)
-
- /**
- * 数据请求状态监听
- */
- abstract fun observeRequestState()
-
- /**
- * 初始化业务逻辑
- */
- abstract fun initEvent()
-
- /**
- * 串口读数,已经切回主线程
- * */
- abstract fun onDataReceived(buffer: ByteArray)
-
- override fun onDestroy() {
- super.onDestroy()
- BaseApplication.get().closeSerialPort()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
new file mode 100644
index 0000000..b06a068
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
@@ -0,0 +1,9 @@
+package com.casic.detector.common.callback
+
+import java.io.OutputStream
+
+interface OnSerialPortDataListener {
+ fun write(outStream: OutputStream)
+
+ fun onDataReceived(buffer: ByteArray)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
new file mode 100644
index 0000000..b1685d5
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
@@ -0,0 +1,6 @@
+package com.casic.detector.common.model
+
+/**
+ * 标识器与当前定位的数据
+ * */
+data class MarkerDistanceData(var markerId: String, var distance: Float)
diff --git a/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
new file mode 100644
index 0000000..090f604
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
@@ -0,0 +1,104 @@
+package com.casic.detector.common.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+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.base.BaseApplication
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.utils.GpioManager
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.IOException
+
+class SerialPortService : Service(), LifecycleOwner {
+
+ private val kTag = "SerialPortService"
+ private val registry = LifecycleRegistry(this)
+ private val gpioManager by lazy { GpioManager() }
+ private val serialPorts by lazy { BaseApplication.get().getSerialPorts() }
+ private var gpioState = ""
+
+ override fun getLifecycle(): Lifecycle {
+ return registry
+ }
+
+ override fun onBind(intent: Intent?): IBinder {
+ return ServiceBinder()
+ }
+
+ inner class ServiceBinder : Binder() {
+ fun getSerialPortService(): SerialPortService {
+ return this@SerialPortService
+ }
+ }
+
+ fun openSerialPort(listener: OnSerialPortDataListener) {
+ //调高串口电位
+ gpioManager.setGpioHigh("18")
+ gpioState = "1"
+ Log.d(kTag, "openSerialPort: 调高串口电位")
+
+ Thread.sleep(100)
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ //写
+ listener.write(this[0].outputStream)
+ val stream = this[0].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ val stream = this[1].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+ }
+
+ fun closeSerialPort() {
+ //降低串口电位
+ gpioManager.setGpioLow("18")
+ gpioState = "0"
+ Log.d(kTag, "closeSerialPort: 降低串口电位")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
new file mode 100644
index 0000000..b50aaaf
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
@@ -0,0 +1,548 @@
+package com.casic.detector.common.view
+
+import android.app.DatePickerDialog
+import android.content.ComponentName
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
+import android.media.AudioAttributes
+import android.media.SoundPool
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.IBinder
+import android.util.Log
+import android.view.View
+import android.widget.AdapterView
+import androidx.lifecycle.ViewModelProvider
+import com.amap.api.location.AMapLocation
+import com.casic.detector.common.R
+import com.casic.detector.common.adapter.EditableImageAdapter
+import com.casic.detector.common.bean.MarkerLocalBean
+import com.casic.detector.common.callback.OnGetLocationListener
+import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.databinding.ActivityInstallMarkerBinding
+import com.casic.detector.common.extensions.compressImage
+import com.casic.detector.common.extensions.getDefaultValue
+import com.casic.detector.common.extensions.hexToString
+import com.casic.detector.common.extensions.isNumber
+import com.casic.detector.common.extensions.setDefaultValue
+import com.casic.detector.common.extensions.show
+import com.casic.detector.common.extensions.toColor
+import com.casic.detector.common.extensions.toHex
+import com.casic.detector.common.extensions.toObjectType
+import com.casic.detector.common.service.SerialPortService
+import com.casic.detector.common.utils.DataBaseManager
+import com.casic.detector.common.utils.LocaleConstant
+import com.casic.detector.common.utils.LocationTool
+import com.casic.detector.common.vm.TaskViewModel
+import com.luck.picture.lib.basic.PictureSelector
+import com.luck.picture.lib.config.SelectMimeType
+import com.luck.picture.lib.entity.LocalMedia
+import com.luck.picture.lib.interfaces.OnResultCallbackListener
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.appendZero
+import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.extensions.dateToTimestamp
+import com.pengxh.kt.lite.extensions.navigatePageTo
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.extensions.timestampToCompleteDate
+import com.pengxh.kt.lite.extensions.timestampToTime
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.LoadState
+import com.pengxh.kt.lite.utils.LoadingDialogHub
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import java.io.File
+import java.io.OutputStream
+import java.util.Calendar
+import java.util.Date
+
+class InstallMarkerActivity : KotlinBaseActivity() {
+
+ private val kTag = "InstallMarkerActivity"
+ private val context = this
+ private val calendar by lazy { Calendar.getInstance() }
+ private val locationTool by lazy { LocationTool(this) }
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val realPaths = ArrayList() //真实图片路径
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var soundResourceId = 0
+ private var serialPortService: SerialPortService? = null
+ private lateinit var imageAdapter: EditableImageAdapter
+
+ override fun initEvent() {
+ //返回
+ binding.titleInclude.leftBackView.setOnClickListener {
+ soundPool.autoPause()
+ finish()
+ }
+
+ binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
+ object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(
+ parent: AdapterView<*>?, view: View?, position: Int, id: Long
+ ) {
+ when (position) {
+ 0 -> {
+ //显示管线属性
+ binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 1 -> {
+ //显示管线附属物属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 2 -> {
+ //显示管线特征点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 3 -> {
+ //显示交叉穿越点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.VISIBLE
+ }
+ }
+ }
+
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+
+ }
+ }
+
+ //安装
+ binding.installButton.setOnClickListener {
+ val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+ if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
+ when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
+ "管线" -> "请输入管线种类!".show(this)
+ "管线附属物" -> "请输入附属物名称!".show(this)
+ "管线特征管点" -> "请输入特征管点!".show(this)
+ "交叉穿越点" -> "请输入上层管种类!".show(this)
+ }
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
+ if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
+ "请输入管径".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
+ "请输入埋深".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
+ if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
+ "请输入下层管管径".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.areaView.text.isNullOrBlank()) {
+ "请输入所属区域".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.lineView.text.isNullOrBlank()) {
+ "请输入所属线路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.roadView.text.isNullOrBlank()) {
+ "请输入所属道路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
+ "请选择建设年代".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
+ "请输入权属单位".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
+ "请先读取标识器获取ID".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
+ "请输入标识器埋深".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
+ "请输入标识器安装部门".show(this)
+ return@setOnClickListener
+ }
+
+ //先存本地再上传服务器
+ saveMarkerInLocal()
+
+ taskViewModel.installLabel(
+ this, companyId,
+ binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
+ binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
+ "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.areaView.text.toString(),
+ binding.objectInclude.lineView.text.toString(),
+ binding.objectInclude.roadView.text.toString(),
+ binding.objectInclude.constructDateView.text.toString(),
+ binding.objectInclude.ownerView.text.toString(),
+ objectId,
+ binding.identifierInclude.identifierIdView.text.toString(),
+ binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
+ "${binding.identifierInclude.identifierDeepView.text}mm",
+ binding.identifierInclude.personDeptView.text.toString(),
+ binding.identifierInclude.installTimeView.text.toString(),
+ binding.identifierInclude.lngView.text.toString(),
+ binding.identifierInclude.latView.text.toString(),
+ binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
+ binding.remarkView.text.toString(),
+ realPaths
+ )
+
+ //保存默认值
+ "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
+ "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
+ "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
+ "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
+ "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
+ "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
+ "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
+ "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
+ "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
+ "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
+ "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
+ }
+
+ //读标识器
+ binding.readMarkerButton.setOnClickListener {
+ LoadingDialogHub.show(this, "标识器读取中,请稍后...")
+ countDownTimer.start()
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ outStream.write('2'.code)
+ outStream.flush()
+
+ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
+ binding.readMarkerButton.isEnabled = false
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ Log.d(kTag, hex)
+ val markerId = hex.take(20).hexToString()
+ if (markerId.isNumber()) {
+ countDownTimer.cancel()
+ cancelLoadingView()
+ binding.readMarkerButton.isEnabled = true
+ binding.identifierInclude.identifierIdView.text = markerId
+ }
+ }
+ })
+ }
+ }
+
+ /**
+ * 搜索标识器超时倒计时
+ * */
+ private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
+ override fun onTick(millisUntilFinished: Long) {
+
+ }
+
+ override fun onFinish() {
+ cancelLoadingView()
+ "读取此标识器ID超时,请重试".show(context)
+ binding.readMarkerButton.isEnabled = true
+ }
+ }
+
+ private fun cancelLoadingView() {
+ LoadingDialogHub.dismiss()
+ soundPool.autoPause()
+ serialPortService?.closeSerialPort()
+ }
+
+ private fun saveMarkerInLocal() {
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+
+ val marker = MarkerLocalBean()
+ marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
+ marker.pipelineType = binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
+ marker.pipelineMaterial =
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
+ marker.pipelineDiameter = "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
+ marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
+ marker.underlyingPipelineType =
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
+ marker.underlyingPipelineMaterial =
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
+ marker.underlyingPipelineDiameter =
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
+ marker.underlyingPipelineDepth =
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
+ marker.buryMethod =
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
+ marker.area = binding.objectInclude.areaView.text.toString()
+ marker.line = binding.objectInclude.lineView.text.toString()
+ marker.road = binding.objectInclude.roadView.text.toString()
+ marker.constructTime = binding.objectInclude.constructDateView.text.toString()
+ marker.owner = binding.objectInclude.ownerView.text.toString()
+ marker.objectId = objectId
+ marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
+ marker.markerType = binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
+ marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
+ marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
+ marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
+ marker.lng = binding.identifierInclude.lngView.text.toString()
+ marker.lat = binding.identifierInclude.latView.text.toString()
+ marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
+ marker.remark = binding.remarkView.text.toString()
+ marker.imagePath = realPaths.toJson()
+
+ DataBaseManager.get.saveMarkerInLocale(marker)
+ }
+
+ private fun takePicture() {
+ PictureSelector.create(this).openCamera(SelectMimeType.ofImage())
+ .forResult(object : OnResultCallbackListener {
+ override fun onResult(result: ArrayList?) {
+ if (result == null) {
+ "拍照失败,请重试".show(context)
+ return
+ }
+ analyticalSelectResults(result[0])
+ }
+
+ override fun onCancel() {
+
+ }
+ })
+ }
+
+ private fun analyticalSelectResults(result: LocalMedia) {
+ //压缩图片
+ result.realPath.compressImage(context, object : OnImageCompressListener {
+ override fun onSuccess(file: File) {
+ realPaths.add(file.absolutePath)
+ imageAdapter.setupImage(realPaths)
+ }
+
+ override fun onError(e: Throwable) {
+ e.printStackTrace()
+ }
+ })
+ }
+
+ 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?) {
+ //在连接正常关闭的情况下不会被调用, 只在Service被破坏了或者被杀死的时候调用
+ }
+ }
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ //绑定串口通信服务
+ Intent(this, SerialPortService::class.java).also {
+ bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
+ }
+
+ locationTool.getCurrentLocation(true, object : OnGetLocationListener {
+ override fun onAMapLocationGet(location: AMapLocation?) {
+ if (location != null) {
+ binding.identifierInclude.lngView.text = location.longitude.toString()
+ binding.identifierInclude.latView.text = location.latitude.toString()
+ } else {
+ "当前位置信号差,无法获取定位".show(context)
+ }
+ }
+ })
+ soundResourceId = soundPool.load(this, R.raw.ring3, 1)
+
+ //初始化数据
+ initDefaultData()
+ }
+
+ override fun initViewBinding(): ActivityInstallMarkerBinding {
+ return ActivityInstallMarkerBinding.inflate(layoutInflater)
+ }
+
+ override fun observeRequestState() {
+ taskViewModel.loadState.observe(this) {
+ when (it) {
+ LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...")
+
+ LoadState.Success -> {
+ LoadingDialogHub.dismiss()
+ clearDefaultData()
+ "安装成功".show(this)
+ }
+
+ else -> LoadingDialogHub.dismiss()
+ }
+ }
+ }
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ private fun initDefaultData() {
+ binding.titleInclude.titleView.text = "安装新标识器"
+ binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
+
+ imageAdapter = EditableImageAdapter(this, 3, 3)
+ binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
+
+ //设置默认值
+ binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
+ binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
+ binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
+ binding.objectInclude.areaView.setText("areaView".getDefaultValue())
+ binding.objectInclude.lineView.setText("lineView".getDefaultValue())
+ binding.objectInclude.roadView.setText("roadView".getDefaultValue())
+ binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
+ binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
+ binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
+
+ /**************************************************************************************/
+ binding.objectInclude.objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0)
+ binding.objectInclude.pipeInclude.materialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeAttachInclude.attachSpinner.show(
+ this, LocaleConstant.ATTACH_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
+ this, LocaleConstant.FEATURE_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeInclude.buryTypeSpinner.show(
+ this, LocaleConstant.BURY_METHOD_ARRAY, 0
+ )
+ binding.objectInclude.constructDateView.setOnClickListener {
+ val datePicker = DatePickerDialog(
+ this, null,
+ calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH),
+ calendar.get(Calendar.DAY_OF_MONTH)
+ )
+ datePicker.show()
+
+ datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
+ val year = datePicker.datePicker.year
+ val month = datePicker.datePicker.month + 1
+ val day = datePicker.datePicker.dayOfMonth
+ val selectedDate = String.format(
+ "%s-%s-%s", year, month.appendZero(), day.appendZero()
+ )
+
+ //当前时间
+ val current = System.currentTimeMillis().timestampToTime()
+ val today = "$selectedDate $current".dateToTimestamp()
+ if (Date(today).after(Date())) {
+ "建设年代不能早于当前日期".show(context)
+ } else {
+ datePicker.dismiss()
+ binding.objectInclude.constructDateView.text = selectedDate
+ }
+ }
+ }
+ binding.identifierInclude.identifierTypeSpinner.show(
+ this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
+ )
+ binding.identifierInclude.installTimeView.text =
+ System.currentTimeMillis().timestampToCompleteDate()
+ binding.identifierInclude.colorSpinner.show(this, LocaleConstant.COLOR_ARRAY, 0)
+
+ imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
+ override fun onAddImageClick() {
+ takePicture()
+ }
+
+ override fun onItemClick(position: Int) {
+ if (realPaths[position].isEmpty()) {
+ "图片加载失败,无法查看大图".show(context)
+ } else {
+ navigatePageTo(position, realPaths)
+ }
+ }
+
+ override fun onItemLongClick(view: View?, position: Int) {
+ imageAdapter.deleteImage(position)
+ }
+ })
+ }
+
+ //清除默认数据
+ private fun clearDefaultData() {
+ "markerObjectTypeView".setDefaultValue("")
+ "pipelineDiameterView".setDefaultValue("")
+ "buryDeepView".setDefaultValue("")
+ "bottomPipeDiameterView".setDefaultValue("")
+ "bottomPointDeepView".setDefaultValue("")
+ "areaView".setDefaultValue("")
+ "lineView".setDefaultValue("")
+ "roadView".setDefaultValue("")
+ "ownerView".setDefaultValue("")
+ "identifierDeepView".setDefaultValue("")
+ "personDeptView".setDefaultValue("")
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ soundPool.autoPause()
+ locationTool.stopLocation()
+ 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 1dac658..f949269 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,31 +1,25 @@
package com.casic.detector.common.view
-import android.app.DatePickerDialog
-import android.app.Dialog
+import android.content.ComponentName
import android.content.Context
-import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
-import android.hardware.Sensor
-import android.hardware.SensorEvent
-import android.hardware.SensorEventListener
-import android.hardware.SensorManager
import android.media.AudioAttributes
import android.media.SoundPool
import android.os.Bundle
-import android.os.CountDownTimer
+import android.os.IBinder
import android.util.Log
import android.view.KeyEvent
import android.view.View
-import android.widget.AdapterView
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.amap.api.location.AMapLocation
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
-import com.amap.api.maps.AMapUtils
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.CoordinateConverter
import com.amap.api.maps.model.BitmapDescriptorFactory
@@ -34,38 +28,29 @@
import com.amap.api.maps.model.MarkerOptions
import com.amap.api.maps.model.MyLocationStyle
import com.casic.detector.common.R
-import com.casic.detector.common.adapter.EditableImageAdapter
-import com.casic.detector.common.base.SerialPortActivity
+import com.casic.detector.common.base.BaseApplication
import com.casic.detector.common.bean.MarkerLocalBean
import com.casic.detector.common.bean.TaskLocalBean
import com.casic.detector.common.callback.OnGetLocationListener
-import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
import com.casic.detector.common.cluster.ClusterItem
import com.casic.detector.common.cluster.ClusterOverlay
import com.casic.detector.common.cluster.RegionItem
import com.casic.detector.common.databinding.ActivityMainBinding
-import com.casic.detector.common.databinding.DialogInstallMarkerBinding
-import com.casic.detector.common.databinding.DialogSearchMarkerNewBinding
import com.casic.detector.common.extensions.appendDownloadUrl
-import com.casic.detector.common.extensions.compressImage
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.getDefaultValue
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.setDefaultValue
-import com.casic.detector.common.extensions.show
-import com.casic.detector.common.extensions.toColor
import com.casic.detector.common.extensions.toHex
-import com.casic.detector.common.extensions.toObjectType
import com.casic.detector.common.model.TaskDetailLocalModel
import com.casic.detector.common.model.TaskModel
+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.GpioManager
import com.casic.detector.common.utils.LocaleConstant
import com.casic.detector.common.utils.LocationTool
import com.casic.detector.common.utils.NtripAuthorizationCreator
@@ -77,26 +62,15 @@
import com.casic.detector.common.vm.TaskViewModel
import com.casic.detector.common.widgets.MarkerDetailDialog
import com.casic.detector.common.widgets.QueryMarkerDialog
-import com.casic.detector.common.widgets.RadarScanView
import com.casic.detector.common.widgets.SamplePopupWindow
-import com.luck.picture.lib.basic.PictureSelector
-import com.luck.picture.lib.config.SelectMimeType
-import com.luck.picture.lib.entity.LocalMedia
-import com.luck.picture.lib.interfaces.OnResultCallbackListener
-import com.pengxh.kt.lite.extensions.appendZero
-import com.pengxh.kt.lite.extensions.binding
-import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertDrawable
import com.pengxh.kt.lite.extensions.createDownloadFileDir
-import com.pengxh.kt.lite.extensions.dateToTimestamp
import com.pengxh.kt.lite.extensions.dp2px
-import com.pengxh.kt.lite.extensions.getSystemService
-import com.pengxh.kt.lite.extensions.initDialogLayoutParams
import com.pengxh.kt.lite.extensions.isNetworkConnected
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.extensions.timestampToCompleteDate
-import com.pengxh.kt.lite.extensions.timestampToTime
import com.pengxh.kt.lite.extensions.toJson
import com.pengxh.kt.lite.utils.FileDownloadManager
import com.pengxh.kt.lite.utils.LoadState
@@ -108,60 +82,41 @@
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
import io.netty.buffer.Unpooled
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
+import java.io.OutputStream
import java.nio.charset.StandardCharsets
-import java.util.Calendar
-import java.util.Date
import java.util.Timer
import java.util.TimerTask
-import kotlin.math.atan2
-class MainActivity : SerialPortActivity(), SensorEventListener,
- OnSocketConnectListener {
+class MainActivity : KotlinBaseActivity(), OnSocketConnectListener {
private val kTag = "MainActivity"
private val context = this
private val samplePopupWindow by lazy { SamplePopupWindow(this) }
private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) }
private val backDrawables by lazy { HashMap() }
- private val installDialog by lazy { InstallMarkerDialog(this) }
- private val searchNewDialog by lazy { SearchMarkerNewDialog(this) }
private val detailDialog by lazy { MarkerDetailDialog(this) }
private val locationTool by lazy { LocationTool(this) }
- private val rotationMatrix = FloatArray(9)//旋转矩阵缓存
- private val valueArray = FloatArray(3)//方位角数值
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
private var clickTime: Long = 0
private var markers = ArrayList()
private var clusterOverlay: ClusterOverlay? = null
private var isFreeTask = false
private var freeTaskTitle = ""
private var ids = HashSet()
- private var signalTask: TimerTask? = null
- private var energyTask: TimerTask? = null
- private var searchMarkerTimer: Timer? = null
private var freeTaskId: String? = null
- private var gravity: FloatArray? = null
- private var geomagnetic: FloatArray? = null
private var connectState = ConnectState.CLOSED
private var socketClient: SocketClient? = null
- private lateinit var aMap: AMap
- private lateinit var sensorManager: SensorManager
-
- /***inner class 需要用到*****start*/
- private val gpioManager by lazy { GpioManager() }
- private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
- private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
- .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
- private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var serialPortService: SerialPortService? = null
+ private var searchMarkerTimer: Timer? = null
private var soundResourceId = 0
- private var slowSoundResourceId = 0
- private var fastSoundResourceId = 0
private var isExecuteTask = false
-
- /***inner class 需要用到*****end*/
+ private lateinit var aMap: AMap
override fun initViewBinding(): ActivityMainBinding {
return ActivityMainBinding.inflate(layoutInflater)
@@ -171,10 +126,26 @@
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)
+ }
+
soundResourceId = soundPool.load(this, R.raw.ring3, 1)
- slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
- fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)
RtkLocationTool.getCurrentLocation(this) {
if (connectState == ConnectState.SUCCESS) {
@@ -192,8 +163,6 @@
samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES)
samplePopupWindow.setBackgroundDrawable(null)
- sensorManager = getSystemService()!!
-
//task网络请求监听
taskViewModel.markerFileResult.observe(this) {
if (it.isSuccess) {
@@ -316,9 +285,6 @@
//安装。上传,然后存入本地库
binding.installButton.setOnClickListener {
- /**
- * 改为Dialog方式,避免频繁打开/关闭串口
- * */
if (isFreeTask) {
AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示")
.setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能")
@@ -329,7 +295,7 @@
}
}).build().show()
} else {
- installDialog.show()
+ navigatePageTo()
}
}
@@ -449,8 +415,6 @@
//探测
binding.detectionButton.setOnClickListener {
/**
- * 改为Dialog方式,避免频繁打开/关闭串口
- *
* 如果开启自由巡检就不让探测
* */
if (isFreeTask) {
@@ -463,7 +427,12 @@
}
}).build().show()
} else {
- searchNewDialog.show()
+ val flag = if (isExecuteTask) {
+ "1"
+ } else {
+ "0"
+ }
+ navigatePageTo(flag)
}
}
@@ -476,14 +445,8 @@
override fun onConfirmClick() {
isFreeTask = false
soundPool.autoPause()
-
- //停止信号和ID搜索定时器
- signalTask?.cancel()
- energyTask?.cancel()
searchMarkerTimer?.cancel()
-
- //降低串口电位
- gpioManager.setGpioLow("18")
+ serialPortService?.closeSerialPort()
binding.stopFreeTaskButton.visibility = View.GONE
if (freeTaskId.isNullOrBlank()) {
@@ -527,110 +490,79 @@
}
private fun openSerialPort() {
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- isFreeTask = true
- //自由巡检
- signalTask = object : TimerTask() {
- override fun run() {
- out.write('2'.code)
- out.flush()
- }
- }
-
- energyTask = object : TimerTask() {
- override fun run() {
- out.write('6'.code)
- out.flush()
- }
- }
-
- searchMarkerTimer = Timer()
- searchMarkerTimer?.apply {
- schedule(signalTask, 0, 200)
- schedule(energyTask, 0, 251)
- }
-
binding.stopFreeTaskButton.visibility = View.VISIBLE
- }
+ isFreeTask = true
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ searchMarkerTimer = Timer()
+ searchMarkerTimer?.schedule(object : TimerTask() {
+ override fun run() {
+ outStream.write('2'.code)
+ outStream.flush()
- override fun onDataReceived(buffer: ByteArray) {
- val hex = buffer.toHex()
-// Log.d(kTag, "$kTag => $hex")
- if (searchNewDialog.isDetectMarker) {
- searchNewDialog.bindingValue(hex)
- } else if (installDialog.isReadMarker) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- installDialog.bindingValue(markerId)
+ Thread.sleep(50)
+
+ outStream.write('6'.code)
+ outStream.flush()
+ }
+ }, 0, 200)
}
- } else if (isFreeTask) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- //只响一次,因为探测频率高,所以依旧是连续的报警声
- soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
- //添加地图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))
- )
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ if (hex.startsWith("4E")) {
+ //只响一次,因为探测频率高,所以依旧是连续的报警声
+ soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
+
+ 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()
}
}
- 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()
+ 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 (hex.startsWith("4E")) {
- val energyResponse = hex.take(10).hexToString()
- try {
- val energy = energyResponse.substring(1).toInt()
- if (energy <= 500 && detailDialog.isShowing) {
- detailDialog.dismiss()
- }
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- }
- }
+ })
}
override fun observeRequestState() {
taskViewModel.loadState.observe(this) {
when (it) {
- LoadState.Loading -> {
- if (installDialog.isInstallMarker) {
- LoadingDialogHub.show(this, "标识器安装中,请稍后...")
- } else {
- LoadingDialogHub.show(this, "提交工单中,请稍后")
- }
- }
-
- LoadState.Success -> {
- if (installDialog.isInstallMarker) {
- installDialog.clearDefaultData()
- installDialog.dismiss()
- "${installDialog.markerId}安装成功".show(this)
- }
- LoadingDialogHub.dismiss()
- }
+ LoadState.Loading -> LoadingDialogHub.show(this, "提交工单中,请稍后")
else -> LoadingDialogHub.dismiss()
}
@@ -939,32 +871,6 @@
} else super.onKeyDown(keyCode, event)
}
- override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
- //精度发生变化时触发
- }
-
- override fun onSensorChanged(event: SensorEvent?) {
- //值发生变化时触发
- val type = event?.sensor?.type
-
- if (type == Sensor.TYPE_ACCELEROMETER) {
- gravity = event.values
- } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
- geomagnetic = event.values
- }
-
- if (gravity == null || geomagnetic == null) {
- return
- }
-
- if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
- SensorManager.getOrientation(rotationMatrix, valueArray)
-
- val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt()
- searchNewDialog.updateDegreeValue(degree)
- }
- }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
@@ -978,14 +884,6 @@
showLabelsOnMap()
}
- //注册加速度传感器监听
- val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
- sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)
-
- //注册磁场传感器监听
- val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
- sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL)
-
//取缓存
val remoteHost = SaveKeyValues.getValue(
LocaleConstant.RTK_SERVER, "203.107.45.154"
@@ -995,20 +893,20 @@
) as String
//连接千寻RTK服务器
- lifecycleScope.launch(Dispatchers.IO) {
- if (socketClient != null) {
- socketClient?.disconnect()
- delay(3000)
- }
-
- socketClient = SocketClient.Builder()
- .setHostname(remoteHost)
- .setPort(remotePort.toInt())
- .setTimeout(5000)
- .setOnSocketListener(this@MainActivity)
- .build()
- socketClient?.connect()
- }
+// lifecycleScope.launch(Dispatchers.IO) {
+// if (socketClient != null) {
+// socketClient?.disconnect()
+// delay(3000)
+// }
+//
+// socketClient = SocketClient.Builder()
+// .setHostname(remoteHost)
+// .setPort(remotePort.toInt())
+// .setTimeout(5000)
+// .setOnSocketListener(this@MainActivity)
+// .build()
+// socketClient?.connect()
+// }
}
override fun onMessageResponse(data: ByteArray) {
@@ -1021,12 +919,12 @@
val result = String(data, StandardCharsets.UTF_8)
Log.d(kTag, "onMessageResponse: $result")
if (result.contains("ICY 200 OK")) {
- "高精度定位服务器连接成功".show(this)
+ "高精度定位服务连接成功".show(this)
}
} else {
"收到千寻数据返回,长度:${data.size}".show(this)
- out.write(data)
- out.flush()
+// out.write(data)
+// out.flush()
}
}
@@ -1061,7 +959,6 @@
override fun onPause() {
super.onPause()
binding.mapView.onPause()
- sensorManager.unregisterListener(this)
}
override fun onSaveInstanceState(outState: Bundle) {
@@ -1072,794 +969,11 @@
override fun onDestroy() {
super.onDestroy()
binding.mapView.onDestroy()
- soundPool.release()
+ soundPool.autoPause()
+ searchMarkerTimer?.cancel()
+ serialPortService?.closeSerialPort()
locationTool.stopLocation()
- //降低串口电位
- gpioManager.setGpioLow("18")
+ unbindService(serviceConnection)
+ BaseApplication.get().closeSerialPort()
}
-
- /**安装标识器对话框******************************************************************************/
- inner class InstallMarkerDialog(private val context: Context) : Dialog(context) {
-
- private val binding: DialogInstallMarkerBinding by binding()
- private val calendar by lazy { Calendar.getInstance() }
- private val realPaths = ArrayList() //真实图片路径
- private lateinit var imageAdapter: EditableImageAdapter
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
-
- var isReadMarker = false
- var isInstallMarker = false
- var markerId = ""
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
-
- //初始化数据
- initDefaultData()
-
- //返回
- binding.titleInclude.leftBackView.setOnClickListener {
- soundPool.autoPause()
- dismiss()
- }
-
- binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
- object : AdapterView.OnItemSelectedListener {
- override fun onItemSelected(
- parent: AdapterView<*>?, view: View?, position: Int, id: Long
- ) {
- when (position) {
- 0 -> {
- //显示管线属性
- binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 1 -> {
- //显示管线附属物属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 2 -> {
- //显示管线特征点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 3 -> {
- //显示交叉穿越点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility =
- View.VISIBLE
- }
- }
- }
-
- override fun onNothingSelected(parent: AdapterView<*>?) {
-
- }
- }
-
- //安装
- binding.installButton.setOnClickListener {
- val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
- if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
- when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
- "管线" -> "请输入管线种类!".show(context)
- "管线附属物" -> "请输入附属物名称!".show(context)
- "管线特征管点" -> "请输入特征管点!".show(context)
- "交叉穿越点" -> "请输入上层管种类!".show(context)
- }
- return@setOnClickListener
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
- if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
- "请输入管径".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
- "请输入埋深".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
- if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
- "请输入下层管管径".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.areaView.text.isNullOrBlank()) {
- "请输入所属区域".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.lineView.text.isNullOrBlank()) {
- "请输入所属线路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.roadView.text.isNullOrBlank()) {
- "请输入所属道路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
- "请选择建设年代".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
- "请输入权属单位".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
- "请先读取标识器获取ID".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
- "请输入标识器埋深".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
- "请输入标识器安装部门".show(context)
- return@setOnClickListener
- }
-
- //先存本地再上传服务器
- saveMarkerInLocal()
-
- isInstallMarker = true
- taskViewModel.installLabel(
- context,
- companyId,
- binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
- "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
- binding.objectInclude.areaView.text.toString(),
- binding.objectInclude.lineView.text.toString(),
- binding.objectInclude.roadView.text.toString(),
- binding.objectInclude.constructDateView.text.toString(),
- binding.objectInclude.ownerView.text.toString(),
- objectId,
- binding.identifierInclude.identifierIdView.text.toString(),
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
- "${binding.identifierInclude.identifierDeepView.text}mm",
- binding.identifierInclude.personDeptView.text.toString(),
- binding.identifierInclude.installTimeView.text.toString(),
- binding.identifierInclude.lngView.text.toString(),
- binding.identifierInclude.latView.text.toString(),
- binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
- binding.remarkView.text.toString(),
- realPaths
- )
-
- //保存默认值
- "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
- "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
- "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
- "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
- "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
- "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
- "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
- "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
- "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
- "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
- "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
- }
-
- //读标识器
- binding.readMarkerButton.setOnClickListener {
- LoadingDialogHub.show(this@MainActivity, "标识器读取中,请稍后...")
- binding.readMarkerButton.isEnabled = false
-
- isReadMarker = true
-
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
-
- out.write('2'.code)
- out.flush()
-
- countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- "读取此标识器ID超时,请退出应用再试".show(context)
- }
- }
- countDownTimer.start()
- }
- }
-
- override fun show() {
- super.show()
- locationTool = LocationTool(context)
- locationTool.getCurrentLocation(true, object : OnGetLocationListener {
- override fun onAMapLocationGet(location: AMapLocation?) {
- if (location != null) {
- binding.identifierInclude.lngView.text = location.longitude.toString()
- binding.identifierInclude.latView.text = location.latitude.toString()
- } else {
- "当前位置信号差,无法获取定位".show(context)
- }
- }
- })
- }
-
- fun bindingValue(markerId: String) {
- this.markerId = markerId
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- countDownTimer.cancel()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- binding.identifierInclude.identifierIdView.text = markerId
- }
-
- override fun dismiss() {
- //降低串口电位
- gpioManager.setGpioLow("18")
- soundPool.autoPause()
- isInstallMarker = false
- locationTool.stopLocation()
- super.dismiss()
- }
-
- private fun initDefaultData() {
- binding.titleInclude.titleView.text = "安装新标识器"
- binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
-
- imageAdapter = EditableImageAdapter(context, 3, 3)
- binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
-
- //设置默认值
- binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
- binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
- binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
- binding.objectInclude.areaView.setText("areaView".getDefaultValue())
- binding.objectInclude.lineView.setText("lineView".getDefaultValue())
- binding.objectInclude.roadView.setText("roadView".getDefaultValue())
- binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
- binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
- binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
-
- /**************************************************************************************/
- binding.objectInclude.objectTypeSpinner.show(
- this@MainActivity, LocaleConstant.POINT_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.materialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeAttachInclude.attachSpinner.show(
- this@MainActivity, LocaleConstant.ATTACH_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
- this@MainActivity, LocaleConstant.FEATURE_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.buryTypeSpinner.show(
- this@MainActivity, LocaleConstant.BURY_METHOD_ARRAY, 0
- )
-
- binding.objectInclude.constructDateView.setOnClickListener {
- val datePicker = DatePickerDialog(
- context,
- null,
- calendar.get(Calendar.YEAR),
- calendar.get(Calendar.MONTH),
- calendar.get(Calendar.DAY_OF_MONTH)
- )
- datePicker.show()
-
- datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
- val year = datePicker.datePicker.year
- val month = datePicker.datePicker.month + 1
- val day = datePicker.datePicker.dayOfMonth
- val selectedDate = String.format(
- "%s-%s-%s", year, month.appendZero(), day.appendZero()
- )
-
- //当前时间
- val current = System.currentTimeMillis().timestampToTime()
- val today = "$selectedDate $current".dateToTimestamp()
- if (Date(today).after(Date())) {
- "建设年代不能早于当前日期".show(context)
- } else {
- datePicker.dismiss()
- binding.objectInclude.constructDateView.text = selectedDate
- }
- }
- }
-
- binding.identifierInclude.identifierTypeSpinner.show(
- this@MainActivity, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
- )
-
- binding.identifierInclude.installTimeView.text =
- System.currentTimeMillis().timestampToCompleteDate()
-
- binding.identifierInclude.colorSpinner.show(
- this@MainActivity, LocaleConstant.COLOR_ARRAY, 0
- )
-
- imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
- override fun onAddImageClick() {
- takePicture()
- }
-
- override fun onItemClick(position: Int) {
- if (realPaths[position].isEmpty()) {
- "图片加载失败,无法查看大图".show(context)
- } else {
- context.navigatePageTo(position, realPaths)
- }
- }
-
- override fun onItemLongClick(view: View?, position: Int) {
- imageAdapter.deleteImage(position)
- }
- })
- /**************************************************************************************/
- }
-
- //清除默认数据
- fun clearDefaultData() {
- "markerObjectTypeView".setDefaultValue("")
- "pipelineDiameterView".setDefaultValue("")
- "buryDeepView".setDefaultValue("")
- "bottomPipeDiameterView".setDefaultValue("")
- "bottomPointDeepView".setDefaultValue("")
- "areaView".setDefaultValue("")
- "lineView".setDefaultValue("")
- "roadView".setDefaultValue("")
- "ownerView".setDefaultValue("")
- "identifierDeepView".setDefaultValue("")
- "personDeptView".setDefaultValue("")
- }
-
- private fun saveMarkerInLocal() {
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
-
- val marker = MarkerLocalBean()
- marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
- marker.pipelineType =
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
- marker.pipelineMaterial =
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
- marker.pipelineDiameter =
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
- marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
- marker.underlyingPipelineType =
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
- marker.underlyingPipelineMaterial =
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
- marker.underlyingPipelineDiameter =
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
- marker.underlyingPipelineDepth =
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
- marker.buryMethod =
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
- marker.area = binding.objectInclude.areaView.text.toString()
- marker.line = binding.objectInclude.lineView.text.toString()
- marker.road = binding.objectInclude.roadView.text.toString()
- marker.constructTime = binding.objectInclude.constructDateView.text.toString()
- marker.owner = binding.objectInclude.ownerView.text.toString()
- marker.objectId = objectId
- marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
- marker.markerType =
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
- marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
- marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
- marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
- marker.lng = binding.identifierInclude.lngView.text.toString()
- marker.lat = binding.identifierInclude.latView.text.toString()
- marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
- marker.remark = binding.remarkView.text.toString()
- marker.imagePath = realPaths.toJson()
-
- DataBaseManager.get.saveMarkerInLocale(marker)
- }
-
- private fun takePicture() {
- PictureSelector.create(this@MainActivity).openCamera(SelectMimeType.ofImage())
- .forResult(object : OnResultCallbackListener {
- override fun onResult(result: java.util.ArrayList?) {
- if (result == null) {
- "拍照失败,请重试".show(context)
- return
- }
- analyticalSelectResults(result[0])
- }
-
- override fun onCancel() {
-
- }
- })
- }
-
- private fun analyticalSelectResults(result: LocalMedia) {
- //压缩图片
- result.realPath.compressImage(context, object : OnImageCompressListener {
- override fun onSuccess(file: File) {
- realPaths.add(file.absolutePath)
- imageAdapter.setupImage(realPaths)
- }
-
- override fun onError(e: Throwable) {
- e.printStackTrace()
- }
- })
- }
- }
-
- /**探测标识器新对话框****************************************************************************/
- inner class SearchMarkerNewDialog(private val context: Context) : Dialog(context) {
-
- private val taskId by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
- }
- private val taskCode by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_CODE, "") as String
- }
- private val markerPoints by lazy { ArrayList() }
- private val binding: DialogSearchMarkerNewBinding by binding()
- private var markerId = ""//实际探测出来的标识器ID
- private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID
- private lateinit var searchMarkerTimer: Timer
- private lateinit var signalTask: TimerTask
- private lateinit var energyTask: TimerTask
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
- var isDetectMarker = false
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
- binding.depthButton.setOnClickListener {
- signalTask.cancel()
- energyTask.cancel()
- searchMarkerTimer.cancel()
-
- out.write('3'.code)
- val result = DataBaseManager.get.queryMarkerById(markerId)
- if (result.isNotEmpty()) {
- val tag = when (result.first().markerType) {
- "EM30" -> '7'
- "EM50" -> '8'
- "EM14" -> '9'
- else -> '1'
- }
- if (tag == '1') {
- "此标识器无法读取埋深!".show(context)
- initTimer()
- } else {
- // 发送读取标识器埋设深度指令
- LoadingDialogHub.show(this@MainActivity, "正在测距,请稍后...")
- out.write(tag.code)
- out.flush()
- countDownTimer = object : CountDownTimer(15 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- "探测此标识器深度超时,请重试".show(context)
- initTimer()
- }
- }
- countDownTimer.start()
- }
- } else {
- "标识器未安装,安装成功后才可读取埋深!".show(context)
- initTimer()
- }
- }
-
- binding.markerInfoButton.setOnClickListener {
- val id = if (markerId == "") {
- nearestMarkerId
- } else {
- markerId
- }
- //查库
- val result = DataBaseManager.get.queryMarkerById(id)
- if (result.isNotEmpty()) {
- context.navigatePageTo(result.first().toJson())
- } else {
- context.navigatePageTo(id)
- }
- //查看完就把ID置空,便于下次查看最新的ID
- markerId = ""
- }
- }
-
- override fun show() {
- super.show()
- locationTool = LocationTool(context)
- //点位渲染,每次定位都计算当前位置与符合条件的点距离
- locationTool.getCurrentLocation(false, object : OnGetLocationListener {
- override fun onAMapLocationGet(location: AMapLocation?) {
- location?.apply {
- renderDataPoint(this)
- }
- }
- })
- }
-
- /**
- * 计算并渲染数据点。点太多采用协程计算,不然会有点卡顿
- * @param location 定位点(RTK获取)
- * */
- private fun renderDataPoint(location: AMapLocation) {
- val longitude = location.longitude
- val latitude = location.latitude
- lifecycleScope.launch(Dispatchers.IO) {
- val dataPoints = ArrayList()
- DataBaseManager.get.loadMarkers().forEach {
- val distance = AMapUtils.calculateLineDistance(
- LatLng(it.lat.toDouble(), it.lng.toDouble()), LatLng(latitude, longitude)
- )
- val formatDistance = "%.2f".format(distance).toFloat()
-
- markerPoints.add(MarkerDistanceData(it.markerId, formatDistance))
-
- if (formatDistance <= LocaleConstant.MAX_DISTANCE) {
- val angle = atan2(
- (it.lat.toDouble() - latitude), (it.lng.toDouble() - longitude)
- ) + Math.PI
- val formatAngle = "%.2f".format(angle).toDouble()
- dataPoints.add(
- RadarScanView.DataPoint(formatAngle, formatDistance)
- )
- }
- }
- withContext(Dispatchers.Main) {
- binding.radarScanView.renderPointData(dataPoints,
- object : RadarScanView.OnGetNearestPointCallback {
- override fun getNearestPoint(point: RadarScanView.DataPoint?) {
- if (point == null) {
- binding.distanceValueView.text = "大于5.5m"
- binding.distancePgBar.progress = 100
- } else {
- binding.distanceValueView.text = "${point.distance}m"
- val progress =
- if (point.distance > LocaleConstant.MAX_DISTANCE) {
- 100
- } else {
- (point.distance / LocaleConstant.MAX_DISTANCE) * 100
- }
- binding.distancePgBar.progress = progress.toInt()
- }
- }
- })
- }
- }
- }
-
- override fun onStart() {
- super.onStart()
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- initTimer()
-
- isDetectMarker = true
-
- if (isExecuteTask) {
- binding.taskStateView.visibility = View.GONE
- binding.taskStateView.isSelected = false
- } else {
- binding.taskStateView.visibility = View.VISIBLE
- binding.taskStateView.isSelected = true
- }
- }
-
- fun bindingValue(hex: String) {
- if (hex.startsWith("4E")) {
- try {
- //4E转为String为N,代表能量值
- //用能量值转动表盘
- val energyResponse = hex.take(10).hexToString()
- val energy = energyResponse.substring(1).toInt()
- if (energy >= 4000) {
- soundPool.play(fastSoundResourceId, 1f, 1f, 0, 0, 1f)
- } else {
- soundPool.play(slowSoundResourceId, 1f, 1f, 0, 0, 1f)
- }
-
- //通过设置进度条表示能量值
- binding.energyPgBar.progress = energy
- binding.energyValueView.text = "${energy}dB"
-
- if (energy <= 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.searchResultView.text = "未检测到标识器"
- binding.searchResultView.setTextColor(Color.parseColor("#8D1717"))
- binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_red)
- } else if (energy >= 4100) {
- binding.energyTipsView.text = "信号极强,接近标识器正上方"
- binding.energyTipsView.setTextColor(Color.parseColor("#428d00"))
- binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green)
-
- if (markerPoints.isEmpty()) {
- Log.d(kTag, "bindingValue: markerPoints.isEmpty()")
- return
- }
-
- //需要转一下,不然会有并发问题
- val temp = ArrayList()
- temp.addAll(markerPoints)
- temp.sortBy(MarkerDistanceData::distance)
- val nearestPoint = temp.first()
- nearestMarkerId = nearestPoint.markerId
- handleMarker(nearestMarkerId)
- } else {
- binding.energyTipsView.text = "已靠近,请继续移动位置"
- binding.energyTipsView.setTextColor(Color.parseColor("#8C5700"))
- binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow)
- }
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- } else if (hex.startsWith("53")) {
- LoadingDialogHub.dismiss()
- countDownTimer.cancel()
- try {
- val depthResponse = hex.take(10).hexToString()
- val depth = depthResponse.drop(2).toInt()
- AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示")
- .setMessage("标识器埋深:${depth}厘米").setPositiveButton("知道了")
- .setOnDialogButtonClickListener(object :
- AlertMessageDialog.OnDialogButtonClickListener {
- override fun onConfirmClick() {
- initTimer()
- }
- }).build().show()
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- } else {
- val id = hex.take(20).hexToString()
- if (id.isNumber()) {
- markerId = id
- handleMarker(markerId)
- }
- }
- }
-
- private fun handleMarker(id: String) {
- binding.depthButton.isEnabled = true
- binding.depthButton.setTextColor(Color.WHITE)
- binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
- binding.markerInfoButton.isEnabled = true
- binding.markerInfoButton.setTextColor(Color.WHITE)
- binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)
-
- binding.searchResultView.text = "已检测到标识器"
- binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
- binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)
-
- //自动上传标识器
- if (isExecuteTask) {
- val taskMarkerLocalBean = DataBaseManager.get.queryTaskMarkerById(
- taskId, taskCode, id, "0"
- )
- taskMarkerLocalBean?.apply {
- taskViewModel.uploadMarker(context, this)
- }
- }
- }
-
- //更新罗盘角度
- fun updateDegreeValue(degree: Int) {
- binding.radarScanView.setDegreeValue(degree)
- }
-
- private fun initTimer() {
- searchMarkerTimer = Timer()
-
- signalTask = object : TimerTask() {
- override fun run() {
- out.write('2'.code)
- out.flush()
- }
- }
-
- energyTask = object : TimerTask() {
- override fun run() {
- out.write('6'.code)
- out.flush()
- }
- }
-
- //错开信号和能量定时器
- searchMarkerTimer.schedule(signalTask, 0, 201)
- searchMarkerTimer.schedule(energyTask, 0, 251)
- }
-
- override fun dismiss() {
- signalTask.cancel()
- energyTask.cancel()
- searchMarkerTimer.cancel()
- //降低串口电位
- gpioManager.setGpioLow("18")
- isDetectMarker = false
- soundPool.autoPause()
- locationTool.stopLocation()
- super.dismiss()
- }
- }
-
- /**
- * 标识器与当前定位的数据
- * */
- data class MarkerDistanceData(var markerId: String, var distance: Float)
}
\ 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
new file mode 100644
index 0000000..14fe667
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/view/SearchMarkerActivity.kt
@@ -0,0 +1,462 @@
+package com.casic.detector.common.view
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.graphics.Color
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import android.media.AudioAttributes
+import android.media.SoundPool
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.IBinder
+import android.util.Log
+import android.view.View
+import android.view.WindowManager
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMapUtils
+import com.amap.api.maps.model.LatLng
+import com.casic.detector.common.R
+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.hexToString
+import com.casic.detector.common.extensions.isNumber
+import com.casic.detector.common.extensions.toHex
+import com.casic.detector.common.model.MarkerDistanceData
+import com.casic.detector.common.service.SerialPortService
+import com.casic.detector.common.utils.DataBaseManager
+import com.casic.detector.common.utils.LocaleConstant
+import com.casic.detector.common.utils.LocationTool
+import com.casic.detector.common.vm.TaskViewModel
+import com.casic.detector.common.widgets.RadarScanView
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.Constant
+import com.pengxh.kt.lite.utils.LoadingDialogHub
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.OutputStream
+import java.util.Timer
+import java.util.TimerTask
+import kotlin.math.atan2
+
+class SearchMarkerActivity : KotlinBaseActivity(),
+ SensorEventListener {
+
+ private val kTag = "SearchMarkerActivity"
+ private val context = this
+ private val locationTool by lazy { LocationTool(this) }
+ private val markerPoints by lazy { ArrayList() }
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val sensorManager by lazy { getSystemService()!! }
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private val rotationMatrix = FloatArray(9)//旋转矩阵缓存
+ private val valueArray = FloatArray(3)//方位角数值
+ private var slowSoundResourceId = 0
+ private var fastSoundResourceId = 0
+ private var markerId = ""//实际探测出来的标识器ID
+ private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID
+ private var isExecuteTask = false
+ private var signalEnergy = 0 //标识器信号强度
+ 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 {
+ override fun onServiceConnected(name: ComponentName?, iBinder: IBinder?) {
+ if (iBinder is SerialPortService.ServiceBinder) {
+ serialPortService = iBinder.getSerialPortService()
+ Log.d(kTag, "onServiceConnected: 服务已绑定")
+ searchMarker()
+ }
+ }
+
+ override fun onServiceDisconnected(name: ComponentName?) {
+
+ }
+ }
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ val flag = intent.getStringExtra(Constant.INTENT_PARAM) as String
+ isExecuteTask = flag != "0"
+
+ //绑定串口通信服务
+ Intent(this, SerialPortService::class.java).also {
+ bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
+ }
+
+ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
+ fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)
+
+ //点位渲染,每次定位都计算当前位置与符合条件的点距离
+ locationTool.getCurrentLocation(false, object : OnGetLocationListener {
+ override fun onAMapLocationGet(location: AMapLocation?) {
+ location?.apply {
+ renderDataPoint(this)
+ }
+ }
+ })
+
+ if (isExecuteTask) {
+ binding.taskStateView.visibility = View.GONE
+ binding.taskStateView.isSelected = false
+ } else {
+ binding.taskStateView.visibility = View.VISIBLE
+ binding.taskStateView.isSelected = true
+ }
+
+ //在标识器信号强度很强的时候,从数据库中计算出距离最近的点,以防出现探测不到ID的情况
+ searchSignalEnergyTimer = Timer()
+ searchSignalEnergyTimer.schedule(object : TimerTask() {
+ override fun run() {
+ //markerId为空,说明没有通过探测得到标识器ID,那么就需要通过计算得到近似的标识器
+ if (signalEnergy >= 4100 && markerPoints.isNotEmpty()) {
+ try {
+ //需要转一下,不然会有并发问题
+ val temp = ArrayList()
+ temp.addAll(markerPoints)
+ temp.sortBy(MarkerDistanceData::distance)
+ val nearestPoint = temp.first()
+ nearestMarkerId = nearestPoint.markerId
+ runOnUiThread {
+ handleMarker(nearestMarkerId)
+ }
+ markerPoints.clear()
+ } catch (e: NullPointerException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }, 0, 2000)
+ }
+
+ private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
+ override fun onTick(millisUntilFinished: Long) {
+
+ }
+
+ override fun onFinish() {
+ LoadingDialogHub.dismiss()
+ serialPortService?.closeSerialPort()
+ "标识器深度探测超时,请移动位置重试".show(context)
+ searchMarker()
+ }
+ }
+
+ override fun initEvent() {
+ binding.depthButton.setOnClickListener {
+ stopSearchMarker()
+ val result = DataBaseManager.get.queryMarkerById(markerId)
+ if (result.isNotEmpty()) {
+ val tag = when (result.first().markerType) {
+ "EM30" -> '7'
+ "EM50" -> '8'
+ "EM14" -> '9'
+ else -> '1'
+ }
+ if (tag == '1') {
+ "此标识器无法读取埋深!".show(this)
+ searchMarker()
+ } else {
+ LoadingDialogHub.show(this, "正在探测标识器埋深,请稍后...")
+ countDownTimer.start()
+ // 发送读取标识器埋设深度指令
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ // 发送读取标识器埋设深度指令
+ outStream.write(tag.code)
+ outStream.flush()
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ if (hex.startsWith("53")) {
+ LoadingDialogHub.dismiss()
+ countDownTimer.cancel()
+ try {
+ val depthResponse = hex.take(10).hexToString()
+ val depth = depthResponse.drop(2).toInt()
+ AlertMessageDialog.Builder().setContext(context)
+ .setTitle("温馨提示")
+ .setMessage("标识器埋深:${depth}厘米")
+ .setPositiveButton("知道了")
+ .setOnDialogButtonClickListener(object :
+ AlertMessageDialog.OnDialogButtonClickListener {
+ override fun onConfirmClick() {
+ serialPortService?.closeSerialPort()
+ searchMarker()
+ }
+ }).build().show()
+ } catch (e: WindowManager.BadTokenException) {
+ e.printStackTrace()
+ } catch (e: NumberFormatException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ })
+ }
+ } else {
+ LoadingDialogHub.dismiss()
+ "标识器未安装,安装成功后才可读取埋深!".show(this)
+ searchMarker()
+ }
+ }
+
+ binding.markerInfoButton.setOnClickListener {
+ val id = if (markerId == "") {
+ nearestMarkerId
+ } else {
+ markerId
+ }
+ //查库
+ val result = DataBaseManager.get.queryMarkerById(id)
+ if (result.isNotEmpty()) {
+ navigatePageTo(result.first().toJson())
+ } else {
+ navigatePageTo(id)
+ }
+ //查看完就把ID置空,便于下次查看最新的ID
+ markerId = ""
+ }
+ }
+
+ /**
+ * 搜索标识器
+ * */
+ private fun searchMarker() {
+ Thread.sleep(100)
+
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ searchMarkerTimer = Timer()
+ searchMarkerTimer.schedule(object : TimerTask() {
+ override fun run() {
+ outStream.write('2'.code)
+ outStream.flush()
+
+ Thread.sleep(50)
+
+ outStream.write('6'.code)
+ outStream.flush()
+ }
+ }, 0, 200)
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ 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)
+ }
+
+ //通过设置进度条表示能量值
+ 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)
+
+ 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()
+ }
+ } else {
+ val id = hex.take(20).hexToString()
+ if (id.isNumber()) {
+ markerId = id
+ handleMarker(markerId)
+ }
+ }
+ }
+ })
+ }
+
+ private fun stopSearchMarker() {
+ soundPool.autoPause()
+ searchMarkerTimer.cancel()
+ serialPortService?.closeSerialPort()
+
+ Thread.sleep(100)
+ }
+
+ /**
+ * 计算并渲染数据点。点太多采用协程计算,不然会有点卡顿。默认2s计算一次
+ * @param location 定位点(RTK获取)
+ * */
+ private fun renderDataPoint(location: AMapLocation) {
+ val longitude = location.longitude
+ val latitude = location.latitude
+ lifecycleScope.launch(Dispatchers.IO) {
+ val dataPoints = ArrayList()
+ DataBaseManager.get.loadMarkers().forEach {
+ val distance = AMapUtils.calculateLineDistance(
+ LatLng(it.lat.toDouble(), it.lng.toDouble()), LatLng(latitude, longitude)
+ )
+ val formatDistance = "%.2f".format(distance).toFloat()
+ markerPoints.add(MarkerDistanceData(it.markerId, formatDistance))
+
+ if (formatDistance <= LocaleConstant.MAX_DISTANCE) {
+ val angle = atan2(
+ (it.lat.toDouble() - latitude), (it.lng.toDouble() - longitude)
+ ) + Math.PI
+ val formatAngle = "%.2f".format(angle).toDouble()
+
+ dataPoints.add(RadarScanView.DataPoint(formatAngle, formatDistance))
+ }
+ }
+ withContext(Dispatchers.Main) {
+ binding.radarScanView.renderPointData(dataPoints,
+ object : RadarScanView.OnGetNearestPointCallback {
+ override fun getNearestPoint(point: RadarScanView.DataPoint?) {
+ if (point == null) {
+ binding.distanceValueView.text = "大于5.5m"
+ binding.distancePgBar.progress = 100
+ } else {
+ binding.distanceValueView.text = "${point.distance}m"
+ val progress = if (point.distance > LocaleConstant.MAX_DISTANCE) {
+ 100
+ } else {
+ (point.distance / LocaleConstant.MAX_DISTANCE) * 100
+ }
+ binding.distancePgBar.progress = progress.toInt()
+ }
+ }
+ }
+ )
+ }
+ }
+ }
+
+ override fun initViewBinding(): ActivitySearchMarkerBinding {
+ return ActivitySearchMarkerBinding.inflate(layoutInflater)
+ }
+
+ override fun observeRequestState() {
+
+ }
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ private fun handleMarker(id: String) {
+ binding.depthButton.isEnabled = true
+ binding.depthButton.setTextColor(Color.WHITE)
+ binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
+ binding.markerInfoButton.isEnabled = true
+ binding.markerInfoButton.setTextColor(Color.WHITE)
+ binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)
+
+ binding.searchResultView.text = "已检测到标识器"
+ binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
+ binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)
+
+ //自动上传标识器
+ if (isExecuteTask) {
+ val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
+ val taskCode = SaveKeyValues.getValue(LocaleConstant.TASK_CODE, "") as String
+ val taskMarkerLocalBean = DataBaseManager.get.queryTaskMarkerById(
+ taskId, taskCode, id, "0"
+ )
+ taskMarkerLocalBean?.apply {
+ taskViewModel.uploadMarker(context, this)
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ //注册加速度传感器监听
+ val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
+ sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)
+
+ //注册磁场传感器监听
+ val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
+ sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL)
+ }
+
+ override fun onPause() {
+ super.onPause()
+ sensorManager.unregisterListener(this)
+ }
+
+ override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
+ //精度发生变化时触发
+ }
+
+ override fun onSensorChanged(event: SensorEvent?) {
+ //值发生变化时触发
+ val type = event?.sensor?.type
+
+ if (type == Sensor.TYPE_ACCELEROMETER) {
+ gravity = event.values
+ } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
+ geomagnetic = event.values
+ }
+
+ if (gravity == null || geomagnetic == null) {
+ return
+ }
+
+ if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
+ SensorManager.getOrientation(rotationMatrix, valueArray)
+
+ val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt()
+ //更新罗盘角度
+ binding.radarScanView.setDegreeValue(degree)
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ stopSearchMarker()
+ locationTool.stopLocation()
+ unbindService(serviceConnection)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_install_marker.xml b/app/src/main/res/layout/activity_install_marker.xml
new file mode 100644
index 0000000..65c2262
--- /dev/null
+++ b/app/src/main/res/layout/activity_install_marker.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
index 458f3fb..ca7de13 100644
--- a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
+++ b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
@@ -4,6 +4,7 @@
import com.casic.detector.common.greendao.DaoMaster
import com.casic.detector.common.greendao.DaoSession
import com.casic.detector.common.uart.SerialPort
+import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.SaveKeyValues
import java.io.File
import java.io.IOException
@@ -13,23 +14,12 @@
class BaseApplication : Application() {
private val kTag = "BaseApplication"
- private var serialPorts: ArrayList? = null
+ private var serialPorts = ArrayList()
- @Throws(SecurityException::class, IOException::class, InvalidParameterException::class)
- fun getSerialPorts(): ArrayList? {
- serialPorts = ArrayList()
- /**
- * Open the serial port
- * */
- serialPorts?.apply {
- add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
- add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
- }
- return serialPorts
- }
+ fun getSerialPorts(): ArrayList = serialPorts
fun closeSerialPort() {
- serialPorts?.forEach {
+ serialPorts.forEach {
it.closeSerialPort()
}
}
@@ -49,6 +39,22 @@
val devOpenHelper = DaoMaster.DevOpenHelper(this, "Detector_Common.db", null)
val daoMaster = DaoMaster(devOpenHelper.writableDatabase)
daoSession = daoMaster.newSession()
+
+ /**
+ * Open the serial port
+ * */
+ try {
+ serialPorts.apply {
+ add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
+ add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
+ }
+ } catch (e: SecurityException) {
+ "您没有串口的读写权限!".show(this)
+ } catch (e: IOException) {
+ "因为不明原因,串口无法打开!".show(this)
+ } catch (e: InvalidParameterException) {
+ "请检查串口!".show(this)
+ }
}
fun getDaoSession(): DaoSession {
diff --git a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt b/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
deleted file mode 100644
index 297ac02..0000000
--- a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.casic.detector.common.base
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.lifecycleScope
-import androidx.viewbinding.ViewBinding
-import com.pengxh.kt.lite.extensions.show
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.IOException
-import java.io.OutputStream
-import java.security.InvalidParameterException
-
-
-abstract class SerialPortActivity : AppCompatActivity() {
-
- protected lateinit var binding: VB
-
- lateinit var out: OutputStream
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = initViewBinding()
- setContentView(binding.root)
- setupTopBarLayout()
- initOnCreate(savedInstanceState)
- observeRequestState()
- initEvent()
-
- try {
- val serialPorts = BaseApplication.get().getSerialPorts()
- //读
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[0].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[1].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- //写
- serialPorts?.apply {
- out = this[0].outputStream
- }
- } catch (e: SecurityException) {
- "您没有串口的读写权限!".show(this)
- } catch (e: IOException) {
- "因为不明原因,串口无法打开!".show(this)
- } catch (e: InvalidParameterException) {
- "请检查串口!".show(this)
- }
- }
-
- /**
- * 初始化ViewBinding
- */
- abstract fun initViewBinding(): VB
-
- /**
- * 特定页面定制沉浸式状态栏
- */
- abstract fun setupTopBarLayout()
-
- /**
- * 初始化默认数据
- */
- abstract fun initOnCreate(savedInstanceState: Bundle?)
-
- /**
- * 数据请求状态监听
- */
- abstract fun observeRequestState()
-
- /**
- * 初始化业务逻辑
- */
- abstract fun initEvent()
-
- /**
- * 串口读数,已经切回主线程
- * */
- abstract fun onDataReceived(buffer: ByteArray)
-
- override fun onDestroy() {
- super.onDestroy()
- BaseApplication.get().closeSerialPort()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
new file mode 100644
index 0000000..b06a068
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
@@ -0,0 +1,9 @@
+package com.casic.detector.common.callback
+
+import java.io.OutputStream
+
+interface OnSerialPortDataListener {
+ fun write(outStream: OutputStream)
+
+ fun onDataReceived(buffer: ByteArray)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
new file mode 100644
index 0000000..b1685d5
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
@@ -0,0 +1,6 @@
+package com.casic.detector.common.model
+
+/**
+ * 标识器与当前定位的数据
+ * */
+data class MarkerDistanceData(var markerId: String, var distance: Float)
diff --git a/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
new file mode 100644
index 0000000..090f604
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
@@ -0,0 +1,104 @@
+package com.casic.detector.common.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+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.base.BaseApplication
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.utils.GpioManager
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.IOException
+
+class SerialPortService : Service(), LifecycleOwner {
+
+ private val kTag = "SerialPortService"
+ private val registry = LifecycleRegistry(this)
+ private val gpioManager by lazy { GpioManager() }
+ private val serialPorts by lazy { BaseApplication.get().getSerialPorts() }
+ private var gpioState = ""
+
+ override fun getLifecycle(): Lifecycle {
+ return registry
+ }
+
+ override fun onBind(intent: Intent?): IBinder {
+ return ServiceBinder()
+ }
+
+ inner class ServiceBinder : Binder() {
+ fun getSerialPortService(): SerialPortService {
+ return this@SerialPortService
+ }
+ }
+
+ fun openSerialPort(listener: OnSerialPortDataListener) {
+ //调高串口电位
+ gpioManager.setGpioHigh("18")
+ gpioState = "1"
+ Log.d(kTag, "openSerialPort: 调高串口电位")
+
+ Thread.sleep(100)
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ //写
+ listener.write(this[0].outputStream)
+ val stream = this[0].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ val stream = this[1].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+ }
+
+ fun closeSerialPort() {
+ //降低串口电位
+ gpioManager.setGpioLow("18")
+ gpioState = "0"
+ Log.d(kTag, "closeSerialPort: 降低串口电位")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
new file mode 100644
index 0000000..b50aaaf
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
@@ -0,0 +1,548 @@
+package com.casic.detector.common.view
+
+import android.app.DatePickerDialog
+import android.content.ComponentName
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
+import android.media.AudioAttributes
+import android.media.SoundPool
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.IBinder
+import android.util.Log
+import android.view.View
+import android.widget.AdapterView
+import androidx.lifecycle.ViewModelProvider
+import com.amap.api.location.AMapLocation
+import com.casic.detector.common.R
+import com.casic.detector.common.adapter.EditableImageAdapter
+import com.casic.detector.common.bean.MarkerLocalBean
+import com.casic.detector.common.callback.OnGetLocationListener
+import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.databinding.ActivityInstallMarkerBinding
+import com.casic.detector.common.extensions.compressImage
+import com.casic.detector.common.extensions.getDefaultValue
+import com.casic.detector.common.extensions.hexToString
+import com.casic.detector.common.extensions.isNumber
+import com.casic.detector.common.extensions.setDefaultValue
+import com.casic.detector.common.extensions.show
+import com.casic.detector.common.extensions.toColor
+import com.casic.detector.common.extensions.toHex
+import com.casic.detector.common.extensions.toObjectType
+import com.casic.detector.common.service.SerialPortService
+import com.casic.detector.common.utils.DataBaseManager
+import com.casic.detector.common.utils.LocaleConstant
+import com.casic.detector.common.utils.LocationTool
+import com.casic.detector.common.vm.TaskViewModel
+import com.luck.picture.lib.basic.PictureSelector
+import com.luck.picture.lib.config.SelectMimeType
+import com.luck.picture.lib.entity.LocalMedia
+import com.luck.picture.lib.interfaces.OnResultCallbackListener
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.appendZero
+import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.extensions.dateToTimestamp
+import com.pengxh.kt.lite.extensions.navigatePageTo
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.extensions.timestampToCompleteDate
+import com.pengxh.kt.lite.extensions.timestampToTime
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.LoadState
+import com.pengxh.kt.lite.utils.LoadingDialogHub
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import java.io.File
+import java.io.OutputStream
+import java.util.Calendar
+import java.util.Date
+
+class InstallMarkerActivity : KotlinBaseActivity() {
+
+ private val kTag = "InstallMarkerActivity"
+ private val context = this
+ private val calendar by lazy { Calendar.getInstance() }
+ private val locationTool by lazy { LocationTool(this) }
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val realPaths = ArrayList() //真实图片路径
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var soundResourceId = 0
+ private var serialPortService: SerialPortService? = null
+ private lateinit var imageAdapter: EditableImageAdapter
+
+ override fun initEvent() {
+ //返回
+ binding.titleInclude.leftBackView.setOnClickListener {
+ soundPool.autoPause()
+ finish()
+ }
+
+ binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
+ object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(
+ parent: AdapterView<*>?, view: View?, position: Int, id: Long
+ ) {
+ when (position) {
+ 0 -> {
+ //显示管线属性
+ binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 1 -> {
+ //显示管线附属物属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 2 -> {
+ //显示管线特征点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 3 -> {
+ //显示交叉穿越点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.VISIBLE
+ }
+ }
+ }
+
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+
+ }
+ }
+
+ //安装
+ binding.installButton.setOnClickListener {
+ val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+ if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
+ when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
+ "管线" -> "请输入管线种类!".show(this)
+ "管线附属物" -> "请输入附属物名称!".show(this)
+ "管线特征管点" -> "请输入特征管点!".show(this)
+ "交叉穿越点" -> "请输入上层管种类!".show(this)
+ }
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
+ if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
+ "请输入管径".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
+ "请输入埋深".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
+ if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
+ "请输入下层管管径".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.areaView.text.isNullOrBlank()) {
+ "请输入所属区域".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.lineView.text.isNullOrBlank()) {
+ "请输入所属线路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.roadView.text.isNullOrBlank()) {
+ "请输入所属道路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
+ "请选择建设年代".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
+ "请输入权属单位".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
+ "请先读取标识器获取ID".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
+ "请输入标识器埋深".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
+ "请输入标识器安装部门".show(this)
+ return@setOnClickListener
+ }
+
+ //先存本地再上传服务器
+ saveMarkerInLocal()
+
+ taskViewModel.installLabel(
+ this, companyId,
+ binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
+ binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
+ "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.areaView.text.toString(),
+ binding.objectInclude.lineView.text.toString(),
+ binding.objectInclude.roadView.text.toString(),
+ binding.objectInclude.constructDateView.text.toString(),
+ binding.objectInclude.ownerView.text.toString(),
+ objectId,
+ binding.identifierInclude.identifierIdView.text.toString(),
+ binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
+ "${binding.identifierInclude.identifierDeepView.text}mm",
+ binding.identifierInclude.personDeptView.text.toString(),
+ binding.identifierInclude.installTimeView.text.toString(),
+ binding.identifierInclude.lngView.text.toString(),
+ binding.identifierInclude.latView.text.toString(),
+ binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
+ binding.remarkView.text.toString(),
+ realPaths
+ )
+
+ //保存默认值
+ "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
+ "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
+ "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
+ "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
+ "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
+ "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
+ "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
+ "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
+ "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
+ "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
+ "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
+ }
+
+ //读标识器
+ binding.readMarkerButton.setOnClickListener {
+ LoadingDialogHub.show(this, "标识器读取中,请稍后...")
+ countDownTimer.start()
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ outStream.write('2'.code)
+ outStream.flush()
+
+ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
+ binding.readMarkerButton.isEnabled = false
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ Log.d(kTag, hex)
+ val markerId = hex.take(20).hexToString()
+ if (markerId.isNumber()) {
+ countDownTimer.cancel()
+ cancelLoadingView()
+ binding.readMarkerButton.isEnabled = true
+ binding.identifierInclude.identifierIdView.text = markerId
+ }
+ }
+ })
+ }
+ }
+
+ /**
+ * 搜索标识器超时倒计时
+ * */
+ private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
+ override fun onTick(millisUntilFinished: Long) {
+
+ }
+
+ override fun onFinish() {
+ cancelLoadingView()
+ "读取此标识器ID超时,请重试".show(context)
+ binding.readMarkerButton.isEnabled = true
+ }
+ }
+
+ private fun cancelLoadingView() {
+ LoadingDialogHub.dismiss()
+ soundPool.autoPause()
+ serialPortService?.closeSerialPort()
+ }
+
+ private fun saveMarkerInLocal() {
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+
+ val marker = MarkerLocalBean()
+ marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
+ marker.pipelineType = binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
+ marker.pipelineMaterial =
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
+ marker.pipelineDiameter = "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
+ marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
+ marker.underlyingPipelineType =
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
+ marker.underlyingPipelineMaterial =
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
+ marker.underlyingPipelineDiameter =
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
+ marker.underlyingPipelineDepth =
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
+ marker.buryMethod =
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
+ marker.area = binding.objectInclude.areaView.text.toString()
+ marker.line = binding.objectInclude.lineView.text.toString()
+ marker.road = binding.objectInclude.roadView.text.toString()
+ marker.constructTime = binding.objectInclude.constructDateView.text.toString()
+ marker.owner = binding.objectInclude.ownerView.text.toString()
+ marker.objectId = objectId
+ marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
+ marker.markerType = binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
+ marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
+ marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
+ marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
+ marker.lng = binding.identifierInclude.lngView.text.toString()
+ marker.lat = binding.identifierInclude.latView.text.toString()
+ marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
+ marker.remark = binding.remarkView.text.toString()
+ marker.imagePath = realPaths.toJson()
+
+ DataBaseManager.get.saveMarkerInLocale(marker)
+ }
+
+ private fun takePicture() {
+ PictureSelector.create(this).openCamera(SelectMimeType.ofImage())
+ .forResult(object : OnResultCallbackListener {
+ override fun onResult(result: ArrayList?) {
+ if (result == null) {
+ "拍照失败,请重试".show(context)
+ return
+ }
+ analyticalSelectResults(result[0])
+ }
+
+ override fun onCancel() {
+
+ }
+ })
+ }
+
+ private fun analyticalSelectResults(result: LocalMedia) {
+ //压缩图片
+ result.realPath.compressImage(context, object : OnImageCompressListener {
+ override fun onSuccess(file: File) {
+ realPaths.add(file.absolutePath)
+ imageAdapter.setupImage(realPaths)
+ }
+
+ override fun onError(e: Throwable) {
+ e.printStackTrace()
+ }
+ })
+ }
+
+ 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?) {
+ //在连接正常关闭的情况下不会被调用, 只在Service被破坏了或者被杀死的时候调用
+ }
+ }
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ //绑定串口通信服务
+ Intent(this, SerialPortService::class.java).also {
+ bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
+ }
+
+ locationTool.getCurrentLocation(true, object : OnGetLocationListener {
+ override fun onAMapLocationGet(location: AMapLocation?) {
+ if (location != null) {
+ binding.identifierInclude.lngView.text = location.longitude.toString()
+ binding.identifierInclude.latView.text = location.latitude.toString()
+ } else {
+ "当前位置信号差,无法获取定位".show(context)
+ }
+ }
+ })
+ soundResourceId = soundPool.load(this, R.raw.ring3, 1)
+
+ //初始化数据
+ initDefaultData()
+ }
+
+ override fun initViewBinding(): ActivityInstallMarkerBinding {
+ return ActivityInstallMarkerBinding.inflate(layoutInflater)
+ }
+
+ override fun observeRequestState() {
+ taskViewModel.loadState.observe(this) {
+ when (it) {
+ LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...")
+
+ LoadState.Success -> {
+ LoadingDialogHub.dismiss()
+ clearDefaultData()
+ "安装成功".show(this)
+ }
+
+ else -> LoadingDialogHub.dismiss()
+ }
+ }
+ }
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ private fun initDefaultData() {
+ binding.titleInclude.titleView.text = "安装新标识器"
+ binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
+
+ imageAdapter = EditableImageAdapter(this, 3, 3)
+ binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
+
+ //设置默认值
+ binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
+ binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
+ binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
+ binding.objectInclude.areaView.setText("areaView".getDefaultValue())
+ binding.objectInclude.lineView.setText("lineView".getDefaultValue())
+ binding.objectInclude.roadView.setText("roadView".getDefaultValue())
+ binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
+ binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
+ binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
+
+ /**************************************************************************************/
+ binding.objectInclude.objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0)
+ binding.objectInclude.pipeInclude.materialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeAttachInclude.attachSpinner.show(
+ this, LocaleConstant.ATTACH_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
+ this, LocaleConstant.FEATURE_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeInclude.buryTypeSpinner.show(
+ this, LocaleConstant.BURY_METHOD_ARRAY, 0
+ )
+ binding.objectInclude.constructDateView.setOnClickListener {
+ val datePicker = DatePickerDialog(
+ this, null,
+ calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH),
+ calendar.get(Calendar.DAY_OF_MONTH)
+ )
+ datePicker.show()
+
+ datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
+ val year = datePicker.datePicker.year
+ val month = datePicker.datePicker.month + 1
+ val day = datePicker.datePicker.dayOfMonth
+ val selectedDate = String.format(
+ "%s-%s-%s", year, month.appendZero(), day.appendZero()
+ )
+
+ //当前时间
+ val current = System.currentTimeMillis().timestampToTime()
+ val today = "$selectedDate $current".dateToTimestamp()
+ if (Date(today).after(Date())) {
+ "建设年代不能早于当前日期".show(context)
+ } else {
+ datePicker.dismiss()
+ binding.objectInclude.constructDateView.text = selectedDate
+ }
+ }
+ }
+ binding.identifierInclude.identifierTypeSpinner.show(
+ this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
+ )
+ binding.identifierInclude.installTimeView.text =
+ System.currentTimeMillis().timestampToCompleteDate()
+ binding.identifierInclude.colorSpinner.show(this, LocaleConstant.COLOR_ARRAY, 0)
+
+ imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
+ override fun onAddImageClick() {
+ takePicture()
+ }
+
+ override fun onItemClick(position: Int) {
+ if (realPaths[position].isEmpty()) {
+ "图片加载失败,无法查看大图".show(context)
+ } else {
+ navigatePageTo(position, realPaths)
+ }
+ }
+
+ override fun onItemLongClick(view: View?, position: Int) {
+ imageAdapter.deleteImage(position)
+ }
+ })
+ }
+
+ //清除默认数据
+ private fun clearDefaultData() {
+ "markerObjectTypeView".setDefaultValue("")
+ "pipelineDiameterView".setDefaultValue("")
+ "buryDeepView".setDefaultValue("")
+ "bottomPipeDiameterView".setDefaultValue("")
+ "bottomPointDeepView".setDefaultValue("")
+ "areaView".setDefaultValue("")
+ "lineView".setDefaultValue("")
+ "roadView".setDefaultValue("")
+ "ownerView".setDefaultValue("")
+ "identifierDeepView".setDefaultValue("")
+ "personDeptView".setDefaultValue("")
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ soundPool.autoPause()
+ locationTool.stopLocation()
+ 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 1dac658..f949269 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,31 +1,25 @@
package com.casic.detector.common.view
-import android.app.DatePickerDialog
-import android.app.Dialog
+import android.content.ComponentName
import android.content.Context
-import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
-import android.hardware.Sensor
-import android.hardware.SensorEvent
-import android.hardware.SensorEventListener
-import android.hardware.SensorManager
import android.media.AudioAttributes
import android.media.SoundPool
import android.os.Bundle
-import android.os.CountDownTimer
+import android.os.IBinder
import android.util.Log
import android.view.KeyEvent
import android.view.View
-import android.widget.AdapterView
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.amap.api.location.AMapLocation
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
-import com.amap.api.maps.AMapUtils
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.CoordinateConverter
import com.amap.api.maps.model.BitmapDescriptorFactory
@@ -34,38 +28,29 @@
import com.amap.api.maps.model.MarkerOptions
import com.amap.api.maps.model.MyLocationStyle
import com.casic.detector.common.R
-import com.casic.detector.common.adapter.EditableImageAdapter
-import com.casic.detector.common.base.SerialPortActivity
+import com.casic.detector.common.base.BaseApplication
import com.casic.detector.common.bean.MarkerLocalBean
import com.casic.detector.common.bean.TaskLocalBean
import com.casic.detector.common.callback.OnGetLocationListener
-import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
import com.casic.detector.common.cluster.ClusterItem
import com.casic.detector.common.cluster.ClusterOverlay
import com.casic.detector.common.cluster.RegionItem
import com.casic.detector.common.databinding.ActivityMainBinding
-import com.casic.detector.common.databinding.DialogInstallMarkerBinding
-import com.casic.detector.common.databinding.DialogSearchMarkerNewBinding
import com.casic.detector.common.extensions.appendDownloadUrl
-import com.casic.detector.common.extensions.compressImage
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.getDefaultValue
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.setDefaultValue
-import com.casic.detector.common.extensions.show
-import com.casic.detector.common.extensions.toColor
import com.casic.detector.common.extensions.toHex
-import com.casic.detector.common.extensions.toObjectType
import com.casic.detector.common.model.TaskDetailLocalModel
import com.casic.detector.common.model.TaskModel
+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.GpioManager
import com.casic.detector.common.utils.LocaleConstant
import com.casic.detector.common.utils.LocationTool
import com.casic.detector.common.utils.NtripAuthorizationCreator
@@ -77,26 +62,15 @@
import com.casic.detector.common.vm.TaskViewModel
import com.casic.detector.common.widgets.MarkerDetailDialog
import com.casic.detector.common.widgets.QueryMarkerDialog
-import com.casic.detector.common.widgets.RadarScanView
import com.casic.detector.common.widgets.SamplePopupWindow
-import com.luck.picture.lib.basic.PictureSelector
-import com.luck.picture.lib.config.SelectMimeType
-import com.luck.picture.lib.entity.LocalMedia
-import com.luck.picture.lib.interfaces.OnResultCallbackListener
-import com.pengxh.kt.lite.extensions.appendZero
-import com.pengxh.kt.lite.extensions.binding
-import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertDrawable
import com.pengxh.kt.lite.extensions.createDownloadFileDir
-import com.pengxh.kt.lite.extensions.dateToTimestamp
import com.pengxh.kt.lite.extensions.dp2px
-import com.pengxh.kt.lite.extensions.getSystemService
-import com.pengxh.kt.lite.extensions.initDialogLayoutParams
import com.pengxh.kt.lite.extensions.isNetworkConnected
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.extensions.timestampToCompleteDate
-import com.pengxh.kt.lite.extensions.timestampToTime
import com.pengxh.kt.lite.extensions.toJson
import com.pengxh.kt.lite.utils.FileDownloadManager
import com.pengxh.kt.lite.utils.LoadState
@@ -108,60 +82,41 @@
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
import io.netty.buffer.Unpooled
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
+import java.io.OutputStream
import java.nio.charset.StandardCharsets
-import java.util.Calendar
-import java.util.Date
import java.util.Timer
import java.util.TimerTask
-import kotlin.math.atan2
-class MainActivity : SerialPortActivity(), SensorEventListener,
- OnSocketConnectListener {
+class MainActivity : KotlinBaseActivity(), OnSocketConnectListener {
private val kTag = "MainActivity"
private val context = this
private val samplePopupWindow by lazy { SamplePopupWindow(this) }
private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) }
private val backDrawables by lazy { HashMap() }
- private val installDialog by lazy { InstallMarkerDialog(this) }
- private val searchNewDialog by lazy { SearchMarkerNewDialog(this) }
private val detailDialog by lazy { MarkerDetailDialog(this) }
private val locationTool by lazy { LocationTool(this) }
- private val rotationMatrix = FloatArray(9)//旋转矩阵缓存
- private val valueArray = FloatArray(3)//方位角数值
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
private var clickTime: Long = 0
private var markers = ArrayList()
private var clusterOverlay: ClusterOverlay? = null
private var isFreeTask = false
private var freeTaskTitle = ""
private var ids = HashSet()
- private var signalTask: TimerTask? = null
- private var energyTask: TimerTask? = null
- private var searchMarkerTimer: Timer? = null
private var freeTaskId: String? = null
- private var gravity: FloatArray? = null
- private var geomagnetic: FloatArray? = null
private var connectState = ConnectState.CLOSED
private var socketClient: SocketClient? = null
- private lateinit var aMap: AMap
- private lateinit var sensorManager: SensorManager
-
- /***inner class 需要用到*****start*/
- private val gpioManager by lazy { GpioManager() }
- private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
- private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
- .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
- private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var serialPortService: SerialPortService? = null
+ private var searchMarkerTimer: Timer? = null
private var soundResourceId = 0
- private var slowSoundResourceId = 0
- private var fastSoundResourceId = 0
private var isExecuteTask = false
-
- /***inner class 需要用到*****end*/
+ private lateinit var aMap: AMap
override fun initViewBinding(): ActivityMainBinding {
return ActivityMainBinding.inflate(layoutInflater)
@@ -171,10 +126,26 @@
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)
+ }
+
soundResourceId = soundPool.load(this, R.raw.ring3, 1)
- slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
- fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)
RtkLocationTool.getCurrentLocation(this) {
if (connectState == ConnectState.SUCCESS) {
@@ -192,8 +163,6 @@
samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES)
samplePopupWindow.setBackgroundDrawable(null)
- sensorManager = getSystemService()!!
-
//task网络请求监听
taskViewModel.markerFileResult.observe(this) {
if (it.isSuccess) {
@@ -316,9 +285,6 @@
//安装。上传,然后存入本地库
binding.installButton.setOnClickListener {
- /**
- * 改为Dialog方式,避免频繁打开/关闭串口
- * */
if (isFreeTask) {
AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示")
.setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能")
@@ -329,7 +295,7 @@
}
}).build().show()
} else {
- installDialog.show()
+ navigatePageTo()
}
}
@@ -449,8 +415,6 @@
//探测
binding.detectionButton.setOnClickListener {
/**
- * 改为Dialog方式,避免频繁打开/关闭串口
- *
* 如果开启自由巡检就不让探测
* */
if (isFreeTask) {
@@ -463,7 +427,12 @@
}
}).build().show()
} else {
- searchNewDialog.show()
+ val flag = if (isExecuteTask) {
+ "1"
+ } else {
+ "0"
+ }
+ navigatePageTo(flag)
}
}
@@ -476,14 +445,8 @@
override fun onConfirmClick() {
isFreeTask = false
soundPool.autoPause()
-
- //停止信号和ID搜索定时器
- signalTask?.cancel()
- energyTask?.cancel()
searchMarkerTimer?.cancel()
-
- //降低串口电位
- gpioManager.setGpioLow("18")
+ serialPortService?.closeSerialPort()
binding.stopFreeTaskButton.visibility = View.GONE
if (freeTaskId.isNullOrBlank()) {
@@ -527,110 +490,79 @@
}
private fun openSerialPort() {
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- isFreeTask = true
- //自由巡检
- signalTask = object : TimerTask() {
- override fun run() {
- out.write('2'.code)
- out.flush()
- }
- }
-
- energyTask = object : TimerTask() {
- override fun run() {
- out.write('6'.code)
- out.flush()
- }
- }
-
- searchMarkerTimer = Timer()
- searchMarkerTimer?.apply {
- schedule(signalTask, 0, 200)
- schedule(energyTask, 0, 251)
- }
-
binding.stopFreeTaskButton.visibility = View.VISIBLE
- }
+ isFreeTask = true
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ searchMarkerTimer = Timer()
+ searchMarkerTimer?.schedule(object : TimerTask() {
+ override fun run() {
+ outStream.write('2'.code)
+ outStream.flush()
- override fun onDataReceived(buffer: ByteArray) {
- val hex = buffer.toHex()
-// Log.d(kTag, "$kTag => $hex")
- if (searchNewDialog.isDetectMarker) {
- searchNewDialog.bindingValue(hex)
- } else if (installDialog.isReadMarker) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- installDialog.bindingValue(markerId)
+ Thread.sleep(50)
+
+ outStream.write('6'.code)
+ outStream.flush()
+ }
+ }, 0, 200)
}
- } else if (isFreeTask) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- //只响一次,因为探测频率高,所以依旧是连续的报警声
- soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
- //添加地图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))
- )
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ if (hex.startsWith("4E")) {
+ //只响一次,因为探测频率高,所以依旧是连续的报警声
+ soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
+
+ 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()
}
}
- 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()
+ 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 (hex.startsWith("4E")) {
- val energyResponse = hex.take(10).hexToString()
- try {
- val energy = energyResponse.substring(1).toInt()
- if (energy <= 500 && detailDialog.isShowing) {
- detailDialog.dismiss()
- }
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- }
- }
+ })
}
override fun observeRequestState() {
taskViewModel.loadState.observe(this) {
when (it) {
- LoadState.Loading -> {
- if (installDialog.isInstallMarker) {
- LoadingDialogHub.show(this, "标识器安装中,请稍后...")
- } else {
- LoadingDialogHub.show(this, "提交工单中,请稍后")
- }
- }
-
- LoadState.Success -> {
- if (installDialog.isInstallMarker) {
- installDialog.clearDefaultData()
- installDialog.dismiss()
- "${installDialog.markerId}安装成功".show(this)
- }
- LoadingDialogHub.dismiss()
- }
+ LoadState.Loading -> LoadingDialogHub.show(this, "提交工单中,请稍后")
else -> LoadingDialogHub.dismiss()
}
@@ -939,32 +871,6 @@
} else super.onKeyDown(keyCode, event)
}
- override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
- //精度发生变化时触发
- }
-
- override fun onSensorChanged(event: SensorEvent?) {
- //值发生变化时触发
- val type = event?.sensor?.type
-
- if (type == Sensor.TYPE_ACCELEROMETER) {
- gravity = event.values
- } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
- geomagnetic = event.values
- }
-
- if (gravity == null || geomagnetic == null) {
- return
- }
-
- if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
- SensorManager.getOrientation(rotationMatrix, valueArray)
-
- val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt()
- searchNewDialog.updateDegreeValue(degree)
- }
- }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
@@ -978,14 +884,6 @@
showLabelsOnMap()
}
- //注册加速度传感器监听
- val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
- sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)
-
- //注册磁场传感器监听
- val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
- sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL)
-
//取缓存
val remoteHost = SaveKeyValues.getValue(
LocaleConstant.RTK_SERVER, "203.107.45.154"
@@ -995,20 +893,20 @@
) as String
//连接千寻RTK服务器
- lifecycleScope.launch(Dispatchers.IO) {
- if (socketClient != null) {
- socketClient?.disconnect()
- delay(3000)
- }
-
- socketClient = SocketClient.Builder()
- .setHostname(remoteHost)
- .setPort(remotePort.toInt())
- .setTimeout(5000)
- .setOnSocketListener(this@MainActivity)
- .build()
- socketClient?.connect()
- }
+// lifecycleScope.launch(Dispatchers.IO) {
+// if (socketClient != null) {
+// socketClient?.disconnect()
+// delay(3000)
+// }
+//
+// socketClient = SocketClient.Builder()
+// .setHostname(remoteHost)
+// .setPort(remotePort.toInt())
+// .setTimeout(5000)
+// .setOnSocketListener(this@MainActivity)
+// .build()
+// socketClient?.connect()
+// }
}
override fun onMessageResponse(data: ByteArray) {
@@ -1021,12 +919,12 @@
val result = String(data, StandardCharsets.UTF_8)
Log.d(kTag, "onMessageResponse: $result")
if (result.contains("ICY 200 OK")) {
- "高精度定位服务器连接成功".show(this)
+ "高精度定位服务连接成功".show(this)
}
} else {
"收到千寻数据返回,长度:${data.size}".show(this)
- out.write(data)
- out.flush()
+// out.write(data)
+// out.flush()
}
}
@@ -1061,7 +959,6 @@
override fun onPause() {
super.onPause()
binding.mapView.onPause()
- sensorManager.unregisterListener(this)
}
override fun onSaveInstanceState(outState: Bundle) {
@@ -1072,794 +969,11 @@
override fun onDestroy() {
super.onDestroy()
binding.mapView.onDestroy()
- soundPool.release()
+ soundPool.autoPause()
+ searchMarkerTimer?.cancel()
+ serialPortService?.closeSerialPort()
locationTool.stopLocation()
- //降低串口电位
- gpioManager.setGpioLow("18")
+ unbindService(serviceConnection)
+ BaseApplication.get().closeSerialPort()
}
-
- /**安装标识器对话框******************************************************************************/
- inner class InstallMarkerDialog(private val context: Context) : Dialog(context) {
-
- private val binding: DialogInstallMarkerBinding by binding()
- private val calendar by lazy { Calendar.getInstance() }
- private val realPaths = ArrayList() //真实图片路径
- private lateinit var imageAdapter: EditableImageAdapter
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
-
- var isReadMarker = false
- var isInstallMarker = false
- var markerId = ""
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
-
- //初始化数据
- initDefaultData()
-
- //返回
- binding.titleInclude.leftBackView.setOnClickListener {
- soundPool.autoPause()
- dismiss()
- }
-
- binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
- object : AdapterView.OnItemSelectedListener {
- override fun onItemSelected(
- parent: AdapterView<*>?, view: View?, position: Int, id: Long
- ) {
- when (position) {
- 0 -> {
- //显示管线属性
- binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 1 -> {
- //显示管线附属物属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 2 -> {
- //显示管线特征点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 3 -> {
- //显示交叉穿越点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility =
- View.VISIBLE
- }
- }
- }
-
- override fun onNothingSelected(parent: AdapterView<*>?) {
-
- }
- }
-
- //安装
- binding.installButton.setOnClickListener {
- val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
- if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
- when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
- "管线" -> "请输入管线种类!".show(context)
- "管线附属物" -> "请输入附属物名称!".show(context)
- "管线特征管点" -> "请输入特征管点!".show(context)
- "交叉穿越点" -> "请输入上层管种类!".show(context)
- }
- return@setOnClickListener
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
- if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
- "请输入管径".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
- "请输入埋深".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
- if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
- "请输入下层管管径".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.areaView.text.isNullOrBlank()) {
- "请输入所属区域".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.lineView.text.isNullOrBlank()) {
- "请输入所属线路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.roadView.text.isNullOrBlank()) {
- "请输入所属道路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
- "请选择建设年代".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
- "请输入权属单位".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
- "请先读取标识器获取ID".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
- "请输入标识器埋深".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
- "请输入标识器安装部门".show(context)
- return@setOnClickListener
- }
-
- //先存本地再上传服务器
- saveMarkerInLocal()
-
- isInstallMarker = true
- taskViewModel.installLabel(
- context,
- companyId,
- binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
- "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
- binding.objectInclude.areaView.text.toString(),
- binding.objectInclude.lineView.text.toString(),
- binding.objectInclude.roadView.text.toString(),
- binding.objectInclude.constructDateView.text.toString(),
- binding.objectInclude.ownerView.text.toString(),
- objectId,
- binding.identifierInclude.identifierIdView.text.toString(),
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
- "${binding.identifierInclude.identifierDeepView.text}mm",
- binding.identifierInclude.personDeptView.text.toString(),
- binding.identifierInclude.installTimeView.text.toString(),
- binding.identifierInclude.lngView.text.toString(),
- binding.identifierInclude.latView.text.toString(),
- binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
- binding.remarkView.text.toString(),
- realPaths
- )
-
- //保存默认值
- "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
- "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
- "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
- "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
- "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
- "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
- "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
- "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
- "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
- "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
- "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
- }
-
- //读标识器
- binding.readMarkerButton.setOnClickListener {
- LoadingDialogHub.show(this@MainActivity, "标识器读取中,请稍后...")
- binding.readMarkerButton.isEnabled = false
-
- isReadMarker = true
-
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
-
- out.write('2'.code)
- out.flush()
-
- countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- "读取此标识器ID超时,请退出应用再试".show(context)
- }
- }
- countDownTimer.start()
- }
- }
-
- override fun show() {
- super.show()
- locationTool = LocationTool(context)
- locationTool.getCurrentLocation(true, object : OnGetLocationListener {
- override fun onAMapLocationGet(location: AMapLocation?) {
- if (location != null) {
- binding.identifierInclude.lngView.text = location.longitude.toString()
- binding.identifierInclude.latView.text = location.latitude.toString()
- } else {
- "当前位置信号差,无法获取定位".show(context)
- }
- }
- })
- }
-
- fun bindingValue(markerId: String) {
- this.markerId = markerId
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- countDownTimer.cancel()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- binding.identifierInclude.identifierIdView.text = markerId
- }
-
- override fun dismiss() {
- //降低串口电位
- gpioManager.setGpioLow("18")
- soundPool.autoPause()
- isInstallMarker = false
- locationTool.stopLocation()
- super.dismiss()
- }
-
- private fun initDefaultData() {
- binding.titleInclude.titleView.text = "安装新标识器"
- binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
-
- imageAdapter = EditableImageAdapter(context, 3, 3)
- binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
-
- //设置默认值
- binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
- binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
- binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
- binding.objectInclude.areaView.setText("areaView".getDefaultValue())
- binding.objectInclude.lineView.setText("lineView".getDefaultValue())
- binding.objectInclude.roadView.setText("roadView".getDefaultValue())
- binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
- binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
- binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
-
- /**************************************************************************************/
- binding.objectInclude.objectTypeSpinner.show(
- this@MainActivity, LocaleConstant.POINT_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.materialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeAttachInclude.attachSpinner.show(
- this@MainActivity, LocaleConstant.ATTACH_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
- this@MainActivity, LocaleConstant.FEATURE_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.buryTypeSpinner.show(
- this@MainActivity, LocaleConstant.BURY_METHOD_ARRAY, 0
- )
-
- binding.objectInclude.constructDateView.setOnClickListener {
- val datePicker = DatePickerDialog(
- context,
- null,
- calendar.get(Calendar.YEAR),
- calendar.get(Calendar.MONTH),
- calendar.get(Calendar.DAY_OF_MONTH)
- )
- datePicker.show()
-
- datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
- val year = datePicker.datePicker.year
- val month = datePicker.datePicker.month + 1
- val day = datePicker.datePicker.dayOfMonth
- val selectedDate = String.format(
- "%s-%s-%s", year, month.appendZero(), day.appendZero()
- )
-
- //当前时间
- val current = System.currentTimeMillis().timestampToTime()
- val today = "$selectedDate $current".dateToTimestamp()
- if (Date(today).after(Date())) {
- "建设年代不能早于当前日期".show(context)
- } else {
- datePicker.dismiss()
- binding.objectInclude.constructDateView.text = selectedDate
- }
- }
- }
-
- binding.identifierInclude.identifierTypeSpinner.show(
- this@MainActivity, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
- )
-
- binding.identifierInclude.installTimeView.text =
- System.currentTimeMillis().timestampToCompleteDate()
-
- binding.identifierInclude.colorSpinner.show(
- this@MainActivity, LocaleConstant.COLOR_ARRAY, 0
- )
-
- imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
- override fun onAddImageClick() {
- takePicture()
- }
-
- override fun onItemClick(position: Int) {
- if (realPaths[position].isEmpty()) {
- "图片加载失败,无法查看大图".show(context)
- } else {
- context.navigatePageTo(position, realPaths)
- }
- }
-
- override fun onItemLongClick(view: View?, position: Int) {
- imageAdapter.deleteImage(position)
- }
- })
- /**************************************************************************************/
- }
-
- //清除默认数据
- fun clearDefaultData() {
- "markerObjectTypeView".setDefaultValue("")
- "pipelineDiameterView".setDefaultValue("")
- "buryDeepView".setDefaultValue("")
- "bottomPipeDiameterView".setDefaultValue("")
- "bottomPointDeepView".setDefaultValue("")
- "areaView".setDefaultValue("")
- "lineView".setDefaultValue("")
- "roadView".setDefaultValue("")
- "ownerView".setDefaultValue("")
- "identifierDeepView".setDefaultValue("")
- "personDeptView".setDefaultValue("")
- }
-
- private fun saveMarkerInLocal() {
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
-
- val marker = MarkerLocalBean()
- marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
- marker.pipelineType =
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
- marker.pipelineMaterial =
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
- marker.pipelineDiameter =
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
- marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
- marker.underlyingPipelineType =
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
- marker.underlyingPipelineMaterial =
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
- marker.underlyingPipelineDiameter =
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
- marker.underlyingPipelineDepth =
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
- marker.buryMethod =
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
- marker.area = binding.objectInclude.areaView.text.toString()
- marker.line = binding.objectInclude.lineView.text.toString()
- marker.road = binding.objectInclude.roadView.text.toString()
- marker.constructTime = binding.objectInclude.constructDateView.text.toString()
- marker.owner = binding.objectInclude.ownerView.text.toString()
- marker.objectId = objectId
- marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
- marker.markerType =
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
- marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
- marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
- marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
- marker.lng = binding.identifierInclude.lngView.text.toString()
- marker.lat = binding.identifierInclude.latView.text.toString()
- marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
- marker.remark = binding.remarkView.text.toString()
- marker.imagePath = realPaths.toJson()
-
- DataBaseManager.get.saveMarkerInLocale(marker)
- }
-
- private fun takePicture() {
- PictureSelector.create(this@MainActivity).openCamera(SelectMimeType.ofImage())
- .forResult(object : OnResultCallbackListener {
- override fun onResult(result: java.util.ArrayList?) {
- if (result == null) {
- "拍照失败,请重试".show(context)
- return
- }
- analyticalSelectResults(result[0])
- }
-
- override fun onCancel() {
-
- }
- })
- }
-
- private fun analyticalSelectResults(result: LocalMedia) {
- //压缩图片
- result.realPath.compressImage(context, object : OnImageCompressListener {
- override fun onSuccess(file: File) {
- realPaths.add(file.absolutePath)
- imageAdapter.setupImage(realPaths)
- }
-
- override fun onError(e: Throwable) {
- e.printStackTrace()
- }
- })
- }
- }
-
- /**探测标识器新对话框****************************************************************************/
- inner class SearchMarkerNewDialog(private val context: Context) : Dialog(context) {
-
- private val taskId by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
- }
- private val taskCode by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_CODE, "") as String
- }
- private val markerPoints by lazy { ArrayList() }
- private val binding: DialogSearchMarkerNewBinding by binding()
- private var markerId = ""//实际探测出来的标识器ID
- private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID
- private lateinit var searchMarkerTimer: Timer
- private lateinit var signalTask: TimerTask
- private lateinit var energyTask: TimerTask
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
- var isDetectMarker = false
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
- binding.depthButton.setOnClickListener {
- signalTask.cancel()
- energyTask.cancel()
- searchMarkerTimer.cancel()
-
- out.write('3'.code)
- val result = DataBaseManager.get.queryMarkerById(markerId)
- if (result.isNotEmpty()) {
- val tag = when (result.first().markerType) {
- "EM30" -> '7'
- "EM50" -> '8'
- "EM14" -> '9'
- else -> '1'
- }
- if (tag == '1') {
- "此标识器无法读取埋深!".show(context)
- initTimer()
- } else {
- // 发送读取标识器埋设深度指令
- LoadingDialogHub.show(this@MainActivity, "正在测距,请稍后...")
- out.write(tag.code)
- out.flush()
- countDownTimer = object : CountDownTimer(15 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- "探测此标识器深度超时,请重试".show(context)
- initTimer()
- }
- }
- countDownTimer.start()
- }
- } else {
- "标识器未安装,安装成功后才可读取埋深!".show(context)
- initTimer()
- }
- }
-
- binding.markerInfoButton.setOnClickListener {
- val id = if (markerId == "") {
- nearestMarkerId
- } else {
- markerId
- }
- //查库
- val result = DataBaseManager.get.queryMarkerById(id)
- if (result.isNotEmpty()) {
- context.navigatePageTo(result.first().toJson())
- } else {
- context.navigatePageTo(id)
- }
- //查看完就把ID置空,便于下次查看最新的ID
- markerId = ""
- }
- }
-
- override fun show() {
- super.show()
- locationTool = LocationTool(context)
- //点位渲染,每次定位都计算当前位置与符合条件的点距离
- locationTool.getCurrentLocation(false, object : OnGetLocationListener {
- override fun onAMapLocationGet(location: AMapLocation?) {
- location?.apply {
- renderDataPoint(this)
- }
- }
- })
- }
-
- /**
- * 计算并渲染数据点。点太多采用协程计算,不然会有点卡顿
- * @param location 定位点(RTK获取)
- * */
- private fun renderDataPoint(location: AMapLocation) {
- val longitude = location.longitude
- val latitude = location.latitude
- lifecycleScope.launch(Dispatchers.IO) {
- val dataPoints = ArrayList()
- DataBaseManager.get.loadMarkers().forEach {
- val distance = AMapUtils.calculateLineDistance(
- LatLng(it.lat.toDouble(), it.lng.toDouble()), LatLng(latitude, longitude)
- )
- val formatDistance = "%.2f".format(distance).toFloat()
-
- markerPoints.add(MarkerDistanceData(it.markerId, formatDistance))
-
- if (formatDistance <= LocaleConstant.MAX_DISTANCE) {
- val angle = atan2(
- (it.lat.toDouble() - latitude), (it.lng.toDouble() - longitude)
- ) + Math.PI
- val formatAngle = "%.2f".format(angle).toDouble()
- dataPoints.add(
- RadarScanView.DataPoint(formatAngle, formatDistance)
- )
- }
- }
- withContext(Dispatchers.Main) {
- binding.radarScanView.renderPointData(dataPoints,
- object : RadarScanView.OnGetNearestPointCallback {
- override fun getNearestPoint(point: RadarScanView.DataPoint?) {
- if (point == null) {
- binding.distanceValueView.text = "大于5.5m"
- binding.distancePgBar.progress = 100
- } else {
- binding.distanceValueView.text = "${point.distance}m"
- val progress =
- if (point.distance > LocaleConstant.MAX_DISTANCE) {
- 100
- } else {
- (point.distance / LocaleConstant.MAX_DISTANCE) * 100
- }
- binding.distancePgBar.progress = progress.toInt()
- }
- }
- })
- }
- }
- }
-
- override fun onStart() {
- super.onStart()
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- initTimer()
-
- isDetectMarker = true
-
- if (isExecuteTask) {
- binding.taskStateView.visibility = View.GONE
- binding.taskStateView.isSelected = false
- } else {
- binding.taskStateView.visibility = View.VISIBLE
- binding.taskStateView.isSelected = true
- }
- }
-
- fun bindingValue(hex: String) {
- if (hex.startsWith("4E")) {
- try {
- //4E转为String为N,代表能量值
- //用能量值转动表盘
- val energyResponse = hex.take(10).hexToString()
- val energy = energyResponse.substring(1).toInt()
- if (energy >= 4000) {
- soundPool.play(fastSoundResourceId, 1f, 1f, 0, 0, 1f)
- } else {
- soundPool.play(slowSoundResourceId, 1f, 1f, 0, 0, 1f)
- }
-
- //通过设置进度条表示能量值
- binding.energyPgBar.progress = energy
- binding.energyValueView.text = "${energy}dB"
-
- if (energy <= 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.searchResultView.text = "未检测到标识器"
- binding.searchResultView.setTextColor(Color.parseColor("#8D1717"))
- binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_red)
- } else if (energy >= 4100) {
- binding.energyTipsView.text = "信号极强,接近标识器正上方"
- binding.energyTipsView.setTextColor(Color.parseColor("#428d00"))
- binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green)
-
- if (markerPoints.isEmpty()) {
- Log.d(kTag, "bindingValue: markerPoints.isEmpty()")
- return
- }
-
- //需要转一下,不然会有并发问题
- val temp = ArrayList()
- temp.addAll(markerPoints)
- temp.sortBy(MarkerDistanceData::distance)
- val nearestPoint = temp.first()
- nearestMarkerId = nearestPoint.markerId
- handleMarker(nearestMarkerId)
- } else {
- binding.energyTipsView.text = "已靠近,请继续移动位置"
- binding.energyTipsView.setTextColor(Color.parseColor("#8C5700"))
- binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow)
- }
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- } else if (hex.startsWith("53")) {
- LoadingDialogHub.dismiss()
- countDownTimer.cancel()
- try {
- val depthResponse = hex.take(10).hexToString()
- val depth = depthResponse.drop(2).toInt()
- AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示")
- .setMessage("标识器埋深:${depth}厘米").setPositiveButton("知道了")
- .setOnDialogButtonClickListener(object :
- AlertMessageDialog.OnDialogButtonClickListener {
- override fun onConfirmClick() {
- initTimer()
- }
- }).build().show()
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- } else {
- val id = hex.take(20).hexToString()
- if (id.isNumber()) {
- markerId = id
- handleMarker(markerId)
- }
- }
- }
-
- private fun handleMarker(id: String) {
- binding.depthButton.isEnabled = true
- binding.depthButton.setTextColor(Color.WHITE)
- binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
- binding.markerInfoButton.isEnabled = true
- binding.markerInfoButton.setTextColor(Color.WHITE)
- binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)
-
- binding.searchResultView.text = "已检测到标识器"
- binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
- binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)
-
- //自动上传标识器
- if (isExecuteTask) {
- val taskMarkerLocalBean = DataBaseManager.get.queryTaskMarkerById(
- taskId, taskCode, id, "0"
- )
- taskMarkerLocalBean?.apply {
- taskViewModel.uploadMarker(context, this)
- }
- }
- }
-
- //更新罗盘角度
- fun updateDegreeValue(degree: Int) {
- binding.radarScanView.setDegreeValue(degree)
- }
-
- private fun initTimer() {
- searchMarkerTimer = Timer()
-
- signalTask = object : TimerTask() {
- override fun run() {
- out.write('2'.code)
- out.flush()
- }
- }
-
- energyTask = object : TimerTask() {
- override fun run() {
- out.write('6'.code)
- out.flush()
- }
- }
-
- //错开信号和能量定时器
- searchMarkerTimer.schedule(signalTask, 0, 201)
- searchMarkerTimer.schedule(energyTask, 0, 251)
- }
-
- override fun dismiss() {
- signalTask.cancel()
- energyTask.cancel()
- searchMarkerTimer.cancel()
- //降低串口电位
- gpioManager.setGpioLow("18")
- isDetectMarker = false
- soundPool.autoPause()
- locationTool.stopLocation()
- super.dismiss()
- }
- }
-
- /**
- * 标识器与当前定位的数据
- * */
- data class MarkerDistanceData(var markerId: String, var distance: Float)
}
\ 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
new file mode 100644
index 0000000..14fe667
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/view/SearchMarkerActivity.kt
@@ -0,0 +1,462 @@
+package com.casic.detector.common.view
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.graphics.Color
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import android.media.AudioAttributes
+import android.media.SoundPool
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.IBinder
+import android.util.Log
+import android.view.View
+import android.view.WindowManager
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMapUtils
+import com.amap.api.maps.model.LatLng
+import com.casic.detector.common.R
+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.hexToString
+import com.casic.detector.common.extensions.isNumber
+import com.casic.detector.common.extensions.toHex
+import com.casic.detector.common.model.MarkerDistanceData
+import com.casic.detector.common.service.SerialPortService
+import com.casic.detector.common.utils.DataBaseManager
+import com.casic.detector.common.utils.LocaleConstant
+import com.casic.detector.common.utils.LocationTool
+import com.casic.detector.common.vm.TaskViewModel
+import com.casic.detector.common.widgets.RadarScanView
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.Constant
+import com.pengxh.kt.lite.utils.LoadingDialogHub
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.OutputStream
+import java.util.Timer
+import java.util.TimerTask
+import kotlin.math.atan2
+
+class SearchMarkerActivity : KotlinBaseActivity(),
+ SensorEventListener {
+
+ private val kTag = "SearchMarkerActivity"
+ private val context = this
+ private val locationTool by lazy { LocationTool(this) }
+ private val markerPoints by lazy { ArrayList() }
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val sensorManager by lazy { getSystemService()!! }
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private val rotationMatrix = FloatArray(9)//旋转矩阵缓存
+ private val valueArray = FloatArray(3)//方位角数值
+ private var slowSoundResourceId = 0
+ private var fastSoundResourceId = 0
+ private var markerId = ""//实际探测出来的标识器ID
+ private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID
+ private var isExecuteTask = false
+ private var signalEnergy = 0 //标识器信号强度
+ 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 {
+ override fun onServiceConnected(name: ComponentName?, iBinder: IBinder?) {
+ if (iBinder is SerialPortService.ServiceBinder) {
+ serialPortService = iBinder.getSerialPortService()
+ Log.d(kTag, "onServiceConnected: 服务已绑定")
+ searchMarker()
+ }
+ }
+
+ override fun onServiceDisconnected(name: ComponentName?) {
+
+ }
+ }
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ val flag = intent.getStringExtra(Constant.INTENT_PARAM) as String
+ isExecuteTask = flag != "0"
+
+ //绑定串口通信服务
+ Intent(this, SerialPortService::class.java).also {
+ bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
+ }
+
+ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
+ fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)
+
+ //点位渲染,每次定位都计算当前位置与符合条件的点距离
+ locationTool.getCurrentLocation(false, object : OnGetLocationListener {
+ override fun onAMapLocationGet(location: AMapLocation?) {
+ location?.apply {
+ renderDataPoint(this)
+ }
+ }
+ })
+
+ if (isExecuteTask) {
+ binding.taskStateView.visibility = View.GONE
+ binding.taskStateView.isSelected = false
+ } else {
+ binding.taskStateView.visibility = View.VISIBLE
+ binding.taskStateView.isSelected = true
+ }
+
+ //在标识器信号强度很强的时候,从数据库中计算出距离最近的点,以防出现探测不到ID的情况
+ searchSignalEnergyTimer = Timer()
+ searchSignalEnergyTimer.schedule(object : TimerTask() {
+ override fun run() {
+ //markerId为空,说明没有通过探测得到标识器ID,那么就需要通过计算得到近似的标识器
+ if (signalEnergy >= 4100 && markerPoints.isNotEmpty()) {
+ try {
+ //需要转一下,不然会有并发问题
+ val temp = ArrayList()
+ temp.addAll(markerPoints)
+ temp.sortBy(MarkerDistanceData::distance)
+ val nearestPoint = temp.first()
+ nearestMarkerId = nearestPoint.markerId
+ runOnUiThread {
+ handleMarker(nearestMarkerId)
+ }
+ markerPoints.clear()
+ } catch (e: NullPointerException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }, 0, 2000)
+ }
+
+ private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
+ override fun onTick(millisUntilFinished: Long) {
+
+ }
+
+ override fun onFinish() {
+ LoadingDialogHub.dismiss()
+ serialPortService?.closeSerialPort()
+ "标识器深度探测超时,请移动位置重试".show(context)
+ searchMarker()
+ }
+ }
+
+ override fun initEvent() {
+ binding.depthButton.setOnClickListener {
+ stopSearchMarker()
+ val result = DataBaseManager.get.queryMarkerById(markerId)
+ if (result.isNotEmpty()) {
+ val tag = when (result.first().markerType) {
+ "EM30" -> '7'
+ "EM50" -> '8'
+ "EM14" -> '9'
+ else -> '1'
+ }
+ if (tag == '1') {
+ "此标识器无法读取埋深!".show(this)
+ searchMarker()
+ } else {
+ LoadingDialogHub.show(this, "正在探测标识器埋深,请稍后...")
+ countDownTimer.start()
+ // 发送读取标识器埋设深度指令
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ // 发送读取标识器埋设深度指令
+ outStream.write(tag.code)
+ outStream.flush()
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ if (hex.startsWith("53")) {
+ LoadingDialogHub.dismiss()
+ countDownTimer.cancel()
+ try {
+ val depthResponse = hex.take(10).hexToString()
+ val depth = depthResponse.drop(2).toInt()
+ AlertMessageDialog.Builder().setContext(context)
+ .setTitle("温馨提示")
+ .setMessage("标识器埋深:${depth}厘米")
+ .setPositiveButton("知道了")
+ .setOnDialogButtonClickListener(object :
+ AlertMessageDialog.OnDialogButtonClickListener {
+ override fun onConfirmClick() {
+ serialPortService?.closeSerialPort()
+ searchMarker()
+ }
+ }).build().show()
+ } catch (e: WindowManager.BadTokenException) {
+ e.printStackTrace()
+ } catch (e: NumberFormatException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ })
+ }
+ } else {
+ LoadingDialogHub.dismiss()
+ "标识器未安装,安装成功后才可读取埋深!".show(this)
+ searchMarker()
+ }
+ }
+
+ binding.markerInfoButton.setOnClickListener {
+ val id = if (markerId == "") {
+ nearestMarkerId
+ } else {
+ markerId
+ }
+ //查库
+ val result = DataBaseManager.get.queryMarkerById(id)
+ if (result.isNotEmpty()) {
+ navigatePageTo(result.first().toJson())
+ } else {
+ navigatePageTo(id)
+ }
+ //查看完就把ID置空,便于下次查看最新的ID
+ markerId = ""
+ }
+ }
+
+ /**
+ * 搜索标识器
+ * */
+ private fun searchMarker() {
+ Thread.sleep(100)
+
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ searchMarkerTimer = Timer()
+ searchMarkerTimer.schedule(object : TimerTask() {
+ override fun run() {
+ outStream.write('2'.code)
+ outStream.flush()
+
+ Thread.sleep(50)
+
+ outStream.write('6'.code)
+ outStream.flush()
+ }
+ }, 0, 200)
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ 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)
+ }
+
+ //通过设置进度条表示能量值
+ 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)
+
+ 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()
+ }
+ } else {
+ val id = hex.take(20).hexToString()
+ if (id.isNumber()) {
+ markerId = id
+ handleMarker(markerId)
+ }
+ }
+ }
+ })
+ }
+
+ private fun stopSearchMarker() {
+ soundPool.autoPause()
+ searchMarkerTimer.cancel()
+ serialPortService?.closeSerialPort()
+
+ Thread.sleep(100)
+ }
+
+ /**
+ * 计算并渲染数据点。点太多采用协程计算,不然会有点卡顿。默认2s计算一次
+ * @param location 定位点(RTK获取)
+ * */
+ private fun renderDataPoint(location: AMapLocation) {
+ val longitude = location.longitude
+ val latitude = location.latitude
+ lifecycleScope.launch(Dispatchers.IO) {
+ val dataPoints = ArrayList()
+ DataBaseManager.get.loadMarkers().forEach {
+ val distance = AMapUtils.calculateLineDistance(
+ LatLng(it.lat.toDouble(), it.lng.toDouble()), LatLng(latitude, longitude)
+ )
+ val formatDistance = "%.2f".format(distance).toFloat()
+ markerPoints.add(MarkerDistanceData(it.markerId, formatDistance))
+
+ if (formatDistance <= LocaleConstant.MAX_DISTANCE) {
+ val angle = atan2(
+ (it.lat.toDouble() - latitude), (it.lng.toDouble() - longitude)
+ ) + Math.PI
+ val formatAngle = "%.2f".format(angle).toDouble()
+
+ dataPoints.add(RadarScanView.DataPoint(formatAngle, formatDistance))
+ }
+ }
+ withContext(Dispatchers.Main) {
+ binding.radarScanView.renderPointData(dataPoints,
+ object : RadarScanView.OnGetNearestPointCallback {
+ override fun getNearestPoint(point: RadarScanView.DataPoint?) {
+ if (point == null) {
+ binding.distanceValueView.text = "大于5.5m"
+ binding.distancePgBar.progress = 100
+ } else {
+ binding.distanceValueView.text = "${point.distance}m"
+ val progress = if (point.distance > LocaleConstant.MAX_DISTANCE) {
+ 100
+ } else {
+ (point.distance / LocaleConstant.MAX_DISTANCE) * 100
+ }
+ binding.distancePgBar.progress = progress.toInt()
+ }
+ }
+ }
+ )
+ }
+ }
+ }
+
+ override fun initViewBinding(): ActivitySearchMarkerBinding {
+ return ActivitySearchMarkerBinding.inflate(layoutInflater)
+ }
+
+ override fun observeRequestState() {
+
+ }
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ private fun handleMarker(id: String) {
+ binding.depthButton.isEnabled = true
+ binding.depthButton.setTextColor(Color.WHITE)
+ binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
+ binding.markerInfoButton.isEnabled = true
+ binding.markerInfoButton.setTextColor(Color.WHITE)
+ binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)
+
+ binding.searchResultView.text = "已检测到标识器"
+ binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
+ binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)
+
+ //自动上传标识器
+ if (isExecuteTask) {
+ val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
+ val taskCode = SaveKeyValues.getValue(LocaleConstant.TASK_CODE, "") as String
+ val taskMarkerLocalBean = DataBaseManager.get.queryTaskMarkerById(
+ taskId, taskCode, id, "0"
+ )
+ taskMarkerLocalBean?.apply {
+ taskViewModel.uploadMarker(context, this)
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ //注册加速度传感器监听
+ val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
+ sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)
+
+ //注册磁场传感器监听
+ val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
+ sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL)
+ }
+
+ override fun onPause() {
+ super.onPause()
+ sensorManager.unregisterListener(this)
+ }
+
+ override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
+ //精度发生变化时触发
+ }
+
+ override fun onSensorChanged(event: SensorEvent?) {
+ //值发生变化时触发
+ val type = event?.sensor?.type
+
+ if (type == Sensor.TYPE_ACCELEROMETER) {
+ gravity = event.values
+ } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
+ geomagnetic = event.values
+ }
+
+ if (gravity == null || geomagnetic == null) {
+ return
+ }
+
+ if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
+ SensorManager.getOrientation(rotationMatrix, valueArray)
+
+ val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt()
+ //更新罗盘角度
+ binding.radarScanView.setDegreeValue(degree)
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ stopSearchMarker()
+ locationTool.stopLocation()
+ unbindService(serviceConnection)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_install_marker.xml b/app/src/main/res/layout/activity_install_marker.xml
new file mode 100644
index 0000000..65c2262
--- /dev/null
+++ b/app/src/main/res/layout/activity_install_marker.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_search_marker.xml b/app/src/main/res/layout/activity_search_marker.xml
new file mode 100644
index 0000000..b989df8
--- /dev/null
+++ b/app/src/main/res/layout/activity_search_marker.xml
@@ -0,0 +1,178 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
index 458f3fb..ca7de13 100644
--- a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
+++ b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
@@ -4,6 +4,7 @@
import com.casic.detector.common.greendao.DaoMaster
import com.casic.detector.common.greendao.DaoSession
import com.casic.detector.common.uart.SerialPort
+import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.SaveKeyValues
import java.io.File
import java.io.IOException
@@ -13,23 +14,12 @@
class BaseApplication : Application() {
private val kTag = "BaseApplication"
- private var serialPorts: ArrayList? = null
+ private var serialPorts = ArrayList()
- @Throws(SecurityException::class, IOException::class, InvalidParameterException::class)
- fun getSerialPorts(): ArrayList? {
- serialPorts = ArrayList()
- /**
- * Open the serial port
- * */
- serialPorts?.apply {
- add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
- add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
- }
- return serialPorts
- }
+ fun getSerialPorts(): ArrayList = serialPorts
fun closeSerialPort() {
- serialPorts?.forEach {
+ serialPorts.forEach {
it.closeSerialPort()
}
}
@@ -49,6 +39,22 @@
val devOpenHelper = DaoMaster.DevOpenHelper(this, "Detector_Common.db", null)
val daoMaster = DaoMaster(devOpenHelper.writableDatabase)
daoSession = daoMaster.newSession()
+
+ /**
+ * Open the serial port
+ * */
+ try {
+ serialPorts.apply {
+ add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
+ add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
+ }
+ } catch (e: SecurityException) {
+ "您没有串口的读写权限!".show(this)
+ } catch (e: IOException) {
+ "因为不明原因,串口无法打开!".show(this)
+ } catch (e: InvalidParameterException) {
+ "请检查串口!".show(this)
+ }
}
fun getDaoSession(): DaoSession {
diff --git a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt b/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
deleted file mode 100644
index 297ac02..0000000
--- a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.casic.detector.common.base
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.lifecycleScope
-import androidx.viewbinding.ViewBinding
-import com.pengxh.kt.lite.extensions.show
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.IOException
-import java.io.OutputStream
-import java.security.InvalidParameterException
-
-
-abstract class SerialPortActivity : AppCompatActivity() {
-
- protected lateinit var binding: VB
-
- lateinit var out: OutputStream
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = initViewBinding()
- setContentView(binding.root)
- setupTopBarLayout()
- initOnCreate(savedInstanceState)
- observeRequestState()
- initEvent()
-
- try {
- val serialPorts = BaseApplication.get().getSerialPorts()
- //读
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[0].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[1].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- //写
- serialPorts?.apply {
- out = this[0].outputStream
- }
- } catch (e: SecurityException) {
- "您没有串口的读写权限!".show(this)
- } catch (e: IOException) {
- "因为不明原因,串口无法打开!".show(this)
- } catch (e: InvalidParameterException) {
- "请检查串口!".show(this)
- }
- }
-
- /**
- * 初始化ViewBinding
- */
- abstract fun initViewBinding(): VB
-
- /**
- * 特定页面定制沉浸式状态栏
- */
- abstract fun setupTopBarLayout()
-
- /**
- * 初始化默认数据
- */
- abstract fun initOnCreate(savedInstanceState: Bundle?)
-
- /**
- * 数据请求状态监听
- */
- abstract fun observeRequestState()
-
- /**
- * 初始化业务逻辑
- */
- abstract fun initEvent()
-
- /**
- * 串口读数,已经切回主线程
- * */
- abstract fun onDataReceived(buffer: ByteArray)
-
- override fun onDestroy() {
- super.onDestroy()
- BaseApplication.get().closeSerialPort()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
new file mode 100644
index 0000000..b06a068
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
@@ -0,0 +1,9 @@
+package com.casic.detector.common.callback
+
+import java.io.OutputStream
+
+interface OnSerialPortDataListener {
+ fun write(outStream: OutputStream)
+
+ fun onDataReceived(buffer: ByteArray)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
new file mode 100644
index 0000000..b1685d5
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
@@ -0,0 +1,6 @@
+package com.casic.detector.common.model
+
+/**
+ * 标识器与当前定位的数据
+ * */
+data class MarkerDistanceData(var markerId: String, var distance: Float)
diff --git a/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
new file mode 100644
index 0000000..090f604
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
@@ -0,0 +1,104 @@
+package com.casic.detector.common.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+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.base.BaseApplication
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.utils.GpioManager
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.IOException
+
+class SerialPortService : Service(), LifecycleOwner {
+
+ private val kTag = "SerialPortService"
+ private val registry = LifecycleRegistry(this)
+ private val gpioManager by lazy { GpioManager() }
+ private val serialPorts by lazy { BaseApplication.get().getSerialPorts() }
+ private var gpioState = ""
+
+ override fun getLifecycle(): Lifecycle {
+ return registry
+ }
+
+ override fun onBind(intent: Intent?): IBinder {
+ return ServiceBinder()
+ }
+
+ inner class ServiceBinder : Binder() {
+ fun getSerialPortService(): SerialPortService {
+ return this@SerialPortService
+ }
+ }
+
+ fun openSerialPort(listener: OnSerialPortDataListener) {
+ //调高串口电位
+ gpioManager.setGpioHigh("18")
+ gpioState = "1"
+ Log.d(kTag, "openSerialPort: 调高串口电位")
+
+ Thread.sleep(100)
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ //写
+ listener.write(this[0].outputStream)
+ val stream = this[0].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ val stream = this[1].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+ }
+
+ fun closeSerialPort() {
+ //降低串口电位
+ gpioManager.setGpioLow("18")
+ gpioState = "0"
+ Log.d(kTag, "closeSerialPort: 降低串口电位")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
new file mode 100644
index 0000000..b50aaaf
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
@@ -0,0 +1,548 @@
+package com.casic.detector.common.view
+
+import android.app.DatePickerDialog
+import android.content.ComponentName
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
+import android.media.AudioAttributes
+import android.media.SoundPool
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.IBinder
+import android.util.Log
+import android.view.View
+import android.widget.AdapterView
+import androidx.lifecycle.ViewModelProvider
+import com.amap.api.location.AMapLocation
+import com.casic.detector.common.R
+import com.casic.detector.common.adapter.EditableImageAdapter
+import com.casic.detector.common.bean.MarkerLocalBean
+import com.casic.detector.common.callback.OnGetLocationListener
+import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.databinding.ActivityInstallMarkerBinding
+import com.casic.detector.common.extensions.compressImage
+import com.casic.detector.common.extensions.getDefaultValue
+import com.casic.detector.common.extensions.hexToString
+import com.casic.detector.common.extensions.isNumber
+import com.casic.detector.common.extensions.setDefaultValue
+import com.casic.detector.common.extensions.show
+import com.casic.detector.common.extensions.toColor
+import com.casic.detector.common.extensions.toHex
+import com.casic.detector.common.extensions.toObjectType
+import com.casic.detector.common.service.SerialPortService
+import com.casic.detector.common.utils.DataBaseManager
+import com.casic.detector.common.utils.LocaleConstant
+import com.casic.detector.common.utils.LocationTool
+import com.casic.detector.common.vm.TaskViewModel
+import com.luck.picture.lib.basic.PictureSelector
+import com.luck.picture.lib.config.SelectMimeType
+import com.luck.picture.lib.entity.LocalMedia
+import com.luck.picture.lib.interfaces.OnResultCallbackListener
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.appendZero
+import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.extensions.dateToTimestamp
+import com.pengxh.kt.lite.extensions.navigatePageTo
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.extensions.timestampToCompleteDate
+import com.pengxh.kt.lite.extensions.timestampToTime
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.LoadState
+import com.pengxh.kt.lite.utils.LoadingDialogHub
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import java.io.File
+import java.io.OutputStream
+import java.util.Calendar
+import java.util.Date
+
+class InstallMarkerActivity : KotlinBaseActivity() {
+
+ private val kTag = "InstallMarkerActivity"
+ private val context = this
+ private val calendar by lazy { Calendar.getInstance() }
+ private val locationTool by lazy { LocationTool(this) }
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val realPaths = ArrayList() //真实图片路径
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var soundResourceId = 0
+ private var serialPortService: SerialPortService? = null
+ private lateinit var imageAdapter: EditableImageAdapter
+
+ override fun initEvent() {
+ //返回
+ binding.titleInclude.leftBackView.setOnClickListener {
+ soundPool.autoPause()
+ finish()
+ }
+
+ binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
+ object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(
+ parent: AdapterView<*>?, view: View?, position: Int, id: Long
+ ) {
+ when (position) {
+ 0 -> {
+ //显示管线属性
+ binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 1 -> {
+ //显示管线附属物属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 2 -> {
+ //显示管线特征点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 3 -> {
+ //显示交叉穿越点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.VISIBLE
+ }
+ }
+ }
+
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+
+ }
+ }
+
+ //安装
+ binding.installButton.setOnClickListener {
+ val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+ if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
+ when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
+ "管线" -> "请输入管线种类!".show(this)
+ "管线附属物" -> "请输入附属物名称!".show(this)
+ "管线特征管点" -> "请输入特征管点!".show(this)
+ "交叉穿越点" -> "请输入上层管种类!".show(this)
+ }
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
+ if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
+ "请输入管径".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
+ "请输入埋深".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
+ if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
+ "请输入下层管管径".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.areaView.text.isNullOrBlank()) {
+ "请输入所属区域".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.lineView.text.isNullOrBlank()) {
+ "请输入所属线路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.roadView.text.isNullOrBlank()) {
+ "请输入所属道路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
+ "请选择建设年代".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
+ "请输入权属单位".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
+ "请先读取标识器获取ID".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
+ "请输入标识器埋深".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
+ "请输入标识器安装部门".show(this)
+ return@setOnClickListener
+ }
+
+ //先存本地再上传服务器
+ saveMarkerInLocal()
+
+ taskViewModel.installLabel(
+ this, companyId,
+ binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
+ binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
+ "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.areaView.text.toString(),
+ binding.objectInclude.lineView.text.toString(),
+ binding.objectInclude.roadView.text.toString(),
+ binding.objectInclude.constructDateView.text.toString(),
+ binding.objectInclude.ownerView.text.toString(),
+ objectId,
+ binding.identifierInclude.identifierIdView.text.toString(),
+ binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
+ "${binding.identifierInclude.identifierDeepView.text}mm",
+ binding.identifierInclude.personDeptView.text.toString(),
+ binding.identifierInclude.installTimeView.text.toString(),
+ binding.identifierInclude.lngView.text.toString(),
+ binding.identifierInclude.latView.text.toString(),
+ binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
+ binding.remarkView.text.toString(),
+ realPaths
+ )
+
+ //保存默认值
+ "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
+ "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
+ "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
+ "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
+ "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
+ "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
+ "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
+ "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
+ "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
+ "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
+ "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
+ }
+
+ //读标识器
+ binding.readMarkerButton.setOnClickListener {
+ LoadingDialogHub.show(this, "标识器读取中,请稍后...")
+ countDownTimer.start()
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ outStream.write('2'.code)
+ outStream.flush()
+
+ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
+ binding.readMarkerButton.isEnabled = false
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ Log.d(kTag, hex)
+ val markerId = hex.take(20).hexToString()
+ if (markerId.isNumber()) {
+ countDownTimer.cancel()
+ cancelLoadingView()
+ binding.readMarkerButton.isEnabled = true
+ binding.identifierInclude.identifierIdView.text = markerId
+ }
+ }
+ })
+ }
+ }
+
+ /**
+ * 搜索标识器超时倒计时
+ * */
+ private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
+ override fun onTick(millisUntilFinished: Long) {
+
+ }
+
+ override fun onFinish() {
+ cancelLoadingView()
+ "读取此标识器ID超时,请重试".show(context)
+ binding.readMarkerButton.isEnabled = true
+ }
+ }
+
+ private fun cancelLoadingView() {
+ LoadingDialogHub.dismiss()
+ soundPool.autoPause()
+ serialPortService?.closeSerialPort()
+ }
+
+ private fun saveMarkerInLocal() {
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+
+ val marker = MarkerLocalBean()
+ marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
+ marker.pipelineType = binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
+ marker.pipelineMaterial =
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
+ marker.pipelineDiameter = "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
+ marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
+ marker.underlyingPipelineType =
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
+ marker.underlyingPipelineMaterial =
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
+ marker.underlyingPipelineDiameter =
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
+ marker.underlyingPipelineDepth =
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
+ marker.buryMethod =
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
+ marker.area = binding.objectInclude.areaView.text.toString()
+ marker.line = binding.objectInclude.lineView.text.toString()
+ marker.road = binding.objectInclude.roadView.text.toString()
+ marker.constructTime = binding.objectInclude.constructDateView.text.toString()
+ marker.owner = binding.objectInclude.ownerView.text.toString()
+ marker.objectId = objectId
+ marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
+ marker.markerType = binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
+ marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
+ marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
+ marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
+ marker.lng = binding.identifierInclude.lngView.text.toString()
+ marker.lat = binding.identifierInclude.latView.text.toString()
+ marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
+ marker.remark = binding.remarkView.text.toString()
+ marker.imagePath = realPaths.toJson()
+
+ DataBaseManager.get.saveMarkerInLocale(marker)
+ }
+
+ private fun takePicture() {
+ PictureSelector.create(this).openCamera(SelectMimeType.ofImage())
+ .forResult(object : OnResultCallbackListener {
+ override fun onResult(result: ArrayList?) {
+ if (result == null) {
+ "拍照失败,请重试".show(context)
+ return
+ }
+ analyticalSelectResults(result[0])
+ }
+
+ override fun onCancel() {
+
+ }
+ })
+ }
+
+ private fun analyticalSelectResults(result: LocalMedia) {
+ //压缩图片
+ result.realPath.compressImage(context, object : OnImageCompressListener {
+ override fun onSuccess(file: File) {
+ realPaths.add(file.absolutePath)
+ imageAdapter.setupImage(realPaths)
+ }
+
+ override fun onError(e: Throwable) {
+ e.printStackTrace()
+ }
+ })
+ }
+
+ 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?) {
+ //在连接正常关闭的情况下不会被调用, 只在Service被破坏了或者被杀死的时候调用
+ }
+ }
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ //绑定串口通信服务
+ Intent(this, SerialPortService::class.java).also {
+ bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
+ }
+
+ locationTool.getCurrentLocation(true, object : OnGetLocationListener {
+ override fun onAMapLocationGet(location: AMapLocation?) {
+ if (location != null) {
+ binding.identifierInclude.lngView.text = location.longitude.toString()
+ binding.identifierInclude.latView.text = location.latitude.toString()
+ } else {
+ "当前位置信号差,无法获取定位".show(context)
+ }
+ }
+ })
+ soundResourceId = soundPool.load(this, R.raw.ring3, 1)
+
+ //初始化数据
+ initDefaultData()
+ }
+
+ override fun initViewBinding(): ActivityInstallMarkerBinding {
+ return ActivityInstallMarkerBinding.inflate(layoutInflater)
+ }
+
+ override fun observeRequestState() {
+ taskViewModel.loadState.observe(this) {
+ when (it) {
+ LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...")
+
+ LoadState.Success -> {
+ LoadingDialogHub.dismiss()
+ clearDefaultData()
+ "安装成功".show(this)
+ }
+
+ else -> LoadingDialogHub.dismiss()
+ }
+ }
+ }
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ private fun initDefaultData() {
+ binding.titleInclude.titleView.text = "安装新标识器"
+ binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
+
+ imageAdapter = EditableImageAdapter(this, 3, 3)
+ binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
+
+ //设置默认值
+ binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
+ binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
+ binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
+ binding.objectInclude.areaView.setText("areaView".getDefaultValue())
+ binding.objectInclude.lineView.setText("lineView".getDefaultValue())
+ binding.objectInclude.roadView.setText("roadView".getDefaultValue())
+ binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
+ binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
+ binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
+
+ /**************************************************************************************/
+ binding.objectInclude.objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0)
+ binding.objectInclude.pipeInclude.materialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeAttachInclude.attachSpinner.show(
+ this, LocaleConstant.ATTACH_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
+ this, LocaleConstant.FEATURE_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeInclude.buryTypeSpinner.show(
+ this, LocaleConstant.BURY_METHOD_ARRAY, 0
+ )
+ binding.objectInclude.constructDateView.setOnClickListener {
+ val datePicker = DatePickerDialog(
+ this, null,
+ calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH),
+ calendar.get(Calendar.DAY_OF_MONTH)
+ )
+ datePicker.show()
+
+ datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
+ val year = datePicker.datePicker.year
+ val month = datePicker.datePicker.month + 1
+ val day = datePicker.datePicker.dayOfMonth
+ val selectedDate = String.format(
+ "%s-%s-%s", year, month.appendZero(), day.appendZero()
+ )
+
+ //当前时间
+ val current = System.currentTimeMillis().timestampToTime()
+ val today = "$selectedDate $current".dateToTimestamp()
+ if (Date(today).after(Date())) {
+ "建设年代不能早于当前日期".show(context)
+ } else {
+ datePicker.dismiss()
+ binding.objectInclude.constructDateView.text = selectedDate
+ }
+ }
+ }
+ binding.identifierInclude.identifierTypeSpinner.show(
+ this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
+ )
+ binding.identifierInclude.installTimeView.text =
+ System.currentTimeMillis().timestampToCompleteDate()
+ binding.identifierInclude.colorSpinner.show(this, LocaleConstant.COLOR_ARRAY, 0)
+
+ imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
+ override fun onAddImageClick() {
+ takePicture()
+ }
+
+ override fun onItemClick(position: Int) {
+ if (realPaths[position].isEmpty()) {
+ "图片加载失败,无法查看大图".show(context)
+ } else {
+ navigatePageTo(position, realPaths)
+ }
+ }
+
+ override fun onItemLongClick(view: View?, position: Int) {
+ imageAdapter.deleteImage(position)
+ }
+ })
+ }
+
+ //清除默认数据
+ private fun clearDefaultData() {
+ "markerObjectTypeView".setDefaultValue("")
+ "pipelineDiameterView".setDefaultValue("")
+ "buryDeepView".setDefaultValue("")
+ "bottomPipeDiameterView".setDefaultValue("")
+ "bottomPointDeepView".setDefaultValue("")
+ "areaView".setDefaultValue("")
+ "lineView".setDefaultValue("")
+ "roadView".setDefaultValue("")
+ "ownerView".setDefaultValue("")
+ "identifierDeepView".setDefaultValue("")
+ "personDeptView".setDefaultValue("")
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ soundPool.autoPause()
+ locationTool.stopLocation()
+ 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 1dac658..f949269 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,31 +1,25 @@
package com.casic.detector.common.view
-import android.app.DatePickerDialog
-import android.app.Dialog
+import android.content.ComponentName
import android.content.Context
-import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
-import android.hardware.Sensor
-import android.hardware.SensorEvent
-import android.hardware.SensorEventListener
-import android.hardware.SensorManager
import android.media.AudioAttributes
import android.media.SoundPool
import android.os.Bundle
-import android.os.CountDownTimer
+import android.os.IBinder
import android.util.Log
import android.view.KeyEvent
import android.view.View
-import android.widget.AdapterView
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.amap.api.location.AMapLocation
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
-import com.amap.api.maps.AMapUtils
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.CoordinateConverter
import com.amap.api.maps.model.BitmapDescriptorFactory
@@ -34,38 +28,29 @@
import com.amap.api.maps.model.MarkerOptions
import com.amap.api.maps.model.MyLocationStyle
import com.casic.detector.common.R
-import com.casic.detector.common.adapter.EditableImageAdapter
-import com.casic.detector.common.base.SerialPortActivity
+import com.casic.detector.common.base.BaseApplication
import com.casic.detector.common.bean.MarkerLocalBean
import com.casic.detector.common.bean.TaskLocalBean
import com.casic.detector.common.callback.OnGetLocationListener
-import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
import com.casic.detector.common.cluster.ClusterItem
import com.casic.detector.common.cluster.ClusterOverlay
import com.casic.detector.common.cluster.RegionItem
import com.casic.detector.common.databinding.ActivityMainBinding
-import com.casic.detector.common.databinding.DialogInstallMarkerBinding
-import com.casic.detector.common.databinding.DialogSearchMarkerNewBinding
import com.casic.detector.common.extensions.appendDownloadUrl
-import com.casic.detector.common.extensions.compressImage
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.getDefaultValue
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.setDefaultValue
-import com.casic.detector.common.extensions.show
-import com.casic.detector.common.extensions.toColor
import com.casic.detector.common.extensions.toHex
-import com.casic.detector.common.extensions.toObjectType
import com.casic.detector.common.model.TaskDetailLocalModel
import com.casic.detector.common.model.TaskModel
+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.GpioManager
import com.casic.detector.common.utils.LocaleConstant
import com.casic.detector.common.utils.LocationTool
import com.casic.detector.common.utils.NtripAuthorizationCreator
@@ -77,26 +62,15 @@
import com.casic.detector.common.vm.TaskViewModel
import com.casic.detector.common.widgets.MarkerDetailDialog
import com.casic.detector.common.widgets.QueryMarkerDialog
-import com.casic.detector.common.widgets.RadarScanView
import com.casic.detector.common.widgets.SamplePopupWindow
-import com.luck.picture.lib.basic.PictureSelector
-import com.luck.picture.lib.config.SelectMimeType
-import com.luck.picture.lib.entity.LocalMedia
-import com.luck.picture.lib.interfaces.OnResultCallbackListener
-import com.pengxh.kt.lite.extensions.appendZero
-import com.pengxh.kt.lite.extensions.binding
-import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertDrawable
import com.pengxh.kt.lite.extensions.createDownloadFileDir
-import com.pengxh.kt.lite.extensions.dateToTimestamp
import com.pengxh.kt.lite.extensions.dp2px
-import com.pengxh.kt.lite.extensions.getSystemService
-import com.pengxh.kt.lite.extensions.initDialogLayoutParams
import com.pengxh.kt.lite.extensions.isNetworkConnected
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.extensions.timestampToCompleteDate
-import com.pengxh.kt.lite.extensions.timestampToTime
import com.pengxh.kt.lite.extensions.toJson
import com.pengxh.kt.lite.utils.FileDownloadManager
import com.pengxh.kt.lite.utils.LoadState
@@ -108,60 +82,41 @@
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
import io.netty.buffer.Unpooled
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
+import java.io.OutputStream
import java.nio.charset.StandardCharsets
-import java.util.Calendar
-import java.util.Date
import java.util.Timer
import java.util.TimerTask
-import kotlin.math.atan2
-class MainActivity : SerialPortActivity(), SensorEventListener,
- OnSocketConnectListener {
+class MainActivity : KotlinBaseActivity(), OnSocketConnectListener {
private val kTag = "MainActivity"
private val context = this
private val samplePopupWindow by lazy { SamplePopupWindow(this) }
private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) }
private val backDrawables by lazy { HashMap() }
- private val installDialog by lazy { InstallMarkerDialog(this) }
- private val searchNewDialog by lazy { SearchMarkerNewDialog(this) }
private val detailDialog by lazy { MarkerDetailDialog(this) }
private val locationTool by lazy { LocationTool(this) }
- private val rotationMatrix = FloatArray(9)//旋转矩阵缓存
- private val valueArray = FloatArray(3)//方位角数值
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
private var clickTime: Long = 0
private var markers = ArrayList()
private var clusterOverlay: ClusterOverlay? = null
private var isFreeTask = false
private var freeTaskTitle = ""
private var ids = HashSet()
- private var signalTask: TimerTask? = null
- private var energyTask: TimerTask? = null
- private var searchMarkerTimer: Timer? = null
private var freeTaskId: String? = null
- private var gravity: FloatArray? = null
- private var geomagnetic: FloatArray? = null
private var connectState = ConnectState.CLOSED
private var socketClient: SocketClient? = null
- private lateinit var aMap: AMap
- private lateinit var sensorManager: SensorManager
-
- /***inner class 需要用到*****start*/
- private val gpioManager by lazy { GpioManager() }
- private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
- private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
- .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
- private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var serialPortService: SerialPortService? = null
+ private var searchMarkerTimer: Timer? = null
private var soundResourceId = 0
- private var slowSoundResourceId = 0
- private var fastSoundResourceId = 0
private var isExecuteTask = false
-
- /***inner class 需要用到*****end*/
+ private lateinit var aMap: AMap
override fun initViewBinding(): ActivityMainBinding {
return ActivityMainBinding.inflate(layoutInflater)
@@ -171,10 +126,26 @@
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)
+ }
+
soundResourceId = soundPool.load(this, R.raw.ring3, 1)
- slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
- fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)
RtkLocationTool.getCurrentLocation(this) {
if (connectState == ConnectState.SUCCESS) {
@@ -192,8 +163,6 @@
samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES)
samplePopupWindow.setBackgroundDrawable(null)
- sensorManager = getSystemService()!!
-
//task网络请求监听
taskViewModel.markerFileResult.observe(this) {
if (it.isSuccess) {
@@ -316,9 +285,6 @@
//安装。上传,然后存入本地库
binding.installButton.setOnClickListener {
- /**
- * 改为Dialog方式,避免频繁打开/关闭串口
- * */
if (isFreeTask) {
AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示")
.setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能")
@@ -329,7 +295,7 @@
}
}).build().show()
} else {
- installDialog.show()
+ navigatePageTo()
}
}
@@ -449,8 +415,6 @@
//探测
binding.detectionButton.setOnClickListener {
/**
- * 改为Dialog方式,避免频繁打开/关闭串口
- *
* 如果开启自由巡检就不让探测
* */
if (isFreeTask) {
@@ -463,7 +427,12 @@
}
}).build().show()
} else {
- searchNewDialog.show()
+ val flag = if (isExecuteTask) {
+ "1"
+ } else {
+ "0"
+ }
+ navigatePageTo(flag)
}
}
@@ -476,14 +445,8 @@
override fun onConfirmClick() {
isFreeTask = false
soundPool.autoPause()
-
- //停止信号和ID搜索定时器
- signalTask?.cancel()
- energyTask?.cancel()
searchMarkerTimer?.cancel()
-
- //降低串口电位
- gpioManager.setGpioLow("18")
+ serialPortService?.closeSerialPort()
binding.stopFreeTaskButton.visibility = View.GONE
if (freeTaskId.isNullOrBlank()) {
@@ -527,110 +490,79 @@
}
private fun openSerialPort() {
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- isFreeTask = true
- //自由巡检
- signalTask = object : TimerTask() {
- override fun run() {
- out.write('2'.code)
- out.flush()
- }
- }
-
- energyTask = object : TimerTask() {
- override fun run() {
- out.write('6'.code)
- out.flush()
- }
- }
-
- searchMarkerTimer = Timer()
- searchMarkerTimer?.apply {
- schedule(signalTask, 0, 200)
- schedule(energyTask, 0, 251)
- }
-
binding.stopFreeTaskButton.visibility = View.VISIBLE
- }
+ isFreeTask = true
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ searchMarkerTimer = Timer()
+ searchMarkerTimer?.schedule(object : TimerTask() {
+ override fun run() {
+ outStream.write('2'.code)
+ outStream.flush()
- override fun onDataReceived(buffer: ByteArray) {
- val hex = buffer.toHex()
-// Log.d(kTag, "$kTag => $hex")
- if (searchNewDialog.isDetectMarker) {
- searchNewDialog.bindingValue(hex)
- } else if (installDialog.isReadMarker) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- installDialog.bindingValue(markerId)
+ Thread.sleep(50)
+
+ outStream.write('6'.code)
+ outStream.flush()
+ }
+ }, 0, 200)
}
- } else if (isFreeTask) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- //只响一次,因为探测频率高,所以依旧是连续的报警声
- soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
- //添加地图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))
- )
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ if (hex.startsWith("4E")) {
+ //只响一次,因为探测频率高,所以依旧是连续的报警声
+ soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
+
+ 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()
}
}
- 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()
+ 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 (hex.startsWith("4E")) {
- val energyResponse = hex.take(10).hexToString()
- try {
- val energy = energyResponse.substring(1).toInt()
- if (energy <= 500 && detailDialog.isShowing) {
- detailDialog.dismiss()
- }
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- }
- }
+ })
}
override fun observeRequestState() {
taskViewModel.loadState.observe(this) {
when (it) {
- LoadState.Loading -> {
- if (installDialog.isInstallMarker) {
- LoadingDialogHub.show(this, "标识器安装中,请稍后...")
- } else {
- LoadingDialogHub.show(this, "提交工单中,请稍后")
- }
- }
-
- LoadState.Success -> {
- if (installDialog.isInstallMarker) {
- installDialog.clearDefaultData()
- installDialog.dismiss()
- "${installDialog.markerId}安装成功".show(this)
- }
- LoadingDialogHub.dismiss()
- }
+ LoadState.Loading -> LoadingDialogHub.show(this, "提交工单中,请稍后")
else -> LoadingDialogHub.dismiss()
}
@@ -939,32 +871,6 @@
} else super.onKeyDown(keyCode, event)
}
- override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
- //精度发生变化时触发
- }
-
- override fun onSensorChanged(event: SensorEvent?) {
- //值发生变化时触发
- val type = event?.sensor?.type
-
- if (type == Sensor.TYPE_ACCELEROMETER) {
- gravity = event.values
- } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
- geomagnetic = event.values
- }
-
- if (gravity == null || geomagnetic == null) {
- return
- }
-
- if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
- SensorManager.getOrientation(rotationMatrix, valueArray)
-
- val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt()
- searchNewDialog.updateDegreeValue(degree)
- }
- }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
@@ -978,14 +884,6 @@
showLabelsOnMap()
}
- //注册加速度传感器监听
- val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
- sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)
-
- //注册磁场传感器监听
- val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
- sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL)
-
//取缓存
val remoteHost = SaveKeyValues.getValue(
LocaleConstant.RTK_SERVER, "203.107.45.154"
@@ -995,20 +893,20 @@
) as String
//连接千寻RTK服务器
- lifecycleScope.launch(Dispatchers.IO) {
- if (socketClient != null) {
- socketClient?.disconnect()
- delay(3000)
- }
-
- socketClient = SocketClient.Builder()
- .setHostname(remoteHost)
- .setPort(remotePort.toInt())
- .setTimeout(5000)
- .setOnSocketListener(this@MainActivity)
- .build()
- socketClient?.connect()
- }
+// lifecycleScope.launch(Dispatchers.IO) {
+// if (socketClient != null) {
+// socketClient?.disconnect()
+// delay(3000)
+// }
+//
+// socketClient = SocketClient.Builder()
+// .setHostname(remoteHost)
+// .setPort(remotePort.toInt())
+// .setTimeout(5000)
+// .setOnSocketListener(this@MainActivity)
+// .build()
+// socketClient?.connect()
+// }
}
override fun onMessageResponse(data: ByteArray) {
@@ -1021,12 +919,12 @@
val result = String(data, StandardCharsets.UTF_8)
Log.d(kTag, "onMessageResponse: $result")
if (result.contains("ICY 200 OK")) {
- "高精度定位服务器连接成功".show(this)
+ "高精度定位服务连接成功".show(this)
}
} else {
"收到千寻数据返回,长度:${data.size}".show(this)
- out.write(data)
- out.flush()
+// out.write(data)
+// out.flush()
}
}
@@ -1061,7 +959,6 @@
override fun onPause() {
super.onPause()
binding.mapView.onPause()
- sensorManager.unregisterListener(this)
}
override fun onSaveInstanceState(outState: Bundle) {
@@ -1072,794 +969,11 @@
override fun onDestroy() {
super.onDestroy()
binding.mapView.onDestroy()
- soundPool.release()
+ soundPool.autoPause()
+ searchMarkerTimer?.cancel()
+ serialPortService?.closeSerialPort()
locationTool.stopLocation()
- //降低串口电位
- gpioManager.setGpioLow("18")
+ unbindService(serviceConnection)
+ BaseApplication.get().closeSerialPort()
}
-
- /**安装标识器对话框******************************************************************************/
- inner class InstallMarkerDialog(private val context: Context) : Dialog(context) {
-
- private val binding: DialogInstallMarkerBinding by binding()
- private val calendar by lazy { Calendar.getInstance() }
- private val realPaths = ArrayList() //真实图片路径
- private lateinit var imageAdapter: EditableImageAdapter
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
-
- var isReadMarker = false
- var isInstallMarker = false
- var markerId = ""
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
-
- //初始化数据
- initDefaultData()
-
- //返回
- binding.titleInclude.leftBackView.setOnClickListener {
- soundPool.autoPause()
- dismiss()
- }
-
- binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
- object : AdapterView.OnItemSelectedListener {
- override fun onItemSelected(
- parent: AdapterView<*>?, view: View?, position: Int, id: Long
- ) {
- when (position) {
- 0 -> {
- //显示管线属性
- binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 1 -> {
- //显示管线附属物属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 2 -> {
- //显示管线特征点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 3 -> {
- //显示交叉穿越点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility =
- View.VISIBLE
- }
- }
- }
-
- override fun onNothingSelected(parent: AdapterView<*>?) {
-
- }
- }
-
- //安装
- binding.installButton.setOnClickListener {
- val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
- if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
- when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
- "管线" -> "请输入管线种类!".show(context)
- "管线附属物" -> "请输入附属物名称!".show(context)
- "管线特征管点" -> "请输入特征管点!".show(context)
- "交叉穿越点" -> "请输入上层管种类!".show(context)
- }
- return@setOnClickListener
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
- if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
- "请输入管径".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
- "请输入埋深".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
- if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
- "请输入下层管管径".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.areaView.text.isNullOrBlank()) {
- "请输入所属区域".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.lineView.text.isNullOrBlank()) {
- "请输入所属线路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.roadView.text.isNullOrBlank()) {
- "请输入所属道路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
- "请选择建设年代".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
- "请输入权属单位".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
- "请先读取标识器获取ID".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
- "请输入标识器埋深".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
- "请输入标识器安装部门".show(context)
- return@setOnClickListener
- }
-
- //先存本地再上传服务器
- saveMarkerInLocal()
-
- isInstallMarker = true
- taskViewModel.installLabel(
- context,
- companyId,
- binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
- "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
- binding.objectInclude.areaView.text.toString(),
- binding.objectInclude.lineView.text.toString(),
- binding.objectInclude.roadView.text.toString(),
- binding.objectInclude.constructDateView.text.toString(),
- binding.objectInclude.ownerView.text.toString(),
- objectId,
- binding.identifierInclude.identifierIdView.text.toString(),
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
- "${binding.identifierInclude.identifierDeepView.text}mm",
- binding.identifierInclude.personDeptView.text.toString(),
- binding.identifierInclude.installTimeView.text.toString(),
- binding.identifierInclude.lngView.text.toString(),
- binding.identifierInclude.latView.text.toString(),
- binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
- binding.remarkView.text.toString(),
- realPaths
- )
-
- //保存默认值
- "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
- "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
- "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
- "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
- "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
- "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
- "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
- "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
- "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
- "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
- "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
- }
-
- //读标识器
- binding.readMarkerButton.setOnClickListener {
- LoadingDialogHub.show(this@MainActivity, "标识器读取中,请稍后...")
- binding.readMarkerButton.isEnabled = false
-
- isReadMarker = true
-
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
-
- out.write('2'.code)
- out.flush()
-
- countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- "读取此标识器ID超时,请退出应用再试".show(context)
- }
- }
- countDownTimer.start()
- }
- }
-
- override fun show() {
- super.show()
- locationTool = LocationTool(context)
- locationTool.getCurrentLocation(true, object : OnGetLocationListener {
- override fun onAMapLocationGet(location: AMapLocation?) {
- if (location != null) {
- binding.identifierInclude.lngView.text = location.longitude.toString()
- binding.identifierInclude.latView.text = location.latitude.toString()
- } else {
- "当前位置信号差,无法获取定位".show(context)
- }
- }
- })
- }
-
- fun bindingValue(markerId: String) {
- this.markerId = markerId
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- countDownTimer.cancel()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- binding.identifierInclude.identifierIdView.text = markerId
- }
-
- override fun dismiss() {
- //降低串口电位
- gpioManager.setGpioLow("18")
- soundPool.autoPause()
- isInstallMarker = false
- locationTool.stopLocation()
- super.dismiss()
- }
-
- private fun initDefaultData() {
- binding.titleInclude.titleView.text = "安装新标识器"
- binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
-
- imageAdapter = EditableImageAdapter(context, 3, 3)
- binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
-
- //设置默认值
- binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
- binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
- binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
- binding.objectInclude.areaView.setText("areaView".getDefaultValue())
- binding.objectInclude.lineView.setText("lineView".getDefaultValue())
- binding.objectInclude.roadView.setText("roadView".getDefaultValue())
- binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
- binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
- binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
-
- /**************************************************************************************/
- binding.objectInclude.objectTypeSpinner.show(
- this@MainActivity, LocaleConstant.POINT_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.materialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeAttachInclude.attachSpinner.show(
- this@MainActivity, LocaleConstant.ATTACH_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
- this@MainActivity, LocaleConstant.FEATURE_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.buryTypeSpinner.show(
- this@MainActivity, LocaleConstant.BURY_METHOD_ARRAY, 0
- )
-
- binding.objectInclude.constructDateView.setOnClickListener {
- val datePicker = DatePickerDialog(
- context,
- null,
- calendar.get(Calendar.YEAR),
- calendar.get(Calendar.MONTH),
- calendar.get(Calendar.DAY_OF_MONTH)
- )
- datePicker.show()
-
- datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
- val year = datePicker.datePicker.year
- val month = datePicker.datePicker.month + 1
- val day = datePicker.datePicker.dayOfMonth
- val selectedDate = String.format(
- "%s-%s-%s", year, month.appendZero(), day.appendZero()
- )
-
- //当前时间
- val current = System.currentTimeMillis().timestampToTime()
- val today = "$selectedDate $current".dateToTimestamp()
- if (Date(today).after(Date())) {
- "建设年代不能早于当前日期".show(context)
- } else {
- datePicker.dismiss()
- binding.objectInclude.constructDateView.text = selectedDate
- }
- }
- }
-
- binding.identifierInclude.identifierTypeSpinner.show(
- this@MainActivity, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
- )
-
- binding.identifierInclude.installTimeView.text =
- System.currentTimeMillis().timestampToCompleteDate()
-
- binding.identifierInclude.colorSpinner.show(
- this@MainActivity, LocaleConstant.COLOR_ARRAY, 0
- )
-
- imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
- override fun onAddImageClick() {
- takePicture()
- }
-
- override fun onItemClick(position: Int) {
- if (realPaths[position].isEmpty()) {
- "图片加载失败,无法查看大图".show(context)
- } else {
- context.navigatePageTo(position, realPaths)
- }
- }
-
- override fun onItemLongClick(view: View?, position: Int) {
- imageAdapter.deleteImage(position)
- }
- })
- /**************************************************************************************/
- }
-
- //清除默认数据
- fun clearDefaultData() {
- "markerObjectTypeView".setDefaultValue("")
- "pipelineDiameterView".setDefaultValue("")
- "buryDeepView".setDefaultValue("")
- "bottomPipeDiameterView".setDefaultValue("")
- "bottomPointDeepView".setDefaultValue("")
- "areaView".setDefaultValue("")
- "lineView".setDefaultValue("")
- "roadView".setDefaultValue("")
- "ownerView".setDefaultValue("")
- "identifierDeepView".setDefaultValue("")
- "personDeptView".setDefaultValue("")
- }
-
- private fun saveMarkerInLocal() {
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
-
- val marker = MarkerLocalBean()
- marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
- marker.pipelineType =
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
- marker.pipelineMaterial =
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
- marker.pipelineDiameter =
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
- marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
- marker.underlyingPipelineType =
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
- marker.underlyingPipelineMaterial =
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
- marker.underlyingPipelineDiameter =
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
- marker.underlyingPipelineDepth =
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
- marker.buryMethod =
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
- marker.area = binding.objectInclude.areaView.text.toString()
- marker.line = binding.objectInclude.lineView.text.toString()
- marker.road = binding.objectInclude.roadView.text.toString()
- marker.constructTime = binding.objectInclude.constructDateView.text.toString()
- marker.owner = binding.objectInclude.ownerView.text.toString()
- marker.objectId = objectId
- marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
- marker.markerType =
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
- marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
- marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
- marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
- marker.lng = binding.identifierInclude.lngView.text.toString()
- marker.lat = binding.identifierInclude.latView.text.toString()
- marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
- marker.remark = binding.remarkView.text.toString()
- marker.imagePath = realPaths.toJson()
-
- DataBaseManager.get.saveMarkerInLocale(marker)
- }
-
- private fun takePicture() {
- PictureSelector.create(this@MainActivity).openCamera(SelectMimeType.ofImage())
- .forResult(object : OnResultCallbackListener {
- override fun onResult(result: java.util.ArrayList?) {
- if (result == null) {
- "拍照失败,请重试".show(context)
- return
- }
- analyticalSelectResults(result[0])
- }
-
- override fun onCancel() {
-
- }
- })
- }
-
- private fun analyticalSelectResults(result: LocalMedia) {
- //压缩图片
- result.realPath.compressImage(context, object : OnImageCompressListener {
- override fun onSuccess(file: File) {
- realPaths.add(file.absolutePath)
- imageAdapter.setupImage(realPaths)
- }
-
- override fun onError(e: Throwable) {
- e.printStackTrace()
- }
- })
- }
- }
-
- /**探测标识器新对话框****************************************************************************/
- inner class SearchMarkerNewDialog(private val context: Context) : Dialog(context) {
-
- private val taskId by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
- }
- private val taskCode by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_CODE, "") as String
- }
- private val markerPoints by lazy { ArrayList() }
- private val binding: DialogSearchMarkerNewBinding by binding()
- private var markerId = ""//实际探测出来的标识器ID
- private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID
- private lateinit var searchMarkerTimer: Timer
- private lateinit var signalTask: TimerTask
- private lateinit var energyTask: TimerTask
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
- var isDetectMarker = false
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
- binding.depthButton.setOnClickListener {
- signalTask.cancel()
- energyTask.cancel()
- searchMarkerTimer.cancel()
-
- out.write('3'.code)
- val result = DataBaseManager.get.queryMarkerById(markerId)
- if (result.isNotEmpty()) {
- val tag = when (result.first().markerType) {
- "EM30" -> '7'
- "EM50" -> '8'
- "EM14" -> '9'
- else -> '1'
- }
- if (tag == '1') {
- "此标识器无法读取埋深!".show(context)
- initTimer()
- } else {
- // 发送读取标识器埋设深度指令
- LoadingDialogHub.show(this@MainActivity, "正在测距,请稍后...")
- out.write(tag.code)
- out.flush()
- countDownTimer = object : CountDownTimer(15 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- "探测此标识器深度超时,请重试".show(context)
- initTimer()
- }
- }
- countDownTimer.start()
- }
- } else {
- "标识器未安装,安装成功后才可读取埋深!".show(context)
- initTimer()
- }
- }
-
- binding.markerInfoButton.setOnClickListener {
- val id = if (markerId == "") {
- nearestMarkerId
- } else {
- markerId
- }
- //查库
- val result = DataBaseManager.get.queryMarkerById(id)
- if (result.isNotEmpty()) {
- context.navigatePageTo(result.first().toJson())
- } else {
- context.navigatePageTo(id)
- }
- //查看完就把ID置空,便于下次查看最新的ID
- markerId = ""
- }
- }
-
- override fun show() {
- super.show()
- locationTool = LocationTool(context)
- //点位渲染,每次定位都计算当前位置与符合条件的点距离
- locationTool.getCurrentLocation(false, object : OnGetLocationListener {
- override fun onAMapLocationGet(location: AMapLocation?) {
- location?.apply {
- renderDataPoint(this)
- }
- }
- })
- }
-
- /**
- * 计算并渲染数据点。点太多采用协程计算,不然会有点卡顿
- * @param location 定位点(RTK获取)
- * */
- private fun renderDataPoint(location: AMapLocation) {
- val longitude = location.longitude
- val latitude = location.latitude
- lifecycleScope.launch(Dispatchers.IO) {
- val dataPoints = ArrayList()
- DataBaseManager.get.loadMarkers().forEach {
- val distance = AMapUtils.calculateLineDistance(
- LatLng(it.lat.toDouble(), it.lng.toDouble()), LatLng(latitude, longitude)
- )
- val formatDistance = "%.2f".format(distance).toFloat()
-
- markerPoints.add(MarkerDistanceData(it.markerId, formatDistance))
-
- if (formatDistance <= LocaleConstant.MAX_DISTANCE) {
- val angle = atan2(
- (it.lat.toDouble() - latitude), (it.lng.toDouble() - longitude)
- ) + Math.PI
- val formatAngle = "%.2f".format(angle).toDouble()
- dataPoints.add(
- RadarScanView.DataPoint(formatAngle, formatDistance)
- )
- }
- }
- withContext(Dispatchers.Main) {
- binding.radarScanView.renderPointData(dataPoints,
- object : RadarScanView.OnGetNearestPointCallback {
- override fun getNearestPoint(point: RadarScanView.DataPoint?) {
- if (point == null) {
- binding.distanceValueView.text = "大于5.5m"
- binding.distancePgBar.progress = 100
- } else {
- binding.distanceValueView.text = "${point.distance}m"
- val progress =
- if (point.distance > LocaleConstant.MAX_DISTANCE) {
- 100
- } else {
- (point.distance / LocaleConstant.MAX_DISTANCE) * 100
- }
- binding.distancePgBar.progress = progress.toInt()
- }
- }
- })
- }
- }
- }
-
- override fun onStart() {
- super.onStart()
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- initTimer()
-
- isDetectMarker = true
-
- if (isExecuteTask) {
- binding.taskStateView.visibility = View.GONE
- binding.taskStateView.isSelected = false
- } else {
- binding.taskStateView.visibility = View.VISIBLE
- binding.taskStateView.isSelected = true
- }
- }
-
- fun bindingValue(hex: String) {
- if (hex.startsWith("4E")) {
- try {
- //4E转为String为N,代表能量值
- //用能量值转动表盘
- val energyResponse = hex.take(10).hexToString()
- val energy = energyResponse.substring(1).toInt()
- if (energy >= 4000) {
- soundPool.play(fastSoundResourceId, 1f, 1f, 0, 0, 1f)
- } else {
- soundPool.play(slowSoundResourceId, 1f, 1f, 0, 0, 1f)
- }
-
- //通过设置进度条表示能量值
- binding.energyPgBar.progress = energy
- binding.energyValueView.text = "${energy}dB"
-
- if (energy <= 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.searchResultView.text = "未检测到标识器"
- binding.searchResultView.setTextColor(Color.parseColor("#8D1717"))
- binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_red)
- } else if (energy >= 4100) {
- binding.energyTipsView.text = "信号极强,接近标识器正上方"
- binding.energyTipsView.setTextColor(Color.parseColor("#428d00"))
- binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green)
-
- if (markerPoints.isEmpty()) {
- Log.d(kTag, "bindingValue: markerPoints.isEmpty()")
- return
- }
-
- //需要转一下,不然会有并发问题
- val temp = ArrayList()
- temp.addAll(markerPoints)
- temp.sortBy(MarkerDistanceData::distance)
- val nearestPoint = temp.first()
- nearestMarkerId = nearestPoint.markerId
- handleMarker(nearestMarkerId)
- } else {
- binding.energyTipsView.text = "已靠近,请继续移动位置"
- binding.energyTipsView.setTextColor(Color.parseColor("#8C5700"))
- binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow)
- }
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- } else if (hex.startsWith("53")) {
- LoadingDialogHub.dismiss()
- countDownTimer.cancel()
- try {
- val depthResponse = hex.take(10).hexToString()
- val depth = depthResponse.drop(2).toInt()
- AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示")
- .setMessage("标识器埋深:${depth}厘米").setPositiveButton("知道了")
- .setOnDialogButtonClickListener(object :
- AlertMessageDialog.OnDialogButtonClickListener {
- override fun onConfirmClick() {
- initTimer()
- }
- }).build().show()
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- } else {
- val id = hex.take(20).hexToString()
- if (id.isNumber()) {
- markerId = id
- handleMarker(markerId)
- }
- }
- }
-
- private fun handleMarker(id: String) {
- binding.depthButton.isEnabled = true
- binding.depthButton.setTextColor(Color.WHITE)
- binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
- binding.markerInfoButton.isEnabled = true
- binding.markerInfoButton.setTextColor(Color.WHITE)
- binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)
-
- binding.searchResultView.text = "已检测到标识器"
- binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
- binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)
-
- //自动上传标识器
- if (isExecuteTask) {
- val taskMarkerLocalBean = DataBaseManager.get.queryTaskMarkerById(
- taskId, taskCode, id, "0"
- )
- taskMarkerLocalBean?.apply {
- taskViewModel.uploadMarker(context, this)
- }
- }
- }
-
- //更新罗盘角度
- fun updateDegreeValue(degree: Int) {
- binding.radarScanView.setDegreeValue(degree)
- }
-
- private fun initTimer() {
- searchMarkerTimer = Timer()
-
- signalTask = object : TimerTask() {
- override fun run() {
- out.write('2'.code)
- out.flush()
- }
- }
-
- energyTask = object : TimerTask() {
- override fun run() {
- out.write('6'.code)
- out.flush()
- }
- }
-
- //错开信号和能量定时器
- searchMarkerTimer.schedule(signalTask, 0, 201)
- searchMarkerTimer.schedule(energyTask, 0, 251)
- }
-
- override fun dismiss() {
- signalTask.cancel()
- energyTask.cancel()
- searchMarkerTimer.cancel()
- //降低串口电位
- gpioManager.setGpioLow("18")
- isDetectMarker = false
- soundPool.autoPause()
- locationTool.stopLocation()
- super.dismiss()
- }
- }
-
- /**
- * 标识器与当前定位的数据
- * */
- data class MarkerDistanceData(var markerId: String, var distance: Float)
}
\ 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
new file mode 100644
index 0000000..14fe667
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/view/SearchMarkerActivity.kt
@@ -0,0 +1,462 @@
+package com.casic.detector.common.view
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.graphics.Color
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import android.media.AudioAttributes
+import android.media.SoundPool
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.IBinder
+import android.util.Log
+import android.view.View
+import android.view.WindowManager
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMapUtils
+import com.amap.api.maps.model.LatLng
+import com.casic.detector.common.R
+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.hexToString
+import com.casic.detector.common.extensions.isNumber
+import com.casic.detector.common.extensions.toHex
+import com.casic.detector.common.model.MarkerDistanceData
+import com.casic.detector.common.service.SerialPortService
+import com.casic.detector.common.utils.DataBaseManager
+import com.casic.detector.common.utils.LocaleConstant
+import com.casic.detector.common.utils.LocationTool
+import com.casic.detector.common.vm.TaskViewModel
+import com.casic.detector.common.widgets.RadarScanView
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.Constant
+import com.pengxh.kt.lite.utils.LoadingDialogHub
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.OutputStream
+import java.util.Timer
+import java.util.TimerTask
+import kotlin.math.atan2
+
+class SearchMarkerActivity : KotlinBaseActivity(),
+ SensorEventListener {
+
+ private val kTag = "SearchMarkerActivity"
+ private val context = this
+ private val locationTool by lazy { LocationTool(this) }
+ private val markerPoints by lazy { ArrayList() }
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val sensorManager by lazy { getSystemService()!! }
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private val rotationMatrix = FloatArray(9)//旋转矩阵缓存
+ private val valueArray = FloatArray(3)//方位角数值
+ private var slowSoundResourceId = 0
+ private var fastSoundResourceId = 0
+ private var markerId = ""//实际探测出来的标识器ID
+ private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID
+ private var isExecuteTask = false
+ private var signalEnergy = 0 //标识器信号强度
+ 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 {
+ override fun onServiceConnected(name: ComponentName?, iBinder: IBinder?) {
+ if (iBinder is SerialPortService.ServiceBinder) {
+ serialPortService = iBinder.getSerialPortService()
+ Log.d(kTag, "onServiceConnected: 服务已绑定")
+ searchMarker()
+ }
+ }
+
+ override fun onServiceDisconnected(name: ComponentName?) {
+
+ }
+ }
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ val flag = intent.getStringExtra(Constant.INTENT_PARAM) as String
+ isExecuteTask = flag != "0"
+
+ //绑定串口通信服务
+ Intent(this, SerialPortService::class.java).also {
+ bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
+ }
+
+ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
+ fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)
+
+ //点位渲染,每次定位都计算当前位置与符合条件的点距离
+ locationTool.getCurrentLocation(false, object : OnGetLocationListener {
+ override fun onAMapLocationGet(location: AMapLocation?) {
+ location?.apply {
+ renderDataPoint(this)
+ }
+ }
+ })
+
+ if (isExecuteTask) {
+ binding.taskStateView.visibility = View.GONE
+ binding.taskStateView.isSelected = false
+ } else {
+ binding.taskStateView.visibility = View.VISIBLE
+ binding.taskStateView.isSelected = true
+ }
+
+ //在标识器信号强度很强的时候,从数据库中计算出距离最近的点,以防出现探测不到ID的情况
+ searchSignalEnergyTimer = Timer()
+ searchSignalEnergyTimer.schedule(object : TimerTask() {
+ override fun run() {
+ //markerId为空,说明没有通过探测得到标识器ID,那么就需要通过计算得到近似的标识器
+ if (signalEnergy >= 4100 && markerPoints.isNotEmpty()) {
+ try {
+ //需要转一下,不然会有并发问题
+ val temp = ArrayList()
+ temp.addAll(markerPoints)
+ temp.sortBy(MarkerDistanceData::distance)
+ val nearestPoint = temp.first()
+ nearestMarkerId = nearestPoint.markerId
+ runOnUiThread {
+ handleMarker(nearestMarkerId)
+ }
+ markerPoints.clear()
+ } catch (e: NullPointerException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }, 0, 2000)
+ }
+
+ private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
+ override fun onTick(millisUntilFinished: Long) {
+
+ }
+
+ override fun onFinish() {
+ LoadingDialogHub.dismiss()
+ serialPortService?.closeSerialPort()
+ "标识器深度探测超时,请移动位置重试".show(context)
+ searchMarker()
+ }
+ }
+
+ override fun initEvent() {
+ binding.depthButton.setOnClickListener {
+ stopSearchMarker()
+ val result = DataBaseManager.get.queryMarkerById(markerId)
+ if (result.isNotEmpty()) {
+ val tag = when (result.first().markerType) {
+ "EM30" -> '7'
+ "EM50" -> '8'
+ "EM14" -> '9'
+ else -> '1'
+ }
+ if (tag == '1') {
+ "此标识器无法读取埋深!".show(this)
+ searchMarker()
+ } else {
+ LoadingDialogHub.show(this, "正在探测标识器埋深,请稍后...")
+ countDownTimer.start()
+ // 发送读取标识器埋设深度指令
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ // 发送读取标识器埋设深度指令
+ outStream.write(tag.code)
+ outStream.flush()
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ if (hex.startsWith("53")) {
+ LoadingDialogHub.dismiss()
+ countDownTimer.cancel()
+ try {
+ val depthResponse = hex.take(10).hexToString()
+ val depth = depthResponse.drop(2).toInt()
+ AlertMessageDialog.Builder().setContext(context)
+ .setTitle("温馨提示")
+ .setMessage("标识器埋深:${depth}厘米")
+ .setPositiveButton("知道了")
+ .setOnDialogButtonClickListener(object :
+ AlertMessageDialog.OnDialogButtonClickListener {
+ override fun onConfirmClick() {
+ serialPortService?.closeSerialPort()
+ searchMarker()
+ }
+ }).build().show()
+ } catch (e: WindowManager.BadTokenException) {
+ e.printStackTrace()
+ } catch (e: NumberFormatException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ })
+ }
+ } else {
+ LoadingDialogHub.dismiss()
+ "标识器未安装,安装成功后才可读取埋深!".show(this)
+ searchMarker()
+ }
+ }
+
+ binding.markerInfoButton.setOnClickListener {
+ val id = if (markerId == "") {
+ nearestMarkerId
+ } else {
+ markerId
+ }
+ //查库
+ val result = DataBaseManager.get.queryMarkerById(id)
+ if (result.isNotEmpty()) {
+ navigatePageTo(result.first().toJson())
+ } else {
+ navigatePageTo(id)
+ }
+ //查看完就把ID置空,便于下次查看最新的ID
+ markerId = ""
+ }
+ }
+
+ /**
+ * 搜索标识器
+ * */
+ private fun searchMarker() {
+ Thread.sleep(100)
+
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ searchMarkerTimer = Timer()
+ searchMarkerTimer.schedule(object : TimerTask() {
+ override fun run() {
+ outStream.write('2'.code)
+ outStream.flush()
+
+ Thread.sleep(50)
+
+ outStream.write('6'.code)
+ outStream.flush()
+ }
+ }, 0, 200)
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ 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)
+ }
+
+ //通过设置进度条表示能量值
+ 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)
+
+ 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()
+ }
+ } else {
+ val id = hex.take(20).hexToString()
+ if (id.isNumber()) {
+ markerId = id
+ handleMarker(markerId)
+ }
+ }
+ }
+ })
+ }
+
+ private fun stopSearchMarker() {
+ soundPool.autoPause()
+ searchMarkerTimer.cancel()
+ serialPortService?.closeSerialPort()
+
+ Thread.sleep(100)
+ }
+
+ /**
+ * 计算并渲染数据点。点太多采用协程计算,不然会有点卡顿。默认2s计算一次
+ * @param location 定位点(RTK获取)
+ * */
+ private fun renderDataPoint(location: AMapLocation) {
+ val longitude = location.longitude
+ val latitude = location.latitude
+ lifecycleScope.launch(Dispatchers.IO) {
+ val dataPoints = ArrayList()
+ DataBaseManager.get.loadMarkers().forEach {
+ val distance = AMapUtils.calculateLineDistance(
+ LatLng(it.lat.toDouble(), it.lng.toDouble()), LatLng(latitude, longitude)
+ )
+ val formatDistance = "%.2f".format(distance).toFloat()
+ markerPoints.add(MarkerDistanceData(it.markerId, formatDistance))
+
+ if (formatDistance <= LocaleConstant.MAX_DISTANCE) {
+ val angle = atan2(
+ (it.lat.toDouble() - latitude), (it.lng.toDouble() - longitude)
+ ) + Math.PI
+ val formatAngle = "%.2f".format(angle).toDouble()
+
+ dataPoints.add(RadarScanView.DataPoint(formatAngle, formatDistance))
+ }
+ }
+ withContext(Dispatchers.Main) {
+ binding.radarScanView.renderPointData(dataPoints,
+ object : RadarScanView.OnGetNearestPointCallback {
+ override fun getNearestPoint(point: RadarScanView.DataPoint?) {
+ if (point == null) {
+ binding.distanceValueView.text = "大于5.5m"
+ binding.distancePgBar.progress = 100
+ } else {
+ binding.distanceValueView.text = "${point.distance}m"
+ val progress = if (point.distance > LocaleConstant.MAX_DISTANCE) {
+ 100
+ } else {
+ (point.distance / LocaleConstant.MAX_DISTANCE) * 100
+ }
+ binding.distancePgBar.progress = progress.toInt()
+ }
+ }
+ }
+ )
+ }
+ }
+ }
+
+ override fun initViewBinding(): ActivitySearchMarkerBinding {
+ return ActivitySearchMarkerBinding.inflate(layoutInflater)
+ }
+
+ override fun observeRequestState() {
+
+ }
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ private fun handleMarker(id: String) {
+ binding.depthButton.isEnabled = true
+ binding.depthButton.setTextColor(Color.WHITE)
+ binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
+ binding.markerInfoButton.isEnabled = true
+ binding.markerInfoButton.setTextColor(Color.WHITE)
+ binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)
+
+ binding.searchResultView.text = "已检测到标识器"
+ binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
+ binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)
+
+ //自动上传标识器
+ if (isExecuteTask) {
+ val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
+ val taskCode = SaveKeyValues.getValue(LocaleConstant.TASK_CODE, "") as String
+ val taskMarkerLocalBean = DataBaseManager.get.queryTaskMarkerById(
+ taskId, taskCode, id, "0"
+ )
+ taskMarkerLocalBean?.apply {
+ taskViewModel.uploadMarker(context, this)
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ //注册加速度传感器监听
+ val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
+ sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)
+
+ //注册磁场传感器监听
+ val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
+ sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL)
+ }
+
+ override fun onPause() {
+ super.onPause()
+ sensorManager.unregisterListener(this)
+ }
+
+ override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
+ //精度发生变化时触发
+ }
+
+ override fun onSensorChanged(event: SensorEvent?) {
+ //值发生变化时触发
+ val type = event?.sensor?.type
+
+ if (type == Sensor.TYPE_ACCELEROMETER) {
+ gravity = event.values
+ } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
+ geomagnetic = event.values
+ }
+
+ if (gravity == null || geomagnetic == null) {
+ return
+ }
+
+ if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
+ SensorManager.getOrientation(rotationMatrix, valueArray)
+
+ val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt()
+ //更新罗盘角度
+ binding.radarScanView.setDegreeValue(degree)
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ stopSearchMarker()
+ locationTool.stopLocation()
+ unbindService(serviceConnection)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_install_marker.xml b/app/src/main/res/layout/activity_install_marker.xml
new file mode 100644
index 0000000..65c2262
--- /dev/null
+++ b/app/src/main/res/layout/activity_install_marker.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_search_marker.xml b/app/src/main/res/layout/activity_search_marker.xml
new file mode 100644
index 0000000..b989df8
--- /dev/null
+++ b/app/src/main/res/layout/activity_search_marker.xml
@@ -0,0 +1,178 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_install_marker.xml b/app/src/main/res/layout/dialog_install_marker.xml
deleted file mode 100644
index 65c2262..0000000
--- a/app/src/main/res/layout/dialog_install_marker.xml
+++ /dev/null
@@ -1,122 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
index 458f3fb..ca7de13 100644
--- a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
+++ b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
@@ -4,6 +4,7 @@
import com.casic.detector.common.greendao.DaoMaster
import com.casic.detector.common.greendao.DaoSession
import com.casic.detector.common.uart.SerialPort
+import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.SaveKeyValues
import java.io.File
import java.io.IOException
@@ -13,23 +14,12 @@
class BaseApplication : Application() {
private val kTag = "BaseApplication"
- private var serialPorts: ArrayList? = null
+ private var serialPorts = ArrayList()
- @Throws(SecurityException::class, IOException::class, InvalidParameterException::class)
- fun getSerialPorts(): ArrayList? {
- serialPorts = ArrayList()
- /**
- * Open the serial port
- * */
- serialPorts?.apply {
- add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
- add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
- }
- return serialPorts
- }
+ fun getSerialPorts(): ArrayList = serialPorts
fun closeSerialPort() {
- serialPorts?.forEach {
+ serialPorts.forEach {
it.closeSerialPort()
}
}
@@ -49,6 +39,22 @@
val devOpenHelper = DaoMaster.DevOpenHelper(this, "Detector_Common.db", null)
val daoMaster = DaoMaster(devOpenHelper.writableDatabase)
daoSession = daoMaster.newSession()
+
+ /**
+ * Open the serial port
+ * */
+ try {
+ serialPorts.apply {
+ add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
+ add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
+ }
+ } catch (e: SecurityException) {
+ "您没有串口的读写权限!".show(this)
+ } catch (e: IOException) {
+ "因为不明原因,串口无法打开!".show(this)
+ } catch (e: InvalidParameterException) {
+ "请检查串口!".show(this)
+ }
}
fun getDaoSession(): DaoSession {
diff --git a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt b/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
deleted file mode 100644
index 297ac02..0000000
--- a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.casic.detector.common.base
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.lifecycleScope
-import androidx.viewbinding.ViewBinding
-import com.pengxh.kt.lite.extensions.show
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.IOException
-import java.io.OutputStream
-import java.security.InvalidParameterException
-
-
-abstract class SerialPortActivity : AppCompatActivity() {
-
- protected lateinit var binding: VB
-
- lateinit var out: OutputStream
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = initViewBinding()
- setContentView(binding.root)
- setupTopBarLayout()
- initOnCreate(savedInstanceState)
- observeRequestState()
- initEvent()
-
- try {
- val serialPorts = BaseApplication.get().getSerialPorts()
- //读
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[0].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[1].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- //写
- serialPorts?.apply {
- out = this[0].outputStream
- }
- } catch (e: SecurityException) {
- "您没有串口的读写权限!".show(this)
- } catch (e: IOException) {
- "因为不明原因,串口无法打开!".show(this)
- } catch (e: InvalidParameterException) {
- "请检查串口!".show(this)
- }
- }
-
- /**
- * 初始化ViewBinding
- */
- abstract fun initViewBinding(): VB
-
- /**
- * 特定页面定制沉浸式状态栏
- */
- abstract fun setupTopBarLayout()
-
- /**
- * 初始化默认数据
- */
- abstract fun initOnCreate(savedInstanceState: Bundle?)
-
- /**
- * 数据请求状态监听
- */
- abstract fun observeRequestState()
-
- /**
- * 初始化业务逻辑
- */
- abstract fun initEvent()
-
- /**
- * 串口读数,已经切回主线程
- * */
- abstract fun onDataReceived(buffer: ByteArray)
-
- override fun onDestroy() {
- super.onDestroy()
- BaseApplication.get().closeSerialPort()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
new file mode 100644
index 0000000..b06a068
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
@@ -0,0 +1,9 @@
+package com.casic.detector.common.callback
+
+import java.io.OutputStream
+
+interface OnSerialPortDataListener {
+ fun write(outStream: OutputStream)
+
+ fun onDataReceived(buffer: ByteArray)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
new file mode 100644
index 0000000..b1685d5
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
@@ -0,0 +1,6 @@
+package com.casic.detector.common.model
+
+/**
+ * 标识器与当前定位的数据
+ * */
+data class MarkerDistanceData(var markerId: String, var distance: Float)
diff --git a/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
new file mode 100644
index 0000000..090f604
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
@@ -0,0 +1,104 @@
+package com.casic.detector.common.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+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.base.BaseApplication
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.utils.GpioManager
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.IOException
+
+class SerialPortService : Service(), LifecycleOwner {
+
+ private val kTag = "SerialPortService"
+ private val registry = LifecycleRegistry(this)
+ private val gpioManager by lazy { GpioManager() }
+ private val serialPorts by lazy { BaseApplication.get().getSerialPorts() }
+ private var gpioState = ""
+
+ override fun getLifecycle(): Lifecycle {
+ return registry
+ }
+
+ override fun onBind(intent: Intent?): IBinder {
+ return ServiceBinder()
+ }
+
+ inner class ServiceBinder : Binder() {
+ fun getSerialPortService(): SerialPortService {
+ return this@SerialPortService
+ }
+ }
+
+ fun openSerialPort(listener: OnSerialPortDataListener) {
+ //调高串口电位
+ gpioManager.setGpioHigh("18")
+ gpioState = "1"
+ Log.d(kTag, "openSerialPort: 调高串口电位")
+
+ Thread.sleep(100)
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ //写
+ listener.write(this[0].outputStream)
+ val stream = this[0].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ val stream = this[1].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+ }
+
+ fun closeSerialPort() {
+ //降低串口电位
+ gpioManager.setGpioLow("18")
+ gpioState = "0"
+ Log.d(kTag, "closeSerialPort: 降低串口电位")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
new file mode 100644
index 0000000..b50aaaf
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
@@ -0,0 +1,548 @@
+package com.casic.detector.common.view
+
+import android.app.DatePickerDialog
+import android.content.ComponentName
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
+import android.media.AudioAttributes
+import android.media.SoundPool
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.IBinder
+import android.util.Log
+import android.view.View
+import android.widget.AdapterView
+import androidx.lifecycle.ViewModelProvider
+import com.amap.api.location.AMapLocation
+import com.casic.detector.common.R
+import com.casic.detector.common.adapter.EditableImageAdapter
+import com.casic.detector.common.bean.MarkerLocalBean
+import com.casic.detector.common.callback.OnGetLocationListener
+import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.databinding.ActivityInstallMarkerBinding
+import com.casic.detector.common.extensions.compressImage
+import com.casic.detector.common.extensions.getDefaultValue
+import com.casic.detector.common.extensions.hexToString
+import com.casic.detector.common.extensions.isNumber
+import com.casic.detector.common.extensions.setDefaultValue
+import com.casic.detector.common.extensions.show
+import com.casic.detector.common.extensions.toColor
+import com.casic.detector.common.extensions.toHex
+import com.casic.detector.common.extensions.toObjectType
+import com.casic.detector.common.service.SerialPortService
+import com.casic.detector.common.utils.DataBaseManager
+import com.casic.detector.common.utils.LocaleConstant
+import com.casic.detector.common.utils.LocationTool
+import com.casic.detector.common.vm.TaskViewModel
+import com.luck.picture.lib.basic.PictureSelector
+import com.luck.picture.lib.config.SelectMimeType
+import com.luck.picture.lib.entity.LocalMedia
+import com.luck.picture.lib.interfaces.OnResultCallbackListener
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.appendZero
+import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.extensions.dateToTimestamp
+import com.pengxh.kt.lite.extensions.navigatePageTo
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.extensions.timestampToCompleteDate
+import com.pengxh.kt.lite.extensions.timestampToTime
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.LoadState
+import com.pengxh.kt.lite.utils.LoadingDialogHub
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import java.io.File
+import java.io.OutputStream
+import java.util.Calendar
+import java.util.Date
+
+class InstallMarkerActivity : KotlinBaseActivity() {
+
+ private val kTag = "InstallMarkerActivity"
+ private val context = this
+ private val calendar by lazy { Calendar.getInstance() }
+ private val locationTool by lazy { LocationTool(this) }
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val realPaths = ArrayList() //真实图片路径
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var soundResourceId = 0
+ private var serialPortService: SerialPortService? = null
+ private lateinit var imageAdapter: EditableImageAdapter
+
+ override fun initEvent() {
+ //返回
+ binding.titleInclude.leftBackView.setOnClickListener {
+ soundPool.autoPause()
+ finish()
+ }
+
+ binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
+ object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(
+ parent: AdapterView<*>?, view: View?, position: Int, id: Long
+ ) {
+ when (position) {
+ 0 -> {
+ //显示管线属性
+ binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 1 -> {
+ //显示管线附属物属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 2 -> {
+ //显示管线特征点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 3 -> {
+ //显示交叉穿越点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.VISIBLE
+ }
+ }
+ }
+
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+
+ }
+ }
+
+ //安装
+ binding.installButton.setOnClickListener {
+ val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+ if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
+ when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
+ "管线" -> "请输入管线种类!".show(this)
+ "管线附属物" -> "请输入附属物名称!".show(this)
+ "管线特征管点" -> "请输入特征管点!".show(this)
+ "交叉穿越点" -> "请输入上层管种类!".show(this)
+ }
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
+ if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
+ "请输入管径".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
+ "请输入埋深".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
+ if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
+ "请输入下层管管径".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.areaView.text.isNullOrBlank()) {
+ "请输入所属区域".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.lineView.text.isNullOrBlank()) {
+ "请输入所属线路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.roadView.text.isNullOrBlank()) {
+ "请输入所属道路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
+ "请选择建设年代".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
+ "请输入权属单位".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
+ "请先读取标识器获取ID".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
+ "请输入标识器埋深".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
+ "请输入标识器安装部门".show(this)
+ return@setOnClickListener
+ }
+
+ //先存本地再上传服务器
+ saveMarkerInLocal()
+
+ taskViewModel.installLabel(
+ this, companyId,
+ binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
+ binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
+ "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.areaView.text.toString(),
+ binding.objectInclude.lineView.text.toString(),
+ binding.objectInclude.roadView.text.toString(),
+ binding.objectInclude.constructDateView.text.toString(),
+ binding.objectInclude.ownerView.text.toString(),
+ objectId,
+ binding.identifierInclude.identifierIdView.text.toString(),
+ binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
+ "${binding.identifierInclude.identifierDeepView.text}mm",
+ binding.identifierInclude.personDeptView.text.toString(),
+ binding.identifierInclude.installTimeView.text.toString(),
+ binding.identifierInclude.lngView.text.toString(),
+ binding.identifierInclude.latView.text.toString(),
+ binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
+ binding.remarkView.text.toString(),
+ realPaths
+ )
+
+ //保存默认值
+ "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
+ "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
+ "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
+ "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
+ "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
+ "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
+ "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
+ "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
+ "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
+ "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
+ "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
+ }
+
+ //读标识器
+ binding.readMarkerButton.setOnClickListener {
+ LoadingDialogHub.show(this, "标识器读取中,请稍后...")
+ countDownTimer.start()
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ outStream.write('2'.code)
+ outStream.flush()
+
+ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
+ binding.readMarkerButton.isEnabled = false
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ Log.d(kTag, hex)
+ val markerId = hex.take(20).hexToString()
+ if (markerId.isNumber()) {
+ countDownTimer.cancel()
+ cancelLoadingView()
+ binding.readMarkerButton.isEnabled = true
+ binding.identifierInclude.identifierIdView.text = markerId
+ }
+ }
+ })
+ }
+ }
+
+ /**
+ * 搜索标识器超时倒计时
+ * */
+ private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
+ override fun onTick(millisUntilFinished: Long) {
+
+ }
+
+ override fun onFinish() {
+ cancelLoadingView()
+ "读取此标识器ID超时,请重试".show(context)
+ binding.readMarkerButton.isEnabled = true
+ }
+ }
+
+ private fun cancelLoadingView() {
+ LoadingDialogHub.dismiss()
+ soundPool.autoPause()
+ serialPortService?.closeSerialPort()
+ }
+
+ private fun saveMarkerInLocal() {
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+
+ val marker = MarkerLocalBean()
+ marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
+ marker.pipelineType = binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
+ marker.pipelineMaterial =
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
+ marker.pipelineDiameter = "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
+ marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
+ marker.underlyingPipelineType =
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
+ marker.underlyingPipelineMaterial =
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
+ marker.underlyingPipelineDiameter =
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
+ marker.underlyingPipelineDepth =
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
+ marker.buryMethod =
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
+ marker.area = binding.objectInclude.areaView.text.toString()
+ marker.line = binding.objectInclude.lineView.text.toString()
+ marker.road = binding.objectInclude.roadView.text.toString()
+ marker.constructTime = binding.objectInclude.constructDateView.text.toString()
+ marker.owner = binding.objectInclude.ownerView.text.toString()
+ marker.objectId = objectId
+ marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
+ marker.markerType = binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
+ marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
+ marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
+ marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
+ marker.lng = binding.identifierInclude.lngView.text.toString()
+ marker.lat = binding.identifierInclude.latView.text.toString()
+ marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
+ marker.remark = binding.remarkView.text.toString()
+ marker.imagePath = realPaths.toJson()
+
+ DataBaseManager.get.saveMarkerInLocale(marker)
+ }
+
+ private fun takePicture() {
+ PictureSelector.create(this).openCamera(SelectMimeType.ofImage())
+ .forResult(object : OnResultCallbackListener {
+ override fun onResult(result: ArrayList?) {
+ if (result == null) {
+ "拍照失败,请重试".show(context)
+ return
+ }
+ analyticalSelectResults(result[0])
+ }
+
+ override fun onCancel() {
+
+ }
+ })
+ }
+
+ private fun analyticalSelectResults(result: LocalMedia) {
+ //压缩图片
+ result.realPath.compressImage(context, object : OnImageCompressListener {
+ override fun onSuccess(file: File) {
+ realPaths.add(file.absolutePath)
+ imageAdapter.setupImage(realPaths)
+ }
+
+ override fun onError(e: Throwable) {
+ e.printStackTrace()
+ }
+ })
+ }
+
+ 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?) {
+ //在连接正常关闭的情况下不会被调用, 只在Service被破坏了或者被杀死的时候调用
+ }
+ }
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ //绑定串口通信服务
+ Intent(this, SerialPortService::class.java).also {
+ bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
+ }
+
+ locationTool.getCurrentLocation(true, object : OnGetLocationListener {
+ override fun onAMapLocationGet(location: AMapLocation?) {
+ if (location != null) {
+ binding.identifierInclude.lngView.text = location.longitude.toString()
+ binding.identifierInclude.latView.text = location.latitude.toString()
+ } else {
+ "当前位置信号差,无法获取定位".show(context)
+ }
+ }
+ })
+ soundResourceId = soundPool.load(this, R.raw.ring3, 1)
+
+ //初始化数据
+ initDefaultData()
+ }
+
+ override fun initViewBinding(): ActivityInstallMarkerBinding {
+ return ActivityInstallMarkerBinding.inflate(layoutInflater)
+ }
+
+ override fun observeRequestState() {
+ taskViewModel.loadState.observe(this) {
+ when (it) {
+ LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...")
+
+ LoadState.Success -> {
+ LoadingDialogHub.dismiss()
+ clearDefaultData()
+ "安装成功".show(this)
+ }
+
+ else -> LoadingDialogHub.dismiss()
+ }
+ }
+ }
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ private fun initDefaultData() {
+ binding.titleInclude.titleView.text = "安装新标识器"
+ binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
+
+ imageAdapter = EditableImageAdapter(this, 3, 3)
+ binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
+
+ //设置默认值
+ binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
+ binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
+ binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
+ binding.objectInclude.areaView.setText("areaView".getDefaultValue())
+ binding.objectInclude.lineView.setText("lineView".getDefaultValue())
+ binding.objectInclude.roadView.setText("roadView".getDefaultValue())
+ binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
+ binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
+ binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
+
+ /**************************************************************************************/
+ binding.objectInclude.objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0)
+ binding.objectInclude.pipeInclude.materialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeAttachInclude.attachSpinner.show(
+ this, LocaleConstant.ATTACH_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
+ this, LocaleConstant.FEATURE_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeInclude.buryTypeSpinner.show(
+ this, LocaleConstant.BURY_METHOD_ARRAY, 0
+ )
+ binding.objectInclude.constructDateView.setOnClickListener {
+ val datePicker = DatePickerDialog(
+ this, null,
+ calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH),
+ calendar.get(Calendar.DAY_OF_MONTH)
+ )
+ datePicker.show()
+
+ datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
+ val year = datePicker.datePicker.year
+ val month = datePicker.datePicker.month + 1
+ val day = datePicker.datePicker.dayOfMonth
+ val selectedDate = String.format(
+ "%s-%s-%s", year, month.appendZero(), day.appendZero()
+ )
+
+ //当前时间
+ val current = System.currentTimeMillis().timestampToTime()
+ val today = "$selectedDate $current".dateToTimestamp()
+ if (Date(today).after(Date())) {
+ "建设年代不能早于当前日期".show(context)
+ } else {
+ datePicker.dismiss()
+ binding.objectInclude.constructDateView.text = selectedDate
+ }
+ }
+ }
+ binding.identifierInclude.identifierTypeSpinner.show(
+ this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
+ )
+ binding.identifierInclude.installTimeView.text =
+ System.currentTimeMillis().timestampToCompleteDate()
+ binding.identifierInclude.colorSpinner.show(this, LocaleConstant.COLOR_ARRAY, 0)
+
+ imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
+ override fun onAddImageClick() {
+ takePicture()
+ }
+
+ override fun onItemClick(position: Int) {
+ if (realPaths[position].isEmpty()) {
+ "图片加载失败,无法查看大图".show(context)
+ } else {
+ navigatePageTo(position, realPaths)
+ }
+ }
+
+ override fun onItemLongClick(view: View?, position: Int) {
+ imageAdapter.deleteImage(position)
+ }
+ })
+ }
+
+ //清除默认数据
+ private fun clearDefaultData() {
+ "markerObjectTypeView".setDefaultValue("")
+ "pipelineDiameterView".setDefaultValue("")
+ "buryDeepView".setDefaultValue("")
+ "bottomPipeDiameterView".setDefaultValue("")
+ "bottomPointDeepView".setDefaultValue("")
+ "areaView".setDefaultValue("")
+ "lineView".setDefaultValue("")
+ "roadView".setDefaultValue("")
+ "ownerView".setDefaultValue("")
+ "identifierDeepView".setDefaultValue("")
+ "personDeptView".setDefaultValue("")
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ soundPool.autoPause()
+ locationTool.stopLocation()
+ 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 1dac658..f949269 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,31 +1,25 @@
package com.casic.detector.common.view
-import android.app.DatePickerDialog
-import android.app.Dialog
+import android.content.ComponentName
import android.content.Context
-import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
-import android.hardware.Sensor
-import android.hardware.SensorEvent
-import android.hardware.SensorEventListener
-import android.hardware.SensorManager
import android.media.AudioAttributes
import android.media.SoundPool
import android.os.Bundle
-import android.os.CountDownTimer
+import android.os.IBinder
import android.util.Log
import android.view.KeyEvent
import android.view.View
-import android.widget.AdapterView
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.amap.api.location.AMapLocation
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
-import com.amap.api.maps.AMapUtils
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.CoordinateConverter
import com.amap.api.maps.model.BitmapDescriptorFactory
@@ -34,38 +28,29 @@
import com.amap.api.maps.model.MarkerOptions
import com.amap.api.maps.model.MyLocationStyle
import com.casic.detector.common.R
-import com.casic.detector.common.adapter.EditableImageAdapter
-import com.casic.detector.common.base.SerialPortActivity
+import com.casic.detector.common.base.BaseApplication
import com.casic.detector.common.bean.MarkerLocalBean
import com.casic.detector.common.bean.TaskLocalBean
import com.casic.detector.common.callback.OnGetLocationListener
-import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
import com.casic.detector.common.cluster.ClusterItem
import com.casic.detector.common.cluster.ClusterOverlay
import com.casic.detector.common.cluster.RegionItem
import com.casic.detector.common.databinding.ActivityMainBinding
-import com.casic.detector.common.databinding.DialogInstallMarkerBinding
-import com.casic.detector.common.databinding.DialogSearchMarkerNewBinding
import com.casic.detector.common.extensions.appendDownloadUrl
-import com.casic.detector.common.extensions.compressImage
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.getDefaultValue
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.setDefaultValue
-import com.casic.detector.common.extensions.show
-import com.casic.detector.common.extensions.toColor
import com.casic.detector.common.extensions.toHex
-import com.casic.detector.common.extensions.toObjectType
import com.casic.detector.common.model.TaskDetailLocalModel
import com.casic.detector.common.model.TaskModel
+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.GpioManager
import com.casic.detector.common.utils.LocaleConstant
import com.casic.detector.common.utils.LocationTool
import com.casic.detector.common.utils.NtripAuthorizationCreator
@@ -77,26 +62,15 @@
import com.casic.detector.common.vm.TaskViewModel
import com.casic.detector.common.widgets.MarkerDetailDialog
import com.casic.detector.common.widgets.QueryMarkerDialog
-import com.casic.detector.common.widgets.RadarScanView
import com.casic.detector.common.widgets.SamplePopupWindow
-import com.luck.picture.lib.basic.PictureSelector
-import com.luck.picture.lib.config.SelectMimeType
-import com.luck.picture.lib.entity.LocalMedia
-import com.luck.picture.lib.interfaces.OnResultCallbackListener
-import com.pengxh.kt.lite.extensions.appendZero
-import com.pengxh.kt.lite.extensions.binding
-import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertDrawable
import com.pengxh.kt.lite.extensions.createDownloadFileDir
-import com.pengxh.kt.lite.extensions.dateToTimestamp
import com.pengxh.kt.lite.extensions.dp2px
-import com.pengxh.kt.lite.extensions.getSystemService
-import com.pengxh.kt.lite.extensions.initDialogLayoutParams
import com.pengxh.kt.lite.extensions.isNetworkConnected
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.extensions.timestampToCompleteDate
-import com.pengxh.kt.lite.extensions.timestampToTime
import com.pengxh.kt.lite.extensions.toJson
import com.pengxh.kt.lite.utils.FileDownloadManager
import com.pengxh.kt.lite.utils.LoadState
@@ -108,60 +82,41 @@
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
import io.netty.buffer.Unpooled
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
+import java.io.OutputStream
import java.nio.charset.StandardCharsets
-import java.util.Calendar
-import java.util.Date
import java.util.Timer
import java.util.TimerTask
-import kotlin.math.atan2
-class MainActivity : SerialPortActivity(), SensorEventListener,
- OnSocketConnectListener {
+class MainActivity : KotlinBaseActivity(), OnSocketConnectListener {
private val kTag = "MainActivity"
private val context = this
private val samplePopupWindow by lazy { SamplePopupWindow(this) }
private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) }
private val backDrawables by lazy { HashMap() }
- private val installDialog by lazy { InstallMarkerDialog(this) }
- private val searchNewDialog by lazy { SearchMarkerNewDialog(this) }
private val detailDialog by lazy { MarkerDetailDialog(this) }
private val locationTool by lazy { LocationTool(this) }
- private val rotationMatrix = FloatArray(9)//旋转矩阵缓存
- private val valueArray = FloatArray(3)//方位角数值
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
private var clickTime: Long = 0
private var markers = ArrayList()
private var clusterOverlay: ClusterOverlay? = null
private var isFreeTask = false
private var freeTaskTitle = ""
private var ids = HashSet()
- private var signalTask: TimerTask? = null
- private var energyTask: TimerTask? = null
- private var searchMarkerTimer: Timer? = null
private var freeTaskId: String? = null
- private var gravity: FloatArray? = null
- private var geomagnetic: FloatArray? = null
private var connectState = ConnectState.CLOSED
private var socketClient: SocketClient? = null
- private lateinit var aMap: AMap
- private lateinit var sensorManager: SensorManager
-
- /***inner class 需要用到*****start*/
- private val gpioManager by lazy { GpioManager() }
- private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
- private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
- .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
- private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var serialPortService: SerialPortService? = null
+ private var searchMarkerTimer: Timer? = null
private var soundResourceId = 0
- private var slowSoundResourceId = 0
- private var fastSoundResourceId = 0
private var isExecuteTask = false
-
- /***inner class 需要用到*****end*/
+ private lateinit var aMap: AMap
override fun initViewBinding(): ActivityMainBinding {
return ActivityMainBinding.inflate(layoutInflater)
@@ -171,10 +126,26 @@
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)
+ }
+
soundResourceId = soundPool.load(this, R.raw.ring3, 1)
- slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
- fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)
RtkLocationTool.getCurrentLocation(this) {
if (connectState == ConnectState.SUCCESS) {
@@ -192,8 +163,6 @@
samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES)
samplePopupWindow.setBackgroundDrawable(null)
- sensorManager = getSystemService()!!
-
//task网络请求监听
taskViewModel.markerFileResult.observe(this) {
if (it.isSuccess) {
@@ -316,9 +285,6 @@
//安装。上传,然后存入本地库
binding.installButton.setOnClickListener {
- /**
- * 改为Dialog方式,避免频繁打开/关闭串口
- * */
if (isFreeTask) {
AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示")
.setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能")
@@ -329,7 +295,7 @@
}
}).build().show()
} else {
- installDialog.show()
+ navigatePageTo()
}
}
@@ -449,8 +415,6 @@
//探测
binding.detectionButton.setOnClickListener {
/**
- * 改为Dialog方式,避免频繁打开/关闭串口
- *
* 如果开启自由巡检就不让探测
* */
if (isFreeTask) {
@@ -463,7 +427,12 @@
}
}).build().show()
} else {
- searchNewDialog.show()
+ val flag = if (isExecuteTask) {
+ "1"
+ } else {
+ "0"
+ }
+ navigatePageTo(flag)
}
}
@@ -476,14 +445,8 @@
override fun onConfirmClick() {
isFreeTask = false
soundPool.autoPause()
-
- //停止信号和ID搜索定时器
- signalTask?.cancel()
- energyTask?.cancel()
searchMarkerTimer?.cancel()
-
- //降低串口电位
- gpioManager.setGpioLow("18")
+ serialPortService?.closeSerialPort()
binding.stopFreeTaskButton.visibility = View.GONE
if (freeTaskId.isNullOrBlank()) {
@@ -527,110 +490,79 @@
}
private fun openSerialPort() {
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- isFreeTask = true
- //自由巡检
- signalTask = object : TimerTask() {
- override fun run() {
- out.write('2'.code)
- out.flush()
- }
- }
-
- energyTask = object : TimerTask() {
- override fun run() {
- out.write('6'.code)
- out.flush()
- }
- }
-
- searchMarkerTimer = Timer()
- searchMarkerTimer?.apply {
- schedule(signalTask, 0, 200)
- schedule(energyTask, 0, 251)
- }
-
binding.stopFreeTaskButton.visibility = View.VISIBLE
- }
+ isFreeTask = true
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ searchMarkerTimer = Timer()
+ searchMarkerTimer?.schedule(object : TimerTask() {
+ override fun run() {
+ outStream.write('2'.code)
+ outStream.flush()
- override fun onDataReceived(buffer: ByteArray) {
- val hex = buffer.toHex()
-// Log.d(kTag, "$kTag => $hex")
- if (searchNewDialog.isDetectMarker) {
- searchNewDialog.bindingValue(hex)
- } else if (installDialog.isReadMarker) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- installDialog.bindingValue(markerId)
+ Thread.sleep(50)
+
+ outStream.write('6'.code)
+ outStream.flush()
+ }
+ }, 0, 200)
}
- } else if (isFreeTask) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- //只响一次,因为探测频率高,所以依旧是连续的报警声
- soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
- //添加地图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))
- )
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ if (hex.startsWith("4E")) {
+ //只响一次,因为探测频率高,所以依旧是连续的报警声
+ soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
+
+ 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()
}
}
- 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()
+ 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 (hex.startsWith("4E")) {
- val energyResponse = hex.take(10).hexToString()
- try {
- val energy = energyResponse.substring(1).toInt()
- if (energy <= 500 && detailDialog.isShowing) {
- detailDialog.dismiss()
- }
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- }
- }
+ })
}
override fun observeRequestState() {
taskViewModel.loadState.observe(this) {
when (it) {
- LoadState.Loading -> {
- if (installDialog.isInstallMarker) {
- LoadingDialogHub.show(this, "标识器安装中,请稍后...")
- } else {
- LoadingDialogHub.show(this, "提交工单中,请稍后")
- }
- }
-
- LoadState.Success -> {
- if (installDialog.isInstallMarker) {
- installDialog.clearDefaultData()
- installDialog.dismiss()
- "${installDialog.markerId}安装成功".show(this)
- }
- LoadingDialogHub.dismiss()
- }
+ LoadState.Loading -> LoadingDialogHub.show(this, "提交工单中,请稍后")
else -> LoadingDialogHub.dismiss()
}
@@ -939,32 +871,6 @@
} else super.onKeyDown(keyCode, event)
}
- override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
- //精度发生变化时触发
- }
-
- override fun onSensorChanged(event: SensorEvent?) {
- //值发生变化时触发
- val type = event?.sensor?.type
-
- if (type == Sensor.TYPE_ACCELEROMETER) {
- gravity = event.values
- } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
- geomagnetic = event.values
- }
-
- if (gravity == null || geomagnetic == null) {
- return
- }
-
- if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
- SensorManager.getOrientation(rotationMatrix, valueArray)
-
- val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt()
- searchNewDialog.updateDegreeValue(degree)
- }
- }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
@@ -978,14 +884,6 @@
showLabelsOnMap()
}
- //注册加速度传感器监听
- val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
- sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)
-
- //注册磁场传感器监听
- val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
- sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL)
-
//取缓存
val remoteHost = SaveKeyValues.getValue(
LocaleConstant.RTK_SERVER, "203.107.45.154"
@@ -995,20 +893,20 @@
) as String
//连接千寻RTK服务器
- lifecycleScope.launch(Dispatchers.IO) {
- if (socketClient != null) {
- socketClient?.disconnect()
- delay(3000)
- }
-
- socketClient = SocketClient.Builder()
- .setHostname(remoteHost)
- .setPort(remotePort.toInt())
- .setTimeout(5000)
- .setOnSocketListener(this@MainActivity)
- .build()
- socketClient?.connect()
- }
+// lifecycleScope.launch(Dispatchers.IO) {
+// if (socketClient != null) {
+// socketClient?.disconnect()
+// delay(3000)
+// }
+//
+// socketClient = SocketClient.Builder()
+// .setHostname(remoteHost)
+// .setPort(remotePort.toInt())
+// .setTimeout(5000)
+// .setOnSocketListener(this@MainActivity)
+// .build()
+// socketClient?.connect()
+// }
}
override fun onMessageResponse(data: ByteArray) {
@@ -1021,12 +919,12 @@
val result = String(data, StandardCharsets.UTF_8)
Log.d(kTag, "onMessageResponse: $result")
if (result.contains("ICY 200 OK")) {
- "高精度定位服务器连接成功".show(this)
+ "高精度定位服务连接成功".show(this)
}
} else {
"收到千寻数据返回,长度:${data.size}".show(this)
- out.write(data)
- out.flush()
+// out.write(data)
+// out.flush()
}
}
@@ -1061,7 +959,6 @@
override fun onPause() {
super.onPause()
binding.mapView.onPause()
- sensorManager.unregisterListener(this)
}
override fun onSaveInstanceState(outState: Bundle) {
@@ -1072,794 +969,11 @@
override fun onDestroy() {
super.onDestroy()
binding.mapView.onDestroy()
- soundPool.release()
+ soundPool.autoPause()
+ searchMarkerTimer?.cancel()
+ serialPortService?.closeSerialPort()
locationTool.stopLocation()
- //降低串口电位
- gpioManager.setGpioLow("18")
+ unbindService(serviceConnection)
+ BaseApplication.get().closeSerialPort()
}
-
- /**安装标识器对话框******************************************************************************/
- inner class InstallMarkerDialog(private val context: Context) : Dialog(context) {
-
- private val binding: DialogInstallMarkerBinding by binding()
- private val calendar by lazy { Calendar.getInstance() }
- private val realPaths = ArrayList() //真实图片路径
- private lateinit var imageAdapter: EditableImageAdapter
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
-
- var isReadMarker = false
- var isInstallMarker = false
- var markerId = ""
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
-
- //初始化数据
- initDefaultData()
-
- //返回
- binding.titleInclude.leftBackView.setOnClickListener {
- soundPool.autoPause()
- dismiss()
- }
-
- binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
- object : AdapterView.OnItemSelectedListener {
- override fun onItemSelected(
- parent: AdapterView<*>?, view: View?, position: Int, id: Long
- ) {
- when (position) {
- 0 -> {
- //显示管线属性
- binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 1 -> {
- //显示管线附属物属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 2 -> {
- //显示管线特征点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 3 -> {
- //显示交叉穿越点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility =
- View.VISIBLE
- }
- }
- }
-
- override fun onNothingSelected(parent: AdapterView<*>?) {
-
- }
- }
-
- //安装
- binding.installButton.setOnClickListener {
- val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
- if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
- when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
- "管线" -> "请输入管线种类!".show(context)
- "管线附属物" -> "请输入附属物名称!".show(context)
- "管线特征管点" -> "请输入特征管点!".show(context)
- "交叉穿越点" -> "请输入上层管种类!".show(context)
- }
- return@setOnClickListener
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
- if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
- "请输入管径".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
- "请输入埋深".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
- if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
- "请输入下层管管径".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.areaView.text.isNullOrBlank()) {
- "请输入所属区域".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.lineView.text.isNullOrBlank()) {
- "请输入所属线路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.roadView.text.isNullOrBlank()) {
- "请输入所属道路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
- "请选择建设年代".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
- "请输入权属单位".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
- "请先读取标识器获取ID".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
- "请输入标识器埋深".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
- "请输入标识器安装部门".show(context)
- return@setOnClickListener
- }
-
- //先存本地再上传服务器
- saveMarkerInLocal()
-
- isInstallMarker = true
- taskViewModel.installLabel(
- context,
- companyId,
- binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
- "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
- binding.objectInclude.areaView.text.toString(),
- binding.objectInclude.lineView.text.toString(),
- binding.objectInclude.roadView.text.toString(),
- binding.objectInclude.constructDateView.text.toString(),
- binding.objectInclude.ownerView.text.toString(),
- objectId,
- binding.identifierInclude.identifierIdView.text.toString(),
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
- "${binding.identifierInclude.identifierDeepView.text}mm",
- binding.identifierInclude.personDeptView.text.toString(),
- binding.identifierInclude.installTimeView.text.toString(),
- binding.identifierInclude.lngView.text.toString(),
- binding.identifierInclude.latView.text.toString(),
- binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
- binding.remarkView.text.toString(),
- realPaths
- )
-
- //保存默认值
- "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
- "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
- "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
- "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
- "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
- "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
- "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
- "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
- "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
- "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
- "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
- }
-
- //读标识器
- binding.readMarkerButton.setOnClickListener {
- LoadingDialogHub.show(this@MainActivity, "标识器读取中,请稍后...")
- binding.readMarkerButton.isEnabled = false
-
- isReadMarker = true
-
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
-
- out.write('2'.code)
- out.flush()
-
- countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- "读取此标识器ID超时,请退出应用再试".show(context)
- }
- }
- countDownTimer.start()
- }
- }
-
- override fun show() {
- super.show()
- locationTool = LocationTool(context)
- locationTool.getCurrentLocation(true, object : OnGetLocationListener {
- override fun onAMapLocationGet(location: AMapLocation?) {
- if (location != null) {
- binding.identifierInclude.lngView.text = location.longitude.toString()
- binding.identifierInclude.latView.text = location.latitude.toString()
- } else {
- "当前位置信号差,无法获取定位".show(context)
- }
- }
- })
- }
-
- fun bindingValue(markerId: String) {
- this.markerId = markerId
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- countDownTimer.cancel()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- binding.identifierInclude.identifierIdView.text = markerId
- }
-
- override fun dismiss() {
- //降低串口电位
- gpioManager.setGpioLow("18")
- soundPool.autoPause()
- isInstallMarker = false
- locationTool.stopLocation()
- super.dismiss()
- }
-
- private fun initDefaultData() {
- binding.titleInclude.titleView.text = "安装新标识器"
- binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
-
- imageAdapter = EditableImageAdapter(context, 3, 3)
- binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
-
- //设置默认值
- binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
- binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
- binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
- binding.objectInclude.areaView.setText("areaView".getDefaultValue())
- binding.objectInclude.lineView.setText("lineView".getDefaultValue())
- binding.objectInclude.roadView.setText("roadView".getDefaultValue())
- binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
- binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
- binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
-
- /**************************************************************************************/
- binding.objectInclude.objectTypeSpinner.show(
- this@MainActivity, LocaleConstant.POINT_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.materialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeAttachInclude.attachSpinner.show(
- this@MainActivity, LocaleConstant.ATTACH_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
- this@MainActivity, LocaleConstant.FEATURE_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.buryTypeSpinner.show(
- this@MainActivity, LocaleConstant.BURY_METHOD_ARRAY, 0
- )
-
- binding.objectInclude.constructDateView.setOnClickListener {
- val datePicker = DatePickerDialog(
- context,
- null,
- calendar.get(Calendar.YEAR),
- calendar.get(Calendar.MONTH),
- calendar.get(Calendar.DAY_OF_MONTH)
- )
- datePicker.show()
-
- datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
- val year = datePicker.datePicker.year
- val month = datePicker.datePicker.month + 1
- val day = datePicker.datePicker.dayOfMonth
- val selectedDate = String.format(
- "%s-%s-%s", year, month.appendZero(), day.appendZero()
- )
-
- //当前时间
- val current = System.currentTimeMillis().timestampToTime()
- val today = "$selectedDate $current".dateToTimestamp()
- if (Date(today).after(Date())) {
- "建设年代不能早于当前日期".show(context)
- } else {
- datePicker.dismiss()
- binding.objectInclude.constructDateView.text = selectedDate
- }
- }
- }
-
- binding.identifierInclude.identifierTypeSpinner.show(
- this@MainActivity, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
- )
-
- binding.identifierInclude.installTimeView.text =
- System.currentTimeMillis().timestampToCompleteDate()
-
- binding.identifierInclude.colorSpinner.show(
- this@MainActivity, LocaleConstant.COLOR_ARRAY, 0
- )
-
- imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
- override fun onAddImageClick() {
- takePicture()
- }
-
- override fun onItemClick(position: Int) {
- if (realPaths[position].isEmpty()) {
- "图片加载失败,无法查看大图".show(context)
- } else {
- context.navigatePageTo(position, realPaths)
- }
- }
-
- override fun onItemLongClick(view: View?, position: Int) {
- imageAdapter.deleteImage(position)
- }
- })
- /**************************************************************************************/
- }
-
- //清除默认数据
- fun clearDefaultData() {
- "markerObjectTypeView".setDefaultValue("")
- "pipelineDiameterView".setDefaultValue("")
- "buryDeepView".setDefaultValue("")
- "bottomPipeDiameterView".setDefaultValue("")
- "bottomPointDeepView".setDefaultValue("")
- "areaView".setDefaultValue("")
- "lineView".setDefaultValue("")
- "roadView".setDefaultValue("")
- "ownerView".setDefaultValue("")
- "identifierDeepView".setDefaultValue("")
- "personDeptView".setDefaultValue("")
- }
-
- private fun saveMarkerInLocal() {
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
-
- val marker = MarkerLocalBean()
- marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
- marker.pipelineType =
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
- marker.pipelineMaterial =
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
- marker.pipelineDiameter =
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
- marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
- marker.underlyingPipelineType =
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
- marker.underlyingPipelineMaterial =
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
- marker.underlyingPipelineDiameter =
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
- marker.underlyingPipelineDepth =
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
- marker.buryMethod =
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
- marker.area = binding.objectInclude.areaView.text.toString()
- marker.line = binding.objectInclude.lineView.text.toString()
- marker.road = binding.objectInclude.roadView.text.toString()
- marker.constructTime = binding.objectInclude.constructDateView.text.toString()
- marker.owner = binding.objectInclude.ownerView.text.toString()
- marker.objectId = objectId
- marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
- marker.markerType =
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
- marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
- marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
- marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
- marker.lng = binding.identifierInclude.lngView.text.toString()
- marker.lat = binding.identifierInclude.latView.text.toString()
- marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
- marker.remark = binding.remarkView.text.toString()
- marker.imagePath = realPaths.toJson()
-
- DataBaseManager.get.saveMarkerInLocale(marker)
- }
-
- private fun takePicture() {
- PictureSelector.create(this@MainActivity).openCamera(SelectMimeType.ofImage())
- .forResult(object : OnResultCallbackListener {
- override fun onResult(result: java.util.ArrayList?) {
- if (result == null) {
- "拍照失败,请重试".show(context)
- return
- }
- analyticalSelectResults(result[0])
- }
-
- override fun onCancel() {
-
- }
- })
- }
-
- private fun analyticalSelectResults(result: LocalMedia) {
- //压缩图片
- result.realPath.compressImage(context, object : OnImageCompressListener {
- override fun onSuccess(file: File) {
- realPaths.add(file.absolutePath)
- imageAdapter.setupImage(realPaths)
- }
-
- override fun onError(e: Throwable) {
- e.printStackTrace()
- }
- })
- }
- }
-
- /**探测标识器新对话框****************************************************************************/
- inner class SearchMarkerNewDialog(private val context: Context) : Dialog(context) {
-
- private val taskId by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
- }
- private val taskCode by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_CODE, "") as String
- }
- private val markerPoints by lazy { ArrayList() }
- private val binding: DialogSearchMarkerNewBinding by binding()
- private var markerId = ""//实际探测出来的标识器ID
- private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID
- private lateinit var searchMarkerTimer: Timer
- private lateinit var signalTask: TimerTask
- private lateinit var energyTask: TimerTask
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
- var isDetectMarker = false
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
- binding.depthButton.setOnClickListener {
- signalTask.cancel()
- energyTask.cancel()
- searchMarkerTimer.cancel()
-
- out.write('3'.code)
- val result = DataBaseManager.get.queryMarkerById(markerId)
- if (result.isNotEmpty()) {
- val tag = when (result.first().markerType) {
- "EM30" -> '7'
- "EM50" -> '8'
- "EM14" -> '9'
- else -> '1'
- }
- if (tag == '1') {
- "此标识器无法读取埋深!".show(context)
- initTimer()
- } else {
- // 发送读取标识器埋设深度指令
- LoadingDialogHub.show(this@MainActivity, "正在测距,请稍后...")
- out.write(tag.code)
- out.flush()
- countDownTimer = object : CountDownTimer(15 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- "探测此标识器深度超时,请重试".show(context)
- initTimer()
- }
- }
- countDownTimer.start()
- }
- } else {
- "标识器未安装,安装成功后才可读取埋深!".show(context)
- initTimer()
- }
- }
-
- binding.markerInfoButton.setOnClickListener {
- val id = if (markerId == "") {
- nearestMarkerId
- } else {
- markerId
- }
- //查库
- val result = DataBaseManager.get.queryMarkerById(id)
- if (result.isNotEmpty()) {
- context.navigatePageTo(result.first().toJson())
- } else {
- context.navigatePageTo(id)
- }
- //查看完就把ID置空,便于下次查看最新的ID
- markerId = ""
- }
- }
-
- override fun show() {
- super.show()
- locationTool = LocationTool(context)
- //点位渲染,每次定位都计算当前位置与符合条件的点距离
- locationTool.getCurrentLocation(false, object : OnGetLocationListener {
- override fun onAMapLocationGet(location: AMapLocation?) {
- location?.apply {
- renderDataPoint(this)
- }
- }
- })
- }
-
- /**
- * 计算并渲染数据点。点太多采用协程计算,不然会有点卡顿
- * @param location 定位点(RTK获取)
- * */
- private fun renderDataPoint(location: AMapLocation) {
- val longitude = location.longitude
- val latitude = location.latitude
- lifecycleScope.launch(Dispatchers.IO) {
- val dataPoints = ArrayList()
- DataBaseManager.get.loadMarkers().forEach {
- val distance = AMapUtils.calculateLineDistance(
- LatLng(it.lat.toDouble(), it.lng.toDouble()), LatLng(latitude, longitude)
- )
- val formatDistance = "%.2f".format(distance).toFloat()
-
- markerPoints.add(MarkerDistanceData(it.markerId, formatDistance))
-
- if (formatDistance <= LocaleConstant.MAX_DISTANCE) {
- val angle = atan2(
- (it.lat.toDouble() - latitude), (it.lng.toDouble() - longitude)
- ) + Math.PI
- val formatAngle = "%.2f".format(angle).toDouble()
- dataPoints.add(
- RadarScanView.DataPoint(formatAngle, formatDistance)
- )
- }
- }
- withContext(Dispatchers.Main) {
- binding.radarScanView.renderPointData(dataPoints,
- object : RadarScanView.OnGetNearestPointCallback {
- override fun getNearestPoint(point: RadarScanView.DataPoint?) {
- if (point == null) {
- binding.distanceValueView.text = "大于5.5m"
- binding.distancePgBar.progress = 100
- } else {
- binding.distanceValueView.text = "${point.distance}m"
- val progress =
- if (point.distance > LocaleConstant.MAX_DISTANCE) {
- 100
- } else {
- (point.distance / LocaleConstant.MAX_DISTANCE) * 100
- }
- binding.distancePgBar.progress = progress.toInt()
- }
- }
- })
- }
- }
- }
-
- override fun onStart() {
- super.onStart()
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- initTimer()
-
- isDetectMarker = true
-
- if (isExecuteTask) {
- binding.taskStateView.visibility = View.GONE
- binding.taskStateView.isSelected = false
- } else {
- binding.taskStateView.visibility = View.VISIBLE
- binding.taskStateView.isSelected = true
- }
- }
-
- fun bindingValue(hex: String) {
- if (hex.startsWith("4E")) {
- try {
- //4E转为String为N,代表能量值
- //用能量值转动表盘
- val energyResponse = hex.take(10).hexToString()
- val energy = energyResponse.substring(1).toInt()
- if (energy >= 4000) {
- soundPool.play(fastSoundResourceId, 1f, 1f, 0, 0, 1f)
- } else {
- soundPool.play(slowSoundResourceId, 1f, 1f, 0, 0, 1f)
- }
-
- //通过设置进度条表示能量值
- binding.energyPgBar.progress = energy
- binding.energyValueView.text = "${energy}dB"
-
- if (energy <= 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.searchResultView.text = "未检测到标识器"
- binding.searchResultView.setTextColor(Color.parseColor("#8D1717"))
- binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_red)
- } else if (energy >= 4100) {
- binding.energyTipsView.text = "信号极强,接近标识器正上方"
- binding.energyTipsView.setTextColor(Color.parseColor("#428d00"))
- binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green)
-
- if (markerPoints.isEmpty()) {
- Log.d(kTag, "bindingValue: markerPoints.isEmpty()")
- return
- }
-
- //需要转一下,不然会有并发问题
- val temp = ArrayList()
- temp.addAll(markerPoints)
- temp.sortBy(MarkerDistanceData::distance)
- val nearestPoint = temp.first()
- nearestMarkerId = nearestPoint.markerId
- handleMarker(nearestMarkerId)
- } else {
- binding.energyTipsView.text = "已靠近,请继续移动位置"
- binding.energyTipsView.setTextColor(Color.parseColor("#8C5700"))
- binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow)
- }
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- } else if (hex.startsWith("53")) {
- LoadingDialogHub.dismiss()
- countDownTimer.cancel()
- try {
- val depthResponse = hex.take(10).hexToString()
- val depth = depthResponse.drop(2).toInt()
- AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示")
- .setMessage("标识器埋深:${depth}厘米").setPositiveButton("知道了")
- .setOnDialogButtonClickListener(object :
- AlertMessageDialog.OnDialogButtonClickListener {
- override fun onConfirmClick() {
- initTimer()
- }
- }).build().show()
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- } else {
- val id = hex.take(20).hexToString()
- if (id.isNumber()) {
- markerId = id
- handleMarker(markerId)
- }
- }
- }
-
- private fun handleMarker(id: String) {
- binding.depthButton.isEnabled = true
- binding.depthButton.setTextColor(Color.WHITE)
- binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
- binding.markerInfoButton.isEnabled = true
- binding.markerInfoButton.setTextColor(Color.WHITE)
- binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)
-
- binding.searchResultView.text = "已检测到标识器"
- binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
- binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)
-
- //自动上传标识器
- if (isExecuteTask) {
- val taskMarkerLocalBean = DataBaseManager.get.queryTaskMarkerById(
- taskId, taskCode, id, "0"
- )
- taskMarkerLocalBean?.apply {
- taskViewModel.uploadMarker(context, this)
- }
- }
- }
-
- //更新罗盘角度
- fun updateDegreeValue(degree: Int) {
- binding.radarScanView.setDegreeValue(degree)
- }
-
- private fun initTimer() {
- searchMarkerTimer = Timer()
-
- signalTask = object : TimerTask() {
- override fun run() {
- out.write('2'.code)
- out.flush()
- }
- }
-
- energyTask = object : TimerTask() {
- override fun run() {
- out.write('6'.code)
- out.flush()
- }
- }
-
- //错开信号和能量定时器
- searchMarkerTimer.schedule(signalTask, 0, 201)
- searchMarkerTimer.schedule(energyTask, 0, 251)
- }
-
- override fun dismiss() {
- signalTask.cancel()
- energyTask.cancel()
- searchMarkerTimer.cancel()
- //降低串口电位
- gpioManager.setGpioLow("18")
- isDetectMarker = false
- soundPool.autoPause()
- locationTool.stopLocation()
- super.dismiss()
- }
- }
-
- /**
- * 标识器与当前定位的数据
- * */
- data class MarkerDistanceData(var markerId: String, var distance: Float)
}
\ 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
new file mode 100644
index 0000000..14fe667
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/view/SearchMarkerActivity.kt
@@ -0,0 +1,462 @@
+package com.casic.detector.common.view
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.graphics.Color
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import android.media.AudioAttributes
+import android.media.SoundPool
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.IBinder
+import android.util.Log
+import android.view.View
+import android.view.WindowManager
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMapUtils
+import com.amap.api.maps.model.LatLng
+import com.casic.detector.common.R
+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.hexToString
+import com.casic.detector.common.extensions.isNumber
+import com.casic.detector.common.extensions.toHex
+import com.casic.detector.common.model.MarkerDistanceData
+import com.casic.detector.common.service.SerialPortService
+import com.casic.detector.common.utils.DataBaseManager
+import com.casic.detector.common.utils.LocaleConstant
+import com.casic.detector.common.utils.LocationTool
+import com.casic.detector.common.vm.TaskViewModel
+import com.casic.detector.common.widgets.RadarScanView
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.Constant
+import com.pengxh.kt.lite.utils.LoadingDialogHub
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.OutputStream
+import java.util.Timer
+import java.util.TimerTask
+import kotlin.math.atan2
+
+class SearchMarkerActivity : KotlinBaseActivity(),
+ SensorEventListener {
+
+ private val kTag = "SearchMarkerActivity"
+ private val context = this
+ private val locationTool by lazy { LocationTool(this) }
+ private val markerPoints by lazy { ArrayList() }
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val sensorManager by lazy { getSystemService()!! }
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private val rotationMatrix = FloatArray(9)//旋转矩阵缓存
+ private val valueArray = FloatArray(3)//方位角数值
+ private var slowSoundResourceId = 0
+ private var fastSoundResourceId = 0
+ private var markerId = ""//实际探测出来的标识器ID
+ private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID
+ private var isExecuteTask = false
+ private var signalEnergy = 0 //标识器信号强度
+ 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 {
+ override fun onServiceConnected(name: ComponentName?, iBinder: IBinder?) {
+ if (iBinder is SerialPortService.ServiceBinder) {
+ serialPortService = iBinder.getSerialPortService()
+ Log.d(kTag, "onServiceConnected: 服务已绑定")
+ searchMarker()
+ }
+ }
+
+ override fun onServiceDisconnected(name: ComponentName?) {
+
+ }
+ }
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ val flag = intent.getStringExtra(Constant.INTENT_PARAM) as String
+ isExecuteTask = flag != "0"
+
+ //绑定串口通信服务
+ Intent(this, SerialPortService::class.java).also {
+ bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
+ }
+
+ slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
+ fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)
+
+ //点位渲染,每次定位都计算当前位置与符合条件的点距离
+ locationTool.getCurrentLocation(false, object : OnGetLocationListener {
+ override fun onAMapLocationGet(location: AMapLocation?) {
+ location?.apply {
+ renderDataPoint(this)
+ }
+ }
+ })
+
+ if (isExecuteTask) {
+ binding.taskStateView.visibility = View.GONE
+ binding.taskStateView.isSelected = false
+ } else {
+ binding.taskStateView.visibility = View.VISIBLE
+ binding.taskStateView.isSelected = true
+ }
+
+ //在标识器信号强度很强的时候,从数据库中计算出距离最近的点,以防出现探测不到ID的情况
+ searchSignalEnergyTimer = Timer()
+ searchSignalEnergyTimer.schedule(object : TimerTask() {
+ override fun run() {
+ //markerId为空,说明没有通过探测得到标识器ID,那么就需要通过计算得到近似的标识器
+ if (signalEnergy >= 4100 && markerPoints.isNotEmpty()) {
+ try {
+ //需要转一下,不然会有并发问题
+ val temp = ArrayList()
+ temp.addAll(markerPoints)
+ temp.sortBy(MarkerDistanceData::distance)
+ val nearestPoint = temp.first()
+ nearestMarkerId = nearestPoint.markerId
+ runOnUiThread {
+ handleMarker(nearestMarkerId)
+ }
+ markerPoints.clear()
+ } catch (e: NullPointerException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }, 0, 2000)
+ }
+
+ private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
+ override fun onTick(millisUntilFinished: Long) {
+
+ }
+
+ override fun onFinish() {
+ LoadingDialogHub.dismiss()
+ serialPortService?.closeSerialPort()
+ "标识器深度探测超时,请移动位置重试".show(context)
+ searchMarker()
+ }
+ }
+
+ override fun initEvent() {
+ binding.depthButton.setOnClickListener {
+ stopSearchMarker()
+ val result = DataBaseManager.get.queryMarkerById(markerId)
+ if (result.isNotEmpty()) {
+ val tag = when (result.first().markerType) {
+ "EM30" -> '7'
+ "EM50" -> '8'
+ "EM14" -> '9'
+ else -> '1'
+ }
+ if (tag == '1') {
+ "此标识器无法读取埋深!".show(this)
+ searchMarker()
+ } else {
+ LoadingDialogHub.show(this, "正在探测标识器埋深,请稍后...")
+ countDownTimer.start()
+ // 发送读取标识器埋设深度指令
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ // 发送读取标识器埋设深度指令
+ outStream.write(tag.code)
+ outStream.flush()
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ if (hex.startsWith("53")) {
+ LoadingDialogHub.dismiss()
+ countDownTimer.cancel()
+ try {
+ val depthResponse = hex.take(10).hexToString()
+ val depth = depthResponse.drop(2).toInt()
+ AlertMessageDialog.Builder().setContext(context)
+ .setTitle("温馨提示")
+ .setMessage("标识器埋深:${depth}厘米")
+ .setPositiveButton("知道了")
+ .setOnDialogButtonClickListener(object :
+ AlertMessageDialog.OnDialogButtonClickListener {
+ override fun onConfirmClick() {
+ serialPortService?.closeSerialPort()
+ searchMarker()
+ }
+ }).build().show()
+ } catch (e: WindowManager.BadTokenException) {
+ e.printStackTrace()
+ } catch (e: NumberFormatException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ })
+ }
+ } else {
+ LoadingDialogHub.dismiss()
+ "标识器未安装,安装成功后才可读取埋深!".show(this)
+ searchMarker()
+ }
+ }
+
+ binding.markerInfoButton.setOnClickListener {
+ val id = if (markerId == "") {
+ nearestMarkerId
+ } else {
+ markerId
+ }
+ //查库
+ val result = DataBaseManager.get.queryMarkerById(id)
+ if (result.isNotEmpty()) {
+ navigatePageTo(result.first().toJson())
+ } else {
+ navigatePageTo(id)
+ }
+ //查看完就把ID置空,便于下次查看最新的ID
+ markerId = ""
+ }
+ }
+
+ /**
+ * 搜索标识器
+ * */
+ private fun searchMarker() {
+ Thread.sleep(100)
+
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ searchMarkerTimer = Timer()
+ searchMarkerTimer.schedule(object : TimerTask() {
+ override fun run() {
+ outStream.write('2'.code)
+ outStream.flush()
+
+ Thread.sleep(50)
+
+ outStream.write('6'.code)
+ outStream.flush()
+ }
+ }, 0, 200)
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ 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)
+ }
+
+ //通过设置进度条表示能量值
+ 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)
+
+ 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()
+ }
+ } else {
+ val id = hex.take(20).hexToString()
+ if (id.isNumber()) {
+ markerId = id
+ handleMarker(markerId)
+ }
+ }
+ }
+ })
+ }
+
+ private fun stopSearchMarker() {
+ soundPool.autoPause()
+ searchMarkerTimer.cancel()
+ serialPortService?.closeSerialPort()
+
+ Thread.sleep(100)
+ }
+
+ /**
+ * 计算并渲染数据点。点太多采用协程计算,不然会有点卡顿。默认2s计算一次
+ * @param location 定位点(RTK获取)
+ * */
+ private fun renderDataPoint(location: AMapLocation) {
+ val longitude = location.longitude
+ val latitude = location.latitude
+ lifecycleScope.launch(Dispatchers.IO) {
+ val dataPoints = ArrayList()
+ DataBaseManager.get.loadMarkers().forEach {
+ val distance = AMapUtils.calculateLineDistance(
+ LatLng(it.lat.toDouble(), it.lng.toDouble()), LatLng(latitude, longitude)
+ )
+ val formatDistance = "%.2f".format(distance).toFloat()
+ markerPoints.add(MarkerDistanceData(it.markerId, formatDistance))
+
+ if (formatDistance <= LocaleConstant.MAX_DISTANCE) {
+ val angle = atan2(
+ (it.lat.toDouble() - latitude), (it.lng.toDouble() - longitude)
+ ) + Math.PI
+ val formatAngle = "%.2f".format(angle).toDouble()
+
+ dataPoints.add(RadarScanView.DataPoint(formatAngle, formatDistance))
+ }
+ }
+ withContext(Dispatchers.Main) {
+ binding.radarScanView.renderPointData(dataPoints,
+ object : RadarScanView.OnGetNearestPointCallback {
+ override fun getNearestPoint(point: RadarScanView.DataPoint?) {
+ if (point == null) {
+ binding.distanceValueView.text = "大于5.5m"
+ binding.distancePgBar.progress = 100
+ } else {
+ binding.distanceValueView.text = "${point.distance}m"
+ val progress = if (point.distance > LocaleConstant.MAX_DISTANCE) {
+ 100
+ } else {
+ (point.distance / LocaleConstant.MAX_DISTANCE) * 100
+ }
+ binding.distancePgBar.progress = progress.toInt()
+ }
+ }
+ }
+ )
+ }
+ }
+ }
+
+ override fun initViewBinding(): ActivitySearchMarkerBinding {
+ return ActivitySearchMarkerBinding.inflate(layoutInflater)
+ }
+
+ override fun observeRequestState() {
+
+ }
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ private fun handleMarker(id: String) {
+ binding.depthButton.isEnabled = true
+ binding.depthButton.setTextColor(Color.WHITE)
+ binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
+ binding.markerInfoButton.isEnabled = true
+ binding.markerInfoButton.setTextColor(Color.WHITE)
+ binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)
+
+ binding.searchResultView.text = "已检测到标识器"
+ binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
+ binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)
+
+ //自动上传标识器
+ if (isExecuteTask) {
+ val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
+ val taskCode = SaveKeyValues.getValue(LocaleConstant.TASK_CODE, "") as String
+ val taskMarkerLocalBean = DataBaseManager.get.queryTaskMarkerById(
+ taskId, taskCode, id, "0"
+ )
+ taskMarkerLocalBean?.apply {
+ taskViewModel.uploadMarker(context, this)
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ //注册加速度传感器监听
+ val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
+ sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)
+
+ //注册磁场传感器监听
+ val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
+ sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL)
+ }
+
+ override fun onPause() {
+ super.onPause()
+ sensorManager.unregisterListener(this)
+ }
+
+ override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
+ //精度发生变化时触发
+ }
+
+ override fun onSensorChanged(event: SensorEvent?) {
+ //值发生变化时触发
+ val type = event?.sensor?.type
+
+ if (type == Sensor.TYPE_ACCELEROMETER) {
+ gravity = event.values
+ } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
+ geomagnetic = event.values
+ }
+
+ if (gravity == null || geomagnetic == null) {
+ return
+ }
+
+ if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
+ SensorManager.getOrientation(rotationMatrix, valueArray)
+
+ val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt()
+ //更新罗盘角度
+ binding.radarScanView.setDegreeValue(degree)
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ stopSearchMarker()
+ locationTool.stopLocation()
+ unbindService(serviceConnection)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_install_marker.xml b/app/src/main/res/layout/activity_install_marker.xml
new file mode 100644
index 0000000..65c2262
--- /dev/null
+++ b/app/src/main/res/layout/activity_install_marker.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_search_marker.xml b/app/src/main/res/layout/activity_search_marker.xml
new file mode 100644
index 0000000..b989df8
--- /dev/null
+++ b/app/src/main/res/layout/activity_search_marker.xml
@@ -0,0 +1,178 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_install_marker.xml b/app/src/main/res/layout/dialog_install_marker.xml
deleted file mode 100644
index 65c2262..0000000
--- a/app/src/main/res/layout/dialog_install_marker.xml
+++ /dev/null
@@ -1,122 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/dialog_search_marker.xml b/app/src/main/res/layout/dialog_search_marker.xml
deleted file mode 100644
index 3e42003..0000000
--- a/app/src/main/res/layout/dialog_search_marker.xml
+++ /dev/null
@@ -1,148 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89fd3c9..81f1347 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
index 458f3fb..ca7de13 100644
--- a/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
+++ b/app/src/main/java/com/casic/detector/common/base/BaseApplication.kt
@@ -4,6 +4,7 @@
import com.casic.detector.common.greendao.DaoMaster
import com.casic.detector.common.greendao.DaoSession
import com.casic.detector.common.uart.SerialPort
+import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.SaveKeyValues
import java.io.File
import java.io.IOException
@@ -13,23 +14,12 @@
class BaseApplication : Application() {
private val kTag = "BaseApplication"
- private var serialPorts: ArrayList? = null
+ private var serialPorts = ArrayList()
- @Throws(SecurityException::class, IOException::class, InvalidParameterException::class)
- fun getSerialPorts(): ArrayList? {
- serialPorts = ArrayList()
- /**
- * Open the serial port
- * */
- serialPorts?.apply {
- add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
- add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
- }
- return serialPorts
- }
+ fun getSerialPorts(): ArrayList = serialPorts
fun closeSerialPort() {
- serialPorts?.forEach {
+ serialPorts.forEach {
it.closeSerialPort()
}
}
@@ -49,6 +39,22 @@
val devOpenHelper = DaoMaster.DevOpenHelper(this, "Detector_Common.db", null)
val daoMaster = DaoMaster(devOpenHelper.writableDatabase)
daoSession = daoMaster.newSession()
+
+ /**
+ * Open the serial port
+ * */
+ try {
+ serialPorts.apply {
+ add(SerialPort(File("/dev/ttysWK1"), 9600, 0))
+ add(SerialPort(File("/dev/ttysWK2"), 9600, 0))
+ }
+ } catch (e: SecurityException) {
+ "您没有串口的读写权限!".show(this)
+ } catch (e: IOException) {
+ "因为不明原因,串口无法打开!".show(this)
+ } catch (e: InvalidParameterException) {
+ "请检查串口!".show(this)
+ }
}
fun getDaoSession(): DaoSession {
diff --git a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt b/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
deleted file mode 100644
index 297ac02..0000000
--- a/app/src/main/java/com/casic/detector/common/base/SerialPortActivity.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.casic.detector.common.base
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.lifecycleScope
-import androidx.viewbinding.ViewBinding
-import com.pengxh.kt.lite.extensions.show
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.io.IOException
-import java.io.OutputStream
-import java.security.InvalidParameterException
-
-
-abstract class SerialPortActivity : AppCompatActivity() {
-
- protected lateinit var binding: VB
-
- lateinit var out: OutputStream
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = initViewBinding()
- setContentView(binding.root)
- setupTopBarLayout()
- initOnCreate(savedInstanceState)
- observeRequestState()
- initEvent()
-
- try {
- val serialPorts = BaseApplication.get().getSerialPorts()
- //读
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[0].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- lifecycleScope.launch(Dispatchers.IO) {
- serialPorts?.apply {
- val stream = this[1].inputStream
- while (isActive) {
- try {
- val buffer = ByteArray(64)
- val size = stream.read(buffer)
- if (size > 0) {
- withContext(Dispatchers.Main) {
- onDataReceived(buffer)
- }
- }
- } catch (e: IOException) {
- e.printStackTrace()
- }
- }
- }
- }
-
- //写
- serialPorts?.apply {
- out = this[0].outputStream
- }
- } catch (e: SecurityException) {
- "您没有串口的读写权限!".show(this)
- } catch (e: IOException) {
- "因为不明原因,串口无法打开!".show(this)
- } catch (e: InvalidParameterException) {
- "请检查串口!".show(this)
- }
- }
-
- /**
- * 初始化ViewBinding
- */
- abstract fun initViewBinding(): VB
-
- /**
- * 特定页面定制沉浸式状态栏
- */
- abstract fun setupTopBarLayout()
-
- /**
- * 初始化默认数据
- */
- abstract fun initOnCreate(savedInstanceState: Bundle?)
-
- /**
- * 数据请求状态监听
- */
- abstract fun observeRequestState()
-
- /**
- * 初始化业务逻辑
- */
- abstract fun initEvent()
-
- /**
- * 串口读数,已经切回主线程
- * */
- abstract fun onDataReceived(buffer: ByteArray)
-
- override fun onDestroy() {
- super.onDestroy()
- BaseApplication.get().closeSerialPort()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
new file mode 100644
index 0000000..b06a068
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/callback/OnSerialPortDataListener.kt
@@ -0,0 +1,9 @@
+package com.casic.detector.common.callback
+
+import java.io.OutputStream
+
+interface OnSerialPortDataListener {
+ fun write(outStream: OutputStream)
+
+ fun onDataReceived(buffer: ByteArray)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
new file mode 100644
index 0000000..b1685d5
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/model/MarkerDistanceData.kt
@@ -0,0 +1,6 @@
+package com.casic.detector.common.model
+
+/**
+ * 标识器与当前定位的数据
+ * */
+data class MarkerDistanceData(var markerId: String, var distance: Float)
diff --git a/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
new file mode 100644
index 0000000..090f604
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/service/SerialPortService.kt
@@ -0,0 +1,104 @@
+package com.casic.detector.common.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+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.base.BaseApplication
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.utils.GpioManager
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.IOException
+
+class SerialPortService : Service(), LifecycleOwner {
+
+ private val kTag = "SerialPortService"
+ private val registry = LifecycleRegistry(this)
+ private val gpioManager by lazy { GpioManager() }
+ private val serialPorts by lazy { BaseApplication.get().getSerialPorts() }
+ private var gpioState = ""
+
+ override fun getLifecycle(): Lifecycle {
+ return registry
+ }
+
+ override fun onBind(intent: Intent?): IBinder {
+ return ServiceBinder()
+ }
+
+ inner class ServiceBinder : Binder() {
+ fun getSerialPortService(): SerialPortService {
+ return this@SerialPortService
+ }
+ }
+
+ fun openSerialPort(listener: OnSerialPortDataListener) {
+ //调高串口电位
+ gpioManager.setGpioHigh("18")
+ gpioState = "1"
+ Log.d(kTag, "openSerialPort: 调高串口电位")
+
+ Thread.sleep(100)
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ //写
+ listener.write(this[0].outputStream)
+ val stream = this[0].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ serialPorts.apply {
+ val stream = this[1].inputStream
+ //读
+ while (isActive) {
+ try {
+ val buffer = ByteArray(64)
+ val size = stream.read(buffer)
+ if (size > 0) {
+ withContext(Dispatchers.Main) {
+ if (gpioState == "1") {
+ listener.onDataReceived(buffer)
+ }
+ }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+ }
+
+ fun closeSerialPort() {
+ //降低串口电位
+ gpioManager.setGpioLow("18")
+ gpioState = "0"
+ Log.d(kTag, "closeSerialPort: 降低串口电位")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
new file mode 100644
index 0000000..b50aaaf
--- /dev/null
+++ b/app/src/main/java/com/casic/detector/common/view/InstallMarkerActivity.kt
@@ -0,0 +1,548 @@
+package com.casic.detector.common.view
+
+import android.app.DatePickerDialog
+import android.content.ComponentName
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
+import android.media.AudioAttributes
+import android.media.SoundPool
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.IBinder
+import android.util.Log
+import android.view.View
+import android.widget.AdapterView
+import androidx.lifecycle.ViewModelProvider
+import com.amap.api.location.AMapLocation
+import com.casic.detector.common.R
+import com.casic.detector.common.adapter.EditableImageAdapter
+import com.casic.detector.common.bean.MarkerLocalBean
+import com.casic.detector.common.callback.OnGetLocationListener
+import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
+import com.casic.detector.common.databinding.ActivityInstallMarkerBinding
+import com.casic.detector.common.extensions.compressImage
+import com.casic.detector.common.extensions.getDefaultValue
+import com.casic.detector.common.extensions.hexToString
+import com.casic.detector.common.extensions.isNumber
+import com.casic.detector.common.extensions.setDefaultValue
+import com.casic.detector.common.extensions.show
+import com.casic.detector.common.extensions.toColor
+import com.casic.detector.common.extensions.toHex
+import com.casic.detector.common.extensions.toObjectType
+import com.casic.detector.common.service.SerialPortService
+import com.casic.detector.common.utils.DataBaseManager
+import com.casic.detector.common.utils.LocaleConstant
+import com.casic.detector.common.utils.LocationTool
+import com.casic.detector.common.vm.TaskViewModel
+import com.luck.picture.lib.basic.PictureSelector
+import com.luck.picture.lib.config.SelectMimeType
+import com.luck.picture.lib.entity.LocalMedia
+import com.luck.picture.lib.interfaces.OnResultCallbackListener
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.appendZero
+import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.extensions.dateToTimestamp
+import com.pengxh.kt.lite.extensions.navigatePageTo
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.extensions.timestampToCompleteDate
+import com.pengxh.kt.lite.extensions.timestampToTime
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.LoadState
+import com.pengxh.kt.lite.utils.LoadingDialogHub
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import java.io.File
+import java.io.OutputStream
+import java.util.Calendar
+import java.util.Date
+
+class InstallMarkerActivity : KotlinBaseActivity() {
+
+ private val kTag = "InstallMarkerActivity"
+ private val context = this
+ private val calendar by lazy { Calendar.getInstance() }
+ private val locationTool by lazy { LocationTool(this) }
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val realPaths = ArrayList() //真实图片路径
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var soundResourceId = 0
+ private var serialPortService: SerialPortService? = null
+ private lateinit var imageAdapter: EditableImageAdapter
+
+ override fun initEvent() {
+ //返回
+ binding.titleInclude.leftBackView.setOnClickListener {
+ soundPool.autoPause()
+ finish()
+ }
+
+ binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
+ object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(
+ parent: AdapterView<*>?, view: View?, position: Int, id: Long
+ ) {
+ when (position) {
+ 0 -> {
+ //显示管线属性
+ binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 1 -> {
+ //显示管线附属物属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 2 -> {
+ //显示管线特征点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.VISIBLE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
+ }
+
+ 3 -> {
+ //显示交叉穿越点属性
+ binding.objectInclude.pipeInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
+ binding.objectInclude.pipeCrossInclude.root.visibility = View.VISIBLE
+ }
+ }
+ }
+
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+
+ }
+ }
+
+ //安装
+ binding.installButton.setOnClickListener {
+ val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+ if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
+ when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
+ "管线" -> "请输入管线种类!".show(this)
+ "管线附属物" -> "请输入附属物名称!".show(this)
+ "管线特征管点" -> "请输入特征管点!".show(this)
+ "交叉穿越点" -> "请输入上层管种类!".show(this)
+ }
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
+ if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
+ "请输入管径".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
+ "请输入埋深".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
+ if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
+ "请输入下层管管径".show(this)
+ return@setOnClickListener
+ }
+ }
+
+ if (binding.objectInclude.areaView.text.isNullOrBlank()) {
+ "请输入所属区域".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.lineView.text.isNullOrBlank()) {
+ "请输入所属线路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.roadView.text.isNullOrBlank()) {
+ "请输入所属道路".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
+ "请选择建设年代".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
+ "请输入权属单位".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
+ "请先读取标识器获取ID".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
+ "请输入标识器埋深".show(this)
+ return@setOnClickListener
+ }
+
+ if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
+ "请输入标识器安装部门".show(this)
+ return@setOnClickListener
+ }
+
+ //先存本地再上传服务器
+ saveMarkerInLocal()
+
+ taskViewModel.installLabel(
+ this, companyId,
+ binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
+ binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
+ "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
+ binding.objectInclude.areaView.text.toString(),
+ binding.objectInclude.lineView.text.toString(),
+ binding.objectInclude.roadView.text.toString(),
+ binding.objectInclude.constructDateView.text.toString(),
+ binding.objectInclude.ownerView.text.toString(),
+ objectId,
+ binding.identifierInclude.identifierIdView.text.toString(),
+ binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
+ "${binding.identifierInclude.identifierDeepView.text}mm",
+ binding.identifierInclude.personDeptView.text.toString(),
+ binding.identifierInclude.installTimeView.text.toString(),
+ binding.identifierInclude.lngView.text.toString(),
+ binding.identifierInclude.latView.text.toString(),
+ binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
+ binding.remarkView.text.toString(),
+ realPaths
+ )
+
+ //保存默认值
+ "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
+ "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
+ "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
+ "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
+ "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
+ "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
+ "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
+ "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
+ "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
+ "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
+ "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
+ }
+
+ //读标识器
+ binding.readMarkerButton.setOnClickListener {
+ LoadingDialogHub.show(this, "标识器读取中,请稍后...")
+ countDownTimer.start()
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ outStream.write('2'.code)
+ outStream.flush()
+
+ soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
+ binding.readMarkerButton.isEnabled = false
+ }
+
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ Log.d(kTag, hex)
+ val markerId = hex.take(20).hexToString()
+ if (markerId.isNumber()) {
+ countDownTimer.cancel()
+ cancelLoadingView()
+ binding.readMarkerButton.isEnabled = true
+ binding.identifierInclude.identifierIdView.text = markerId
+ }
+ }
+ })
+ }
+ }
+
+ /**
+ * 搜索标识器超时倒计时
+ * */
+ private val countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
+ override fun onTick(millisUntilFinished: Long) {
+
+ }
+
+ override fun onFinish() {
+ cancelLoadingView()
+ "读取此标识器ID超时,请重试".show(context)
+ binding.readMarkerButton.isEnabled = true
+ }
+ }
+
+ private fun cancelLoadingView() {
+ LoadingDialogHub.dismiss()
+ soundPool.autoPause()
+ serialPortService?.closeSerialPort()
+ }
+
+ private fun saveMarkerInLocal() {
+ val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
+
+ val marker = MarkerLocalBean()
+ marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
+ marker.pipelineType = binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
+ marker.pipelineMaterial =
+ binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
+ marker.pipelineDiameter = "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
+ marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
+ marker.underlyingPipelineType =
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
+ marker.underlyingPipelineMaterial =
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
+ marker.underlyingPipelineDiameter =
+ "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
+ marker.underlyingPipelineDepth =
+ "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
+ marker.buryMethod =
+ binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
+ marker.area = binding.objectInclude.areaView.text.toString()
+ marker.line = binding.objectInclude.lineView.text.toString()
+ marker.road = binding.objectInclude.roadView.text.toString()
+ marker.constructTime = binding.objectInclude.constructDateView.text.toString()
+ marker.owner = binding.objectInclude.ownerView.text.toString()
+ marker.objectId = objectId
+ marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
+ marker.markerType = binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
+ marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
+ marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
+ marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
+ marker.lng = binding.identifierInclude.lngView.text.toString()
+ marker.lat = binding.identifierInclude.latView.text.toString()
+ marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
+ marker.remark = binding.remarkView.text.toString()
+ marker.imagePath = realPaths.toJson()
+
+ DataBaseManager.get.saveMarkerInLocale(marker)
+ }
+
+ private fun takePicture() {
+ PictureSelector.create(this).openCamera(SelectMimeType.ofImage())
+ .forResult(object : OnResultCallbackListener {
+ override fun onResult(result: ArrayList?) {
+ if (result == null) {
+ "拍照失败,请重试".show(context)
+ return
+ }
+ analyticalSelectResults(result[0])
+ }
+
+ override fun onCancel() {
+
+ }
+ })
+ }
+
+ private fun analyticalSelectResults(result: LocalMedia) {
+ //压缩图片
+ result.realPath.compressImage(context, object : OnImageCompressListener {
+ override fun onSuccess(file: File) {
+ realPaths.add(file.absolutePath)
+ imageAdapter.setupImage(realPaths)
+ }
+
+ override fun onError(e: Throwable) {
+ e.printStackTrace()
+ }
+ })
+ }
+
+ 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?) {
+ //在连接正常关闭的情况下不会被调用, 只在Service被破坏了或者被杀死的时候调用
+ }
+ }
+
+ override fun initOnCreate(savedInstanceState: Bundle?) {
+ //绑定串口通信服务
+ Intent(this, SerialPortService::class.java).also {
+ bindService(it, serviceConnection, Context.BIND_AUTO_CREATE)
+ }
+
+ locationTool.getCurrentLocation(true, object : OnGetLocationListener {
+ override fun onAMapLocationGet(location: AMapLocation?) {
+ if (location != null) {
+ binding.identifierInclude.lngView.text = location.longitude.toString()
+ binding.identifierInclude.latView.text = location.latitude.toString()
+ } else {
+ "当前位置信号差,无法获取定位".show(context)
+ }
+ }
+ })
+ soundResourceId = soundPool.load(this, R.raw.ring3, 1)
+
+ //初始化数据
+ initDefaultData()
+ }
+
+ override fun initViewBinding(): ActivityInstallMarkerBinding {
+ return ActivityInstallMarkerBinding.inflate(layoutInflater)
+ }
+
+ override fun observeRequestState() {
+ taskViewModel.loadState.observe(this) {
+ when (it) {
+ LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...")
+
+ LoadState.Success -> {
+ LoadingDialogHub.dismiss()
+ clearDefaultData()
+ "安装成功".show(this)
+ }
+
+ else -> LoadingDialogHub.dismiss()
+ }
+ }
+ }
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ private fun initDefaultData() {
+ binding.titleInclude.titleView.text = "安装新标识器"
+ binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
+
+ imageAdapter = EditableImageAdapter(this, 3, 3)
+ binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
+
+ //设置默认值
+ binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
+ binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
+ binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
+ binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
+ binding.objectInclude.areaView.setText("areaView".getDefaultValue())
+ binding.objectInclude.lineView.setText("lineView".getDefaultValue())
+ binding.objectInclude.roadView.setText("roadView".getDefaultValue())
+ binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
+ binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
+ binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
+
+ /**************************************************************************************/
+ binding.objectInclude.objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0)
+ binding.objectInclude.pipeInclude.materialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeAttachInclude.attachSpinner.show(
+ this, LocaleConstant.ATTACH_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
+ this, LocaleConstant.FEATURE_NAME_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
+ this, LocaleConstant.PIPE_TYPE_ARRAY, 0
+ )
+ binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
+ this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
+ )
+ binding.objectInclude.pipeInclude.buryTypeSpinner.show(
+ this, LocaleConstant.BURY_METHOD_ARRAY, 0
+ )
+ binding.objectInclude.constructDateView.setOnClickListener {
+ val datePicker = DatePickerDialog(
+ this, null,
+ calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH),
+ calendar.get(Calendar.DAY_OF_MONTH)
+ )
+ datePicker.show()
+
+ datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
+ val year = datePicker.datePicker.year
+ val month = datePicker.datePicker.month + 1
+ val day = datePicker.datePicker.dayOfMonth
+ val selectedDate = String.format(
+ "%s-%s-%s", year, month.appendZero(), day.appendZero()
+ )
+
+ //当前时间
+ val current = System.currentTimeMillis().timestampToTime()
+ val today = "$selectedDate $current".dateToTimestamp()
+ if (Date(today).after(Date())) {
+ "建设年代不能早于当前日期".show(context)
+ } else {
+ datePicker.dismiss()
+ binding.objectInclude.constructDateView.text = selectedDate
+ }
+ }
+ }
+ binding.identifierInclude.identifierTypeSpinner.show(
+ this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
+ )
+ binding.identifierInclude.installTimeView.text =
+ System.currentTimeMillis().timestampToCompleteDate()
+ binding.identifierInclude.colorSpinner.show(this, LocaleConstant.COLOR_ARRAY, 0)
+
+ imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
+ override fun onAddImageClick() {
+ takePicture()
+ }
+
+ override fun onItemClick(position: Int) {
+ if (realPaths[position].isEmpty()) {
+ "图片加载失败,无法查看大图".show(context)
+ } else {
+ navigatePageTo(position, realPaths)
+ }
+ }
+
+ override fun onItemLongClick(view: View?, position: Int) {
+ imageAdapter.deleteImage(position)
+ }
+ })
+ }
+
+ //清除默认数据
+ private fun clearDefaultData() {
+ "markerObjectTypeView".setDefaultValue("")
+ "pipelineDiameterView".setDefaultValue("")
+ "buryDeepView".setDefaultValue("")
+ "bottomPipeDiameterView".setDefaultValue("")
+ "bottomPointDeepView".setDefaultValue("")
+ "areaView".setDefaultValue("")
+ "lineView".setDefaultValue("")
+ "roadView".setDefaultValue("")
+ "ownerView".setDefaultValue("")
+ "identifierDeepView".setDefaultValue("")
+ "personDeptView".setDefaultValue("")
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ soundPool.autoPause()
+ locationTool.stopLocation()
+ 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 1dac658..f949269 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,31 +1,25 @@
package com.casic.detector.common.view
-import android.app.DatePickerDialog
-import android.app.Dialog
+import android.content.ComponentName
import android.content.Context
-import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
-import android.hardware.Sensor
-import android.hardware.SensorEvent
-import android.hardware.SensorEventListener
-import android.hardware.SensorManager
import android.media.AudioAttributes
import android.media.SoundPool
import android.os.Bundle
-import android.os.CountDownTimer
+import android.os.IBinder
import android.util.Log
import android.view.KeyEvent
import android.view.View
-import android.widget.AdapterView
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.amap.api.location.AMapLocation
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
-import com.amap.api.maps.AMapUtils
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.CoordinateConverter
import com.amap.api.maps.model.BitmapDescriptorFactory
@@ -34,38 +28,29 @@
import com.amap.api.maps.model.MarkerOptions
import com.amap.api.maps.model.MyLocationStyle
import com.casic.detector.common.R
-import com.casic.detector.common.adapter.EditableImageAdapter
-import com.casic.detector.common.base.SerialPortActivity
+import com.casic.detector.common.base.BaseApplication
import com.casic.detector.common.bean.MarkerLocalBean
import com.casic.detector.common.bean.TaskLocalBean
import com.casic.detector.common.callback.OnGetLocationListener
-import com.casic.detector.common.callback.OnImageCompressListener
+import com.casic.detector.common.callback.OnSerialPortDataListener
import com.casic.detector.common.cluster.ClusterItem
import com.casic.detector.common.cluster.ClusterOverlay
import com.casic.detector.common.cluster.RegionItem
import com.casic.detector.common.databinding.ActivityMainBinding
-import com.casic.detector.common.databinding.DialogInstallMarkerBinding
-import com.casic.detector.common.databinding.DialogSearchMarkerNewBinding
import com.casic.detector.common.extensions.appendDownloadUrl
-import com.casic.detector.common.extensions.compressImage
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.getDefaultValue
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.setDefaultValue
-import com.casic.detector.common.extensions.show
-import com.casic.detector.common.extensions.toColor
import com.casic.detector.common.extensions.toHex
-import com.casic.detector.common.extensions.toObjectType
import com.casic.detector.common.model.TaskDetailLocalModel
import com.casic.detector.common.model.TaskModel
+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.GpioManager
import com.casic.detector.common.utils.LocaleConstant
import com.casic.detector.common.utils.LocationTool
import com.casic.detector.common.utils.NtripAuthorizationCreator
@@ -77,26 +62,15 @@
import com.casic.detector.common.vm.TaskViewModel
import com.casic.detector.common.widgets.MarkerDetailDialog
import com.casic.detector.common.widgets.QueryMarkerDialog
-import com.casic.detector.common.widgets.RadarScanView
import com.casic.detector.common.widgets.SamplePopupWindow
-import com.luck.picture.lib.basic.PictureSelector
-import com.luck.picture.lib.config.SelectMimeType
-import com.luck.picture.lib.entity.LocalMedia
-import com.luck.picture.lib.interfaces.OnResultCallbackListener
-import com.pengxh.kt.lite.extensions.appendZero
-import com.pengxh.kt.lite.extensions.binding
-import com.pengxh.kt.lite.extensions.convertColor
+import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertDrawable
import com.pengxh.kt.lite.extensions.createDownloadFileDir
-import com.pengxh.kt.lite.extensions.dateToTimestamp
import com.pengxh.kt.lite.extensions.dp2px
-import com.pengxh.kt.lite.extensions.getSystemService
-import com.pengxh.kt.lite.extensions.initDialogLayoutParams
import com.pengxh.kt.lite.extensions.isNetworkConnected
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.extensions.timestampToCompleteDate
-import com.pengxh.kt.lite.extensions.timestampToTime
import com.pengxh.kt.lite.extensions.toJson
import com.pengxh.kt.lite.utils.FileDownloadManager
import com.pengxh.kt.lite.utils.LoadState
@@ -108,60 +82,41 @@
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
import io.netty.buffer.Unpooled
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
+import java.io.OutputStream
import java.nio.charset.StandardCharsets
-import java.util.Calendar
-import java.util.Date
import java.util.Timer
import java.util.TimerTask
-import kotlin.math.atan2
-class MainActivity : SerialPortActivity(), SensorEventListener,
- OnSocketConnectListener {
+class MainActivity : KotlinBaseActivity(), OnSocketConnectListener {
private val kTag = "MainActivity"
private val context = this
private val samplePopupWindow by lazy { SamplePopupWindow(this) }
private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) }
private val backDrawables by lazy { HashMap() }
- private val installDialog by lazy { InstallMarkerDialog(this) }
- private val searchNewDialog by lazy { SearchMarkerNewDialog(this) }
private val detailDialog by lazy { MarkerDetailDialog(this) }
private val locationTool by lazy { LocationTool(this) }
- private val rotationMatrix = FloatArray(9)//旋转矩阵缓存
- private val valueArray = FloatArray(3)//方位角数值
+ private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
+ private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
+ private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
private var clickTime: Long = 0
private var markers = ArrayList()
private var clusterOverlay: ClusterOverlay? = null
private var isFreeTask = false
private var freeTaskTitle = ""
private var ids = HashSet()
- private var signalTask: TimerTask? = null
- private var energyTask: TimerTask? = null
- private var searchMarkerTimer: Timer? = null
private var freeTaskId: String? = null
- private var gravity: FloatArray? = null
- private var geomagnetic: FloatArray? = null
private var connectState = ConnectState.CLOSED
private var socketClient: SocketClient? = null
- private lateinit var aMap: AMap
- private lateinit var sensorManager: SensorManager
-
- /***inner class 需要用到*****start*/
- private val gpioManager by lazy { GpioManager() }
- private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
- private val attr = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM)
- .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()
- private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
+ private var serialPortService: SerialPortService? = null
+ private var searchMarkerTimer: Timer? = null
private var soundResourceId = 0
- private var slowSoundResourceId = 0
- private var fastSoundResourceId = 0
private var isExecuteTask = false
-
- /***inner class 需要用到*****end*/
+ private lateinit var aMap: AMap
override fun initViewBinding(): ActivityMainBinding {
return ActivityMainBinding.inflate(layoutInflater)
@@ -171,10 +126,26 @@
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)
+ }
+
soundResourceId = soundPool.load(this, R.raw.ring3, 1)
- slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
- fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)
RtkLocationTool.getCurrentLocation(this) {
if (connectState == ConnectState.SUCCESS) {
@@ -192,8 +163,6 @@
samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES)
samplePopupWindow.setBackgroundDrawable(null)
- sensorManager = getSystemService()!!
-
//task网络请求监听
taskViewModel.markerFileResult.observe(this) {
if (it.isSuccess) {
@@ -316,9 +285,6 @@
//安装。上传,然后存入本地库
binding.installButton.setOnClickListener {
- /**
- * 改为Dialog方式,避免频繁打开/关闭串口
- * */
if (isFreeTask) {
AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示")
.setMessage("正在自由巡检任务中,请完成此次任务之后再使用此功能")
@@ -329,7 +295,7 @@
}
}).build().show()
} else {
- installDialog.show()
+ navigatePageTo()
}
}
@@ -449,8 +415,6 @@
//探测
binding.detectionButton.setOnClickListener {
/**
- * 改为Dialog方式,避免频繁打开/关闭串口
- *
* 如果开启自由巡检就不让探测
* */
if (isFreeTask) {
@@ -463,7 +427,12 @@
}
}).build().show()
} else {
- searchNewDialog.show()
+ val flag = if (isExecuteTask) {
+ "1"
+ } else {
+ "0"
+ }
+ navigatePageTo(flag)
}
}
@@ -476,14 +445,8 @@
override fun onConfirmClick() {
isFreeTask = false
soundPool.autoPause()
-
- //停止信号和ID搜索定时器
- signalTask?.cancel()
- energyTask?.cancel()
searchMarkerTimer?.cancel()
-
- //降低串口电位
- gpioManager.setGpioLow("18")
+ serialPortService?.closeSerialPort()
binding.stopFreeTaskButton.visibility = View.GONE
if (freeTaskId.isNullOrBlank()) {
@@ -527,110 +490,79 @@
}
private fun openSerialPort() {
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- isFreeTask = true
- //自由巡检
- signalTask = object : TimerTask() {
- override fun run() {
- out.write('2'.code)
- out.flush()
- }
- }
-
- energyTask = object : TimerTask() {
- override fun run() {
- out.write('6'.code)
- out.flush()
- }
- }
-
- searchMarkerTimer = Timer()
- searchMarkerTimer?.apply {
- schedule(signalTask, 0, 200)
- schedule(energyTask, 0, 251)
- }
-
binding.stopFreeTaskButton.visibility = View.VISIBLE
- }
+ isFreeTask = true
+ serialPortService?.openSerialPort(object : OnSerialPortDataListener {
+ override fun write(outStream: OutputStream) {
+ searchMarkerTimer = Timer()
+ searchMarkerTimer?.schedule(object : TimerTask() {
+ override fun run() {
+ outStream.write('2'.code)
+ outStream.flush()
- override fun onDataReceived(buffer: ByteArray) {
- val hex = buffer.toHex()
-// Log.d(kTag, "$kTag => $hex")
- if (searchNewDialog.isDetectMarker) {
- searchNewDialog.bindingValue(hex)
- } else if (installDialog.isReadMarker) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- installDialog.bindingValue(markerId)
+ Thread.sleep(50)
+
+ outStream.write('6'.code)
+ outStream.flush()
+ }
+ }, 0, 200)
}
- } else if (isFreeTask) {
- val markerId = hex.take(20).hexToString()
- if (markerId.isNumber()) {
- //只响一次,因为探测频率高,所以依旧是连续的报警声
- soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
- //添加地图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))
- )
+ override fun onDataReceived(buffer: ByteArray) {
+ val hex = buffer.toHex()
+ if (hex.startsWith("4E")) {
+ //只响一次,因为探测频率高,所以依旧是连续的报警声
+ soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f)
+
+ 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()
}
}
- 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()
+ 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 (hex.startsWith("4E")) {
- val energyResponse = hex.take(10).hexToString()
- try {
- val energy = energyResponse.substring(1).toInt()
- if (energy <= 500 && detailDialog.isShowing) {
- detailDialog.dismiss()
- }
- } catch (e: NumberFormatException) {
- e.printStackTrace()
- }
- }
- }
+ })
}
override fun observeRequestState() {
taskViewModel.loadState.observe(this) {
when (it) {
- LoadState.Loading -> {
- if (installDialog.isInstallMarker) {
- LoadingDialogHub.show(this, "标识器安装中,请稍后...")
- } else {
- LoadingDialogHub.show(this, "提交工单中,请稍后")
- }
- }
-
- LoadState.Success -> {
- if (installDialog.isInstallMarker) {
- installDialog.clearDefaultData()
- installDialog.dismiss()
- "${installDialog.markerId}安装成功".show(this)
- }
- LoadingDialogHub.dismiss()
- }
+ LoadState.Loading -> LoadingDialogHub.show(this, "提交工单中,请稍后")
else -> LoadingDialogHub.dismiss()
}
@@ -939,32 +871,6 @@
} else super.onKeyDown(keyCode, event)
}
- override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
- //精度发生变化时触发
- }
-
- override fun onSensorChanged(event: SensorEvent?) {
- //值发生变化时触发
- val type = event?.sensor?.type
-
- if (type == Sensor.TYPE_ACCELEROMETER) {
- gravity = event.values
- } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
- geomagnetic = event.values
- }
-
- if (gravity == null || geomagnetic == null) {
- return
- }
-
- if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
- SensorManager.getOrientation(rotationMatrix, valueArray)
-
- val degree = ((360f + valueArray[0] * 180f / Math.PI) % 360).toInt()
- searchNewDialog.updateDegreeValue(degree)
- }
- }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
@@ -978,14 +884,6 @@
showLabelsOnMap()
}
- //注册加速度传感器监听
- val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
- sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL)
-
- //注册磁场传感器监听
- val magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
- sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_NORMAL)
-
//取缓存
val remoteHost = SaveKeyValues.getValue(
LocaleConstant.RTK_SERVER, "203.107.45.154"
@@ -995,20 +893,20 @@
) as String
//连接千寻RTK服务器
- lifecycleScope.launch(Dispatchers.IO) {
- if (socketClient != null) {
- socketClient?.disconnect()
- delay(3000)
- }
-
- socketClient = SocketClient.Builder()
- .setHostname(remoteHost)
- .setPort(remotePort.toInt())
- .setTimeout(5000)
- .setOnSocketListener(this@MainActivity)
- .build()
- socketClient?.connect()
- }
+// lifecycleScope.launch(Dispatchers.IO) {
+// if (socketClient != null) {
+// socketClient?.disconnect()
+// delay(3000)
+// }
+//
+// socketClient = SocketClient.Builder()
+// .setHostname(remoteHost)
+// .setPort(remotePort.toInt())
+// .setTimeout(5000)
+// .setOnSocketListener(this@MainActivity)
+// .build()
+// socketClient?.connect()
+// }
}
override fun onMessageResponse(data: ByteArray) {
@@ -1021,12 +919,12 @@
val result = String(data, StandardCharsets.UTF_8)
Log.d(kTag, "onMessageResponse: $result")
if (result.contains("ICY 200 OK")) {
- "高精度定位服务器连接成功".show(this)
+ "高精度定位服务连接成功".show(this)
}
} else {
"收到千寻数据返回,长度:${data.size}".show(this)
- out.write(data)
- out.flush()
+// out.write(data)
+// out.flush()
}
}
@@ -1061,7 +959,6 @@
override fun onPause() {
super.onPause()
binding.mapView.onPause()
- sensorManager.unregisterListener(this)
}
override fun onSaveInstanceState(outState: Bundle) {
@@ -1072,794 +969,11 @@
override fun onDestroy() {
super.onDestroy()
binding.mapView.onDestroy()
- soundPool.release()
+ soundPool.autoPause()
+ searchMarkerTimer?.cancel()
+ serialPortService?.closeSerialPort()
locationTool.stopLocation()
- //降低串口电位
- gpioManager.setGpioLow("18")
+ unbindService(serviceConnection)
+ BaseApplication.get().closeSerialPort()
}
-
- /**安装标识器对话框******************************************************************************/
- inner class InstallMarkerDialog(private val context: Context) : Dialog(context) {
-
- private val binding: DialogInstallMarkerBinding by binding()
- private val calendar by lazy { Calendar.getInstance() }
- private val realPaths = ArrayList() //真实图片路径
- private lateinit var imageAdapter: EditableImageAdapter
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
-
- var isReadMarker = false
- var isInstallMarker = false
- var markerId = ""
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
-
- //初始化数据
- initDefaultData()
-
- //返回
- binding.titleInclude.leftBackView.setOnClickListener {
- soundPool.autoPause()
- dismiss()
- }
-
- binding.objectInclude.objectTypeSpinner.onItemSelectedListener =
- object : AdapterView.OnItemSelectedListener {
- override fun onItemSelected(
- parent: AdapterView<*>?, view: View?, position: Int, id: Long
- ) {
- when (position) {
- 0 -> {
- //显示管线属性
- binding.objectInclude.pipeInclude.root.visibility = View.VISIBLE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 1 -> {
- //显示管线附属物属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 2 -> {
- //显示管线特征点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility =
- View.VISIBLE
- binding.objectInclude.pipeCrossInclude.root.visibility = View.GONE
- }
-
- 3 -> {
- //显示交叉穿越点属性
- binding.objectInclude.pipeInclude.root.visibility = View.GONE
- binding.objectInclude.pipeAttachInclude.root.visibility = View.GONE
- binding.objectInclude.pipeFeatureInclude.root.visibility = View.GONE
- binding.objectInclude.pipeCrossInclude.root.visibility =
- View.VISIBLE
- }
- }
- }
-
- override fun onNothingSelected(parent: AdapterView<*>?) {
-
- }
- }
-
- //安装
- binding.installButton.setOnClickListener {
- val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
- if (binding.objectInclude.pipeInclude.markerObjectTypeView.text.isNullOrBlank()) {
- when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
- "管线" -> "请输入管线种类!".show(context)
- "管线附属物" -> "请输入附属物名称!".show(context)
- "管线特征管点" -> "请输入特征管点!".show(context)
- "交叉穿越点" -> "请输入上层管种类!".show(context)
- }
- return@setOnClickListener
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "管线") {
- if (binding.objectInclude.pipeInclude.pipelineDiameterView.text.isNullOrBlank()) {
- "请输入管径".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.pipeInclude.buryDeepView.text.isNullOrBlank()) {
- "请输入埋深".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.objectTypeSpinner.selectedItem == "交叉穿越点") {
- if (binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.isNullOrBlank()) {
- "请输入下层管管径".show(context)
- return@setOnClickListener
- }
- }
-
- if (binding.objectInclude.areaView.text.isNullOrBlank()) {
- "请输入所属区域".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.lineView.text.isNullOrBlank()) {
- "请输入所属线路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.roadView.text.isNullOrBlank()) {
- "请输入所属道路".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
- "请选择建设年代".show(context)
- return@setOnClickListener
- }
-
- if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
- "请输入权属单位".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
- "请先读取标识器获取ID".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
- "请输入标识器埋深".show(context)
- return@setOnClickListener
- }
-
- if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
- "请输入标识器安装部门".show(context)
- return@setOnClickListener
- }
-
- //先存本地再上传服务器
- saveMarkerInLocal()
-
- isInstallMarker = true
- taskViewModel.installLabel(
- context,
- companyId,
- binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString(),
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm",
- "${binding.objectInclude.pipeInclude.buryDeepView.text}mm",
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString(),
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString(),
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm",
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm",
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString(),
- binding.objectInclude.areaView.text.toString(),
- binding.objectInclude.lineView.text.toString(),
- binding.objectInclude.roadView.text.toString(),
- binding.objectInclude.constructDateView.text.toString(),
- binding.objectInclude.ownerView.text.toString(),
- objectId,
- binding.identifierInclude.identifierIdView.text.toString(),
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
- "${binding.identifierInclude.identifierDeepView.text}mm",
- binding.identifierInclude.personDeptView.text.toString(),
- binding.identifierInclude.installTimeView.text.toString(),
- binding.identifierInclude.lngView.text.toString(),
- binding.identifierInclude.latView.text.toString(),
- binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
- binding.remarkView.text.toString(),
- realPaths
- )
-
- //保存默认值
- "markerObjectTypeView".setDefaultValue(binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString())
- "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipeInclude.pipelineDiameterView.text.toString())
- "buryDeepView".setDefaultValue(binding.objectInclude.pipeInclude.buryDeepView.text.toString())
- "bottomPipeDiameterView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text.toString())
- "bottomPointDeepView".setDefaultValue(binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text.toString())
- "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
- "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
- "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
- "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
- "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
- "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
- }
-
- //读标识器
- binding.readMarkerButton.setOnClickListener {
- LoadingDialogHub.show(this@MainActivity, "标识器读取中,请稍后...")
- binding.readMarkerButton.isEnabled = false
-
- isReadMarker = true
-
- //调高串口电位
- gpioManager.setGpioHigh("18")
-
- soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
-
- out.write('2'.code)
- out.flush()
-
- countDownTimer = object : CountDownTimer(10 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- "读取此标识器ID超时,请退出应用再试".show(context)
- }
- }
- countDownTimer.start()
- }
- }
-
- override fun show() {
- super.show()
- locationTool = LocationTool(context)
- locationTool.getCurrentLocation(true, object : OnGetLocationListener {
- override fun onAMapLocationGet(location: AMapLocation?) {
- if (location != null) {
- binding.identifierInclude.lngView.text = location.longitude.toString()
- binding.identifierInclude.latView.text = location.latitude.toString()
- } else {
- "当前位置信号差,无法获取定位".show(context)
- }
- }
- })
- }
-
- fun bindingValue(markerId: String) {
- this.markerId = markerId
- LoadingDialogHub.dismiss()
- soundPool.autoPause()
- countDownTimer.cancel()
- binding.readMarkerButton.isEnabled = true
-
- //降低串口电位
- gpioManager.setGpioLow("18")
-
- isReadMarker = false
- binding.identifierInclude.identifierIdView.text = markerId
- }
-
- override fun dismiss() {
- //降低串口电位
- gpioManager.setGpioLow("18")
- soundPool.autoPause()
- isInstallMarker = false
- locationTool.stopLocation()
- super.dismiss()
- }
-
- private fun initDefaultData() {
- binding.titleInclude.titleView.text = "安装新标识器"
- binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))
-
- imageAdapter = EditableImageAdapter(context, 3, 3)
- binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter
-
- //设置默认值
- binding.objectInclude.pipeInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
- binding.objectInclude.pipeInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
- binding.objectInclude.pipeInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.setText("bottomPipeDiameterView".getDefaultValue())
- binding.objectInclude.pipeCrossInclude.bottomPointDeepView.setText("bottomPointDeepView".getDefaultValue())
- binding.objectInclude.areaView.setText("areaView".getDefaultValue())
- binding.objectInclude.lineView.setText("lineView".getDefaultValue())
- binding.objectInclude.roadView.setText("roadView".getDefaultValue())
- binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
- binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
- binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())
-
- /**************************************************************************************/
- binding.objectInclude.objectTypeSpinner.show(
- this@MainActivity, LocaleConstant.POINT_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.materialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeAttachInclude.attachSpinner.show(
- this@MainActivity, LocaleConstant.ATTACH_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeFeatureInclude.featureSpinner.show(
- this@MainActivity, LocaleConstant.FEATURE_NAME_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.topPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_TYPE_ARRAY, 0
- )
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.show(
- this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
- )
- binding.objectInclude.pipeInclude.buryTypeSpinner.show(
- this@MainActivity, LocaleConstant.BURY_METHOD_ARRAY, 0
- )
-
- binding.objectInclude.constructDateView.setOnClickListener {
- val datePicker = DatePickerDialog(
- context,
- null,
- calendar.get(Calendar.YEAR),
- calendar.get(Calendar.MONTH),
- calendar.get(Calendar.DAY_OF_MONTH)
- )
- datePicker.show()
-
- datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
- val year = datePicker.datePicker.year
- val month = datePicker.datePicker.month + 1
- val day = datePicker.datePicker.dayOfMonth
- val selectedDate = String.format(
- "%s-%s-%s", year, month.appendZero(), day.appendZero()
- )
-
- //当前时间
- val current = System.currentTimeMillis().timestampToTime()
- val today = "$selectedDate $current".dateToTimestamp()
- if (Date(today).after(Date())) {
- "建设年代不能早于当前日期".show(context)
- } else {
- datePicker.dismiss()
- binding.objectInclude.constructDateView.text = selectedDate
- }
- }
- }
-
- binding.identifierInclude.identifierTypeSpinner.show(
- this@MainActivity, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
- )
-
- binding.identifierInclude.installTimeView.text =
- System.currentTimeMillis().timestampToCompleteDate()
-
- binding.identifierInclude.colorSpinner.show(
- this@MainActivity, LocaleConstant.COLOR_ARRAY, 0
- )
-
- imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
- override fun onAddImageClick() {
- takePicture()
- }
-
- override fun onItemClick(position: Int) {
- if (realPaths[position].isEmpty()) {
- "图片加载失败,无法查看大图".show(context)
- } else {
- context.navigatePageTo(position, realPaths)
- }
- }
-
- override fun onItemLongClick(view: View?, position: Int) {
- imageAdapter.deleteImage(position)
- }
- })
- /**************************************************************************************/
- }
-
- //清除默认数据
- fun clearDefaultData() {
- "markerObjectTypeView".setDefaultValue("")
- "pipelineDiameterView".setDefaultValue("")
- "buryDeepView".setDefaultValue("")
- "bottomPipeDiameterView".setDefaultValue("")
- "bottomPointDeepView".setDefaultValue("")
- "areaView".setDefaultValue("")
- "lineView".setDefaultValue("")
- "roadView".setDefaultValue("")
- "ownerView".setDefaultValue("")
- "identifierDeepView".setDefaultValue("")
- "personDeptView".setDefaultValue("")
- }
-
- private fun saveMarkerInLocal() {
- val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
-
- val marker = MarkerLocalBean()
- marker.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
- marker.pipelineType =
- binding.objectInclude.pipeInclude.markerObjectTypeView.text.toString()
- marker.pipelineMaterial =
- binding.objectInclude.pipeInclude.materialSpinner.selectedItem.toString()
- marker.pipelineDiameter =
- "${binding.objectInclude.pipeInclude.pipelineDiameterView.text}mm"
- marker.buryDepth = "${binding.objectInclude.pipeInclude.buryDeepView.text}mm"
- marker.underlyingPipelineType =
- binding.objectInclude.pipeCrossInclude.bottomPipeTypeSpinner.selectedItem.toString()
- marker.underlyingPipelineMaterial =
- binding.objectInclude.pipeCrossInclude.bottomPipeMaterialSpinner.selectedItem.toString()
- marker.underlyingPipelineDiameter =
- "${binding.objectInclude.pipeCrossInclude.bottomPipeDiameterView.text}mm"
- marker.underlyingPipelineDepth =
- "${binding.objectInclude.pipeCrossInclude.bottomPointDeepView.text}mm"
- marker.buryMethod =
- binding.objectInclude.pipeInclude.buryTypeSpinner.selectedItem.toString()
- marker.area = binding.objectInclude.areaView.text.toString()
- marker.line = binding.objectInclude.lineView.text.toString()
- marker.road = binding.objectInclude.roadView.text.toString()
- marker.constructTime = binding.objectInclude.constructDateView.text.toString()
- marker.owner = binding.objectInclude.ownerView.text.toString()
- marker.objectId = objectId
- marker.markerId = binding.identifierInclude.identifierIdView.text.toString()
- marker.markerType =
- binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
- marker.markerDepth = "${binding.identifierInclude.identifierDeepView.text}mm"
- marker.installationDept = binding.identifierInclude.personDeptView.text.toString()
- marker.updateTime = binding.identifierInclude.installTimeView.text.toString()
- marker.lng = binding.identifierInclude.lngView.text.toString()
- marker.lat = binding.identifierInclude.latView.text.toString()
- marker.color = binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
- marker.remark = binding.remarkView.text.toString()
- marker.imagePath = realPaths.toJson()
-
- DataBaseManager.get.saveMarkerInLocale(marker)
- }
-
- private fun takePicture() {
- PictureSelector.create(this@MainActivity).openCamera(SelectMimeType.ofImage())
- .forResult(object : OnResultCallbackListener {
- override fun onResult(result: java.util.ArrayList?) {
- if (result == null) {
- "拍照失败,请重试".show(context)
- return
- }
- analyticalSelectResults(result[0])
- }
-
- override fun onCancel() {
-
- }
- })
- }
-
- private fun analyticalSelectResults(result: LocalMedia) {
- //压缩图片
- result.realPath.compressImage(context, object : OnImageCompressListener {
- override fun onSuccess(file: File) {
- realPaths.add(file.absolutePath)
- imageAdapter.setupImage(realPaths)
- }
-
- override fun onError(e: Throwable) {
- e.printStackTrace()
- }
- })
- }
- }
-
- /**探测标识器新对话框****************************************************************************/
- inner class SearchMarkerNewDialog(private val context: Context) : Dialog(context) {
-
- private val taskId by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
- }
- private val taskCode by lazy {
- SaveKeyValues.getValue(LocaleConstant.TASK_CODE, "") as String
- }
- private val markerPoints by lazy { ArrayList() }
- private val binding: DialogSearchMarkerNewBinding by binding()
- private var markerId = ""//实际探测出来的标识器ID
- private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID
- private lateinit var searchMarkerTimer: Timer
- private lateinit var signalTask: TimerTask
- private lateinit var energyTask: TimerTask
- private lateinit var countDownTimer: CountDownTimer
- private lateinit var locationTool: LocationTool
- var isDetectMarker = false
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- this.initDialogLayoutParams(1f)
- binding.depthButton.setOnClickListener {
- signalTask.cancel()
- energyTask.cancel()
- searchMarkerTimer.cancel()
-
- out.write('3'.code)
- val result = DataBaseManager.get.queryMarkerById(markerId)
- if (result.isNotEmpty()) {
- val tag = when (result.first().markerType) {
- "EM30" -> '7'
- "EM50" -> '8'
- "EM14" -> '9'
- else -> '1'
- }
- if (tag == '1') {
- "此标识器无法读取埋深!".show(context)
- initTimer()
- } else {
- // 发送读取标识器埋设深度指令
- LoadingDialogHub.show(this@MainActivity, "正在测距,请稍后...")
- out.write(tag.code)
- out.flush()
- countDownTimer = object : CountDownTimer(15 * 1000, 1000) {
- override fun onTick(millisUntilFinished: Long) {
-
- }
-
- override fun onFinish() {
- LoadingDialogHub.dismiss()
- "探测此标识器深度超时,请重试".show(context)
- initTimer()
- }
- }
- countDownTimer.start()
- }
- } else {
- "标识器未安装,安装成功后才可读取埋深!".show(context)
- initTimer()
- }
- }
-
- binding.markerInfoButton.setOnClickListener {
- val id = if (markerId == "") {
- nearestMarkerId
- } else {
- markerId
- }
- //查库
- val result = DataBaseManager.get.queryMarkerById(id)
- if (result.isNotEmpty()) {
- context.navigatePageTo