diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/ArrayList.kt b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt new file mode 100644 index 0000000..52f8ac9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt @@ -0,0 +1,20 @@ +package com.casic.detector.extensions + +/** + * ArrayList扩展方法 + */ + +//将集合格式化成满足上传格式的数据 +fun ArrayList.reformat(): String { + if (this.isEmpty()) return "" + val builder = StringBuilder() + //循环遍历元素,同时得到元素index(下标) + this.forEachIndexed { index, s -> + if (index == this.size - 1) { + builder.append(s) + } else { + builder.append(s).append(",") + } + } + return builder.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/ArrayList.kt b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt new file mode 100644 index 0000000..52f8ac9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt @@ -0,0 +1,20 @@ +package com.casic.detector.extensions + +/** + * ArrayList扩展方法 + */ + +//将集合格式化成满足上传格式的数据 +fun ArrayList.reformat(): String { + if (this.isEmpty()) return "" + val builder = StringBuilder() + //循环遍历元素,同时得到元素index(下标) + this.forEachIndexed { index, s -> + if (index == this.size - 1) { + builder.append(s) + } else { + builder.append(s).append(",") + } + } + return builder.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index b76d83d..785b89f 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -122,4 +122,9 @@ } } return sb.toString() +} + +fun String.isNumber(): Boolean { + val regex = Regex("[-+]?\\d+(\\.\\d+)?") + return this.matches(regex) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/ArrayList.kt b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt new file mode 100644 index 0000000..52f8ac9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt @@ -0,0 +1,20 @@ +package com.casic.detector.extensions + +/** + * ArrayList扩展方法 + */ + +//将集合格式化成满足上传格式的数据 +fun ArrayList.reformat(): String { + if (this.isEmpty()) return "" + val builder = StringBuilder() + //循环遍历元素,同时得到元素index(下标) + this.forEachIndexed { index, s -> + if (index == this.size - 1) { + builder.append(s) + } else { + builder.append(s).append(",") + } + } + return builder.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index b76d83d..785b89f 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -122,4 +122,9 @@ } } return sb.toString() +} + +fun String.isNumber(): Boolean { + val regex = Regex("[-+]?\\d+(\\.\\d+)?") + return this.matches(regex) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java index cab23bb..682c3f8 100644 --- a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java +++ b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java @@ -13,20 +13,25 @@ // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + /** * Master of DAO (schema version 1): knows all DAOs. */ public class DaoMaster extends AbstractDaoMaster { public static final int SCHEMA_VERSION = 1; - /** Creates underlying database table using DAOs. */ + /** + * Creates underlying database table using DAOs. + */ public static void createAllTables(Database db, boolean ifNotExists) { LabelBeanDao.createTable(db, ifNotExists); SmallLabelBeanDao.createTable(db, ifNotExists); TaskBeanDao.createTable(db, ifNotExists); } - /** Drops underlying database table using DAOs. */ + /** + * Drops underlying database table using DAOs. + */ public static void dropAllTables(Database db, boolean ifExists) { LabelBeanDao.dropTable(db, ifExists); SmallLabelBeanDao.dropTable(db, ifExists); @@ -81,7 +86,9 @@ } } - /** WARNING: Drops all table on Upgrade! Use only during development. */ + /** + * WARNING: Drops all table on Upgrade! Use only during development. + */ public static class DevOpenHelper extends OpenHelper { public DevOpenHelper(Context context, String name) { super(context, name); diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/ArrayList.kt b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt new file mode 100644 index 0000000..52f8ac9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt @@ -0,0 +1,20 @@ +package com.casic.detector.extensions + +/** + * ArrayList扩展方法 + */ + +//将集合格式化成满足上传格式的数据 +fun ArrayList.reformat(): String { + if (this.isEmpty()) return "" + val builder = StringBuilder() + //循环遍历元素,同时得到元素index(下标) + this.forEachIndexed { index, s -> + if (index == this.size - 1) { + builder.append(s) + } else { + builder.append(s).append(",") + } + } + return builder.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index b76d83d..785b89f 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -122,4 +122,9 @@ } } return sb.toString() +} + +fun String.isNumber(): Boolean { + val regex = Regex("[-+]?\\d+(\\.\\d+)?") + return this.matches(regex) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java index cab23bb..682c3f8 100644 --- a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java +++ b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java @@ -13,20 +13,25 @@ // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + /** * Master of DAO (schema version 1): knows all DAOs. */ public class DaoMaster extends AbstractDaoMaster { public static final int SCHEMA_VERSION = 1; - /** Creates underlying database table using DAOs. */ + /** + * Creates underlying database table using DAOs. + */ public static void createAllTables(Database db, boolean ifNotExists) { LabelBeanDao.createTable(db, ifNotExists); SmallLabelBeanDao.createTable(db, ifNotExists); TaskBeanDao.createTable(db, ifNotExists); } - /** Drops underlying database table using DAOs. */ + /** + * Drops underlying database table using DAOs. + */ public static void dropAllTables(Database db, boolean ifExists) { LabelBeanDao.dropTable(db, ifExists); SmallLabelBeanDao.dropTable(db, ifExists); @@ -81,7 +86,9 @@ } } - /** WARNING: Drops all table on Upgrade! Use only during development. */ + /** + * WARNING: Drops all table on Upgrade! Use only during development. + */ public static class DevOpenHelper extends OpenHelper { public DevOpenHelper(Context context, String name) { super(context, name); diff --git a/app/src/main/java/com/casic/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/detector/model/CalculateResult.kt new file mode 100644 index 0000000..02cb0a0 --- /dev/null +++ b/app/src/main/java/com/casic/detector/model/CalculateResult.kt @@ -0,0 +1,3 @@ +package com.casic.detector.model + +data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/ArrayList.kt b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt new file mode 100644 index 0000000..52f8ac9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt @@ -0,0 +1,20 @@ +package com.casic.detector.extensions + +/** + * ArrayList扩展方法 + */ + +//将集合格式化成满足上传格式的数据 +fun ArrayList.reformat(): String { + if (this.isEmpty()) return "" + val builder = StringBuilder() + //循环遍历元素,同时得到元素index(下标) + this.forEachIndexed { index, s -> + if (index == this.size - 1) { + builder.append(s) + } else { + builder.append(s).append(",") + } + } + return builder.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index b76d83d..785b89f 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -122,4 +122,9 @@ } } return sb.toString() +} + +fun String.isNumber(): Boolean { + val regex = Regex("[-+]?\\d+(\\.\\d+)?") + return this.matches(regex) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java index cab23bb..682c3f8 100644 --- a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java +++ b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java @@ -13,20 +13,25 @@ // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + /** * Master of DAO (schema version 1): knows all DAOs. */ public class DaoMaster extends AbstractDaoMaster { public static final int SCHEMA_VERSION = 1; - /** Creates underlying database table using DAOs. */ + /** + * Creates underlying database table using DAOs. + */ public static void createAllTables(Database db, boolean ifNotExists) { LabelBeanDao.createTable(db, ifNotExists); SmallLabelBeanDao.createTable(db, ifNotExists); TaskBeanDao.createTable(db, ifNotExists); } - /** Drops underlying database table using DAOs. */ + /** + * Drops underlying database table using DAOs. + */ public static void dropAllTables(Database db, boolean ifExists) { LabelBeanDao.dropTable(db, ifExists); SmallLabelBeanDao.dropTable(db, ifExists); @@ -81,7 +86,9 @@ } } - /** WARNING: Drops all table on Upgrade! Use only during development. */ + /** + * WARNING: Drops all table on Upgrade! Use only during development. + */ public static class DevOpenHelper extends OpenHelper { public DevOpenHelper(Context context, String name) { super(context, name); diff --git a/app/src/main/java/com/casic/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/detector/model/CalculateResult.kt new file mode 100644 index 0000000..02cb0a0 --- /dev/null +++ b/app/src/main/java/com/casic/detector/model/CalculateResult.kt @@ -0,0 +1,3 @@ +package com.casic.detector.model + +data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 43a8484..cae51d5 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -82,25 +82,21 @@ */ @GET("/ems/rs/task/update-task-mark") suspend fun uploadMarker( - @Query("taskDetailId") taskId: String, + @Query("taskDetailId") taskId: String ): String /** * 新建自由巡检任务 * */ - @GET("") + @GET("ems/rs/task/addAppTask") suspend fun createFreeTask( @Query("patrollerId") patrollerId: String, - @Query("description") description: String, + @Query("description") description: String ): String /** * 上传自由巡检过程中发现的标识器 * */ - @Multipart - @POST("") - suspend fun uploadTaskMarker( - @Field("taskId") taskId: String, - @Body requestBody: RequestBody, - ): String + @POST("ems/event/uploadAppMarker.do") + suspend fun uploadTaskMarker(@Body requestBody: RequestBody): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/ArrayList.kt b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt new file mode 100644 index 0000000..52f8ac9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt @@ -0,0 +1,20 @@ +package com.casic.detector.extensions + +/** + * ArrayList扩展方法 + */ + +//将集合格式化成满足上传格式的数据 +fun ArrayList.reformat(): String { + if (this.isEmpty()) return "" + val builder = StringBuilder() + //循环遍历元素,同时得到元素index(下标) + this.forEachIndexed { index, s -> + if (index == this.size - 1) { + builder.append(s) + } else { + builder.append(s).append(",") + } + } + return builder.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index b76d83d..785b89f 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -122,4 +122,9 @@ } } return sb.toString() +} + +fun String.isNumber(): Boolean { + val regex = Regex("[-+]?\\d+(\\.\\d+)?") + return this.matches(regex) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java index cab23bb..682c3f8 100644 --- a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java +++ b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java @@ -13,20 +13,25 @@ // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + /** * Master of DAO (schema version 1): knows all DAOs. */ public class DaoMaster extends AbstractDaoMaster { public static final int SCHEMA_VERSION = 1; - /** Creates underlying database table using DAOs. */ + /** + * Creates underlying database table using DAOs. + */ public static void createAllTables(Database db, boolean ifNotExists) { LabelBeanDao.createTable(db, ifNotExists); SmallLabelBeanDao.createTable(db, ifNotExists); TaskBeanDao.createTable(db, ifNotExists); } - /** Drops underlying database table using DAOs. */ + /** + * Drops underlying database table using DAOs. + */ public static void dropAllTables(Database db, boolean ifExists) { LabelBeanDao.dropTable(db, ifExists); SmallLabelBeanDao.dropTable(db, ifExists); @@ -81,7 +86,9 @@ } } - /** WARNING: Drops all table on Upgrade! Use only during development. */ + /** + * WARNING: Drops all table on Upgrade! Use only during development. + */ public static class DevOpenHelper extends OpenHelper { public DevOpenHelper(Context context, String name) { super(context, name); diff --git a/app/src/main/java/com/casic/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/detector/model/CalculateResult.kt new file mode 100644 index 0000000..02cb0a0 --- /dev/null +++ b/app/src/main/java/com/casic/detector/model/CalculateResult.kt @@ -0,0 +1,3 @@ +package com.casic.detector.model + +data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 43a8484..cae51d5 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -82,25 +82,21 @@ */ @GET("/ems/rs/task/update-task-mark") suspend fun uploadMarker( - @Query("taskDetailId") taskId: String, + @Query("taskDetailId") taskId: String ): String /** * 新建自由巡检任务 * */ - @GET("") + @GET("ems/rs/task/addAppTask") suspend fun createFreeTask( @Query("patrollerId") patrollerId: String, - @Query("description") description: String, + @Query("description") description: String ): String /** * 上传自由巡检过程中发现的标识器 * */ - @Multipart - @POST("") - suspend fun uploadTaskMarker( - @Field("taskId") taskId: String, - @Body requestBody: RequestBody, - ): String + @POST("ems/event/uploadAppMarker.do") + suspend fun uploadTaskMarker(@Body requestBody: RequestBody): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 8ae0794..ac06760 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -1,9 +1,9 @@ package com.casic.detector.retrofit +import com.casic.detector.extensions.reformat import com.casic.detector.utils.LocaleConstant import com.google.gson.Gson import com.google.gson.JsonObject -import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType @@ -16,7 +16,6 @@ object RetrofitServiceManager { private val gson by lazy { Gson() } - private val typeToken = object : TypeToken>() {}.type private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String @@ -233,12 +232,13 @@ /** * 上传自由巡检过程中发现的标识器 */ - suspend fun uploadTaskMarker(taskId: String, models: List): String { + suspend fun uploadTaskMarker(taskId: String, models: ArrayList): String { val param = JsonObject() - param.add("markers", gson.toJsonTree(models, typeToken).asJsonArray) + param.addProperty("taskId", taskId) + param.addProperty("ids", models.reformat()) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return createApi().uploadTaskMarker(taskId, requestBody) + return createApi().uploadTaskMarker(requestBody) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/ArrayList.kt b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt new file mode 100644 index 0000000..52f8ac9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt @@ -0,0 +1,20 @@ +package com.casic.detector.extensions + +/** + * ArrayList扩展方法 + */ + +//将集合格式化成满足上传格式的数据 +fun ArrayList.reformat(): String { + if (this.isEmpty()) return "" + val builder = StringBuilder() + //循环遍历元素,同时得到元素index(下标) + this.forEachIndexed { index, s -> + if (index == this.size - 1) { + builder.append(s) + } else { + builder.append(s).append(",") + } + } + return builder.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index b76d83d..785b89f 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -122,4 +122,9 @@ } } return sb.toString() +} + +fun String.isNumber(): Boolean { + val regex = Regex("[-+]?\\d+(\\.\\d+)?") + return this.matches(regex) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java index cab23bb..682c3f8 100644 --- a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java +++ b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java @@ -13,20 +13,25 @@ // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + /** * Master of DAO (schema version 1): knows all DAOs. */ public class DaoMaster extends AbstractDaoMaster { public static final int SCHEMA_VERSION = 1; - /** Creates underlying database table using DAOs. */ + /** + * Creates underlying database table using DAOs. + */ public static void createAllTables(Database db, boolean ifNotExists) { LabelBeanDao.createTable(db, ifNotExists); SmallLabelBeanDao.createTable(db, ifNotExists); TaskBeanDao.createTable(db, ifNotExists); } - /** Drops underlying database table using DAOs. */ + /** + * Drops underlying database table using DAOs. + */ public static void dropAllTables(Database db, boolean ifExists) { LabelBeanDao.dropTable(db, ifExists); SmallLabelBeanDao.dropTable(db, ifExists); @@ -81,7 +86,9 @@ } } - /** WARNING: Drops all table on Upgrade! Use only during development. */ + /** + * WARNING: Drops all table on Upgrade! Use only during development. + */ public static class DevOpenHelper extends OpenHelper { public DevOpenHelper(Context context, String name) { super(context, name); diff --git a/app/src/main/java/com/casic/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/detector/model/CalculateResult.kt new file mode 100644 index 0000000..02cb0a0 --- /dev/null +++ b/app/src/main/java/com/casic/detector/model/CalculateResult.kt @@ -0,0 +1,3 @@ +package com.casic.detector.model + +data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 43a8484..cae51d5 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -82,25 +82,21 @@ */ @GET("/ems/rs/task/update-task-mark") suspend fun uploadMarker( - @Query("taskDetailId") taskId: String, + @Query("taskDetailId") taskId: String ): String /** * 新建自由巡检任务 * */ - @GET("") + @GET("ems/rs/task/addAppTask") suspend fun createFreeTask( @Query("patrollerId") patrollerId: String, - @Query("description") description: String, + @Query("description") description: String ): String /** * 上传自由巡检过程中发现的标识器 * */ - @Multipart - @POST("") - suspend fun uploadTaskMarker( - @Field("taskId") taskId: String, - @Body requestBody: RequestBody, - ): String + @POST("ems/event/uploadAppMarker.do") + suspend fun uploadTaskMarker(@Body requestBody: RequestBody): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 8ae0794..ac06760 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -1,9 +1,9 @@ package com.casic.detector.retrofit +import com.casic.detector.extensions.reformat import com.casic.detector.utils.LocaleConstant import com.google.gson.Gson import com.google.gson.JsonObject -import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType @@ -16,7 +16,6 @@ object RetrofitServiceManager { private val gson by lazy { Gson() } - private val typeToken = object : TypeToken>() {}.type private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String @@ -233,12 +232,13 @@ /** * 上传自由巡检过程中发现的标识器 */ - suspend fun uploadTaskMarker(taskId: String, models: List): String { + suspend fun uploadTaskMarker(taskId: String, models: ArrayList): String { val param = JsonObject() - param.add("markers", gson.toJsonTree(models, typeToken).asJsonArray) + param.addProperty("taskId", taskId) + param.addProperty("ids", models.reformat()) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return createApi().uploadTaskMarker(taskId, requestBody) + return createApi().uploadTaskMarker(requestBody) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt index 1c7d95b..7e627a4 100644 --- a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt @@ -105,7 +105,7 @@ fun queryTaskLabelByIdAndState(identifierId: String, state: String): TaskBean? { return taskBeanDao.queryBuilder() .where( - TaskBeanDao.Properties.MarkerRealId.eq(identifierId), + TaskBeanDao.Properties.MarkerId.eq(identifierId), TaskBeanDao.Properties.State.eq(state) ).list().firstOrNull() } diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/ArrayList.kt b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt new file mode 100644 index 0000000..52f8ac9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt @@ -0,0 +1,20 @@ +package com.casic.detector.extensions + +/** + * ArrayList扩展方法 + */ + +//将集合格式化成满足上传格式的数据 +fun ArrayList.reformat(): String { + if (this.isEmpty()) return "" + val builder = StringBuilder() + //循环遍历元素,同时得到元素index(下标) + this.forEachIndexed { index, s -> + if (index == this.size - 1) { + builder.append(s) + } else { + builder.append(s).append(",") + } + } + return builder.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index b76d83d..785b89f 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -122,4 +122,9 @@ } } return sb.toString() +} + +fun String.isNumber(): Boolean { + val regex = Regex("[-+]?\\d+(\\.\\d+)?") + return this.matches(regex) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java index cab23bb..682c3f8 100644 --- a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java +++ b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java @@ -13,20 +13,25 @@ // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + /** * Master of DAO (schema version 1): knows all DAOs. */ public class DaoMaster extends AbstractDaoMaster { public static final int SCHEMA_VERSION = 1; - /** Creates underlying database table using DAOs. */ + /** + * Creates underlying database table using DAOs. + */ public static void createAllTables(Database db, boolean ifNotExists) { LabelBeanDao.createTable(db, ifNotExists); SmallLabelBeanDao.createTable(db, ifNotExists); TaskBeanDao.createTable(db, ifNotExists); } - /** Drops underlying database table using DAOs. */ + /** + * Drops underlying database table using DAOs. + */ public static void dropAllTables(Database db, boolean ifExists) { LabelBeanDao.dropTable(db, ifExists); SmallLabelBeanDao.dropTable(db, ifExists); @@ -81,7 +86,9 @@ } } - /** WARNING: Drops all table on Upgrade! Use only during development. */ + /** + * WARNING: Drops all table on Upgrade! Use only during development. + */ public static class DevOpenHelper extends OpenHelper { public DevOpenHelper(Context context, String name) { super(context, name); diff --git a/app/src/main/java/com/casic/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/detector/model/CalculateResult.kt new file mode 100644 index 0000000..02cb0a0 --- /dev/null +++ b/app/src/main/java/com/casic/detector/model/CalculateResult.kt @@ -0,0 +1,3 @@ +package com.casic.detector.model + +data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 43a8484..cae51d5 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -82,25 +82,21 @@ */ @GET("/ems/rs/task/update-task-mark") suspend fun uploadMarker( - @Query("taskDetailId") taskId: String, + @Query("taskDetailId") taskId: String ): String /** * 新建自由巡检任务 * */ - @GET("") + @GET("ems/rs/task/addAppTask") suspend fun createFreeTask( @Query("patrollerId") patrollerId: String, - @Query("description") description: String, + @Query("description") description: String ): String /** * 上传自由巡检过程中发现的标识器 * */ - @Multipart - @POST("") - suspend fun uploadTaskMarker( - @Field("taskId") taskId: String, - @Body requestBody: RequestBody, - ): String + @POST("ems/event/uploadAppMarker.do") + suspend fun uploadTaskMarker(@Body requestBody: RequestBody): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 8ae0794..ac06760 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -1,9 +1,9 @@ package com.casic.detector.retrofit +import com.casic.detector.extensions.reformat import com.casic.detector.utils.LocaleConstant import com.google.gson.Gson import com.google.gson.JsonObject -import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType @@ -16,7 +16,6 @@ object RetrofitServiceManager { private val gson by lazy { Gson() } - private val typeToken = object : TypeToken>() {}.type private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String @@ -233,12 +232,13 @@ /** * 上传自由巡检过程中发现的标识器 */ - suspend fun uploadTaskMarker(taskId: String, models: List): String { + suspend fun uploadTaskMarker(taskId: String, models: ArrayList): String { val param = JsonObject() - param.add("markers", gson.toJsonTree(models, typeToken).asJsonArray) + param.addProperty("taskId", taskId) + param.addProperty("ids", models.reformat()) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return createApi().uploadTaskMarker(taskId, requestBody) + return createApi().uploadTaskMarker(requestBody) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt index 1c7d95b..7e627a4 100644 --- a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt @@ -105,7 +105,7 @@ fun queryTaskLabelByIdAndState(identifierId: String, state: String): TaskBean? { return taskBeanDao.queryBuilder() .where( - TaskBeanDao.Properties.MarkerRealId.eq(identifierId), + TaskBeanDao.Properties.MarkerId.eq(identifierId), TaskBeanDao.Properties.State.eq(state) ).list().firstOrNull() } diff --git a/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt b/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt new file mode 100644 index 0000000..c235471 --- /dev/null +++ b/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt @@ -0,0 +1,119 @@ +package com.casic.detector.utils + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.lifecycleScope +import com.casic.detector.base.BaseApplication +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.IOException + +class SerialPortManager(private val listener: OnSerialPortListener) : LifecycleOwner { + + private val kTag = "SerialPortManager" + private val registry = LifecycleRegistry(this) + + init { + //读取串口数据 + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + val buffer = ByteArray(72) + var size: Int + serialPorts?.forEach { + val stream = it.inputStream + while (true) { + try { + size = stream.read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + listener.onDataReceived(buffer) + } + } + } catch (e: IOException) { + e.printStackTrace() + return@launch + } + } + } + } + } + + /** + * 探测 + * */ + fun detectMarker() { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + while (size >= 1) { + val outStream = this[0].outputStream + try { + // 发送读标识器ID指令 + outStream?.write('2'.code) + outStream?.flush() + delay(100) + + outStream.write('6'.code) + outStream.flush() + delay(100) + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + } + + /** + * 发送探测深度指令 + * */ + fun detectDepth(markerTag: Char) { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + val outStream = this[0].outputStream + try { + // 发送测距指令 + outStream?.write(markerTag.code) + outStream?.flush() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + + /** + * 发送读标识器ID指令 + * */ + fun searchMarkerSignal() { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + val outStream = this[0].outputStream + try { + // 发送读标识器ID指令 + outStream?.write('2'.code) + outStream?.flush() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + + fun closeSerialPort() { + BaseApplication.get().closeSerialPort() + } + + interface OnSerialPortListener { + fun onDataReceived(buffer: ByteArray) + } + + override fun getLifecycle(): Lifecycle { + return registry + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/ArrayList.kt b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt new file mode 100644 index 0000000..52f8ac9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt @@ -0,0 +1,20 @@ +package com.casic.detector.extensions + +/** + * ArrayList扩展方法 + */ + +//将集合格式化成满足上传格式的数据 +fun ArrayList.reformat(): String { + if (this.isEmpty()) return "" + val builder = StringBuilder() + //循环遍历元素,同时得到元素index(下标) + this.forEachIndexed { index, s -> + if (index == this.size - 1) { + builder.append(s) + } else { + builder.append(s).append(",") + } + } + return builder.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index b76d83d..785b89f 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -122,4 +122,9 @@ } } return sb.toString() +} + +fun String.isNumber(): Boolean { + val regex = Regex("[-+]?\\d+(\\.\\d+)?") + return this.matches(regex) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java index cab23bb..682c3f8 100644 --- a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java +++ b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java @@ -13,20 +13,25 @@ // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + /** * Master of DAO (schema version 1): knows all DAOs. */ public class DaoMaster extends AbstractDaoMaster { public static final int SCHEMA_VERSION = 1; - /** Creates underlying database table using DAOs. */ + /** + * Creates underlying database table using DAOs. + */ public static void createAllTables(Database db, boolean ifNotExists) { LabelBeanDao.createTable(db, ifNotExists); SmallLabelBeanDao.createTable(db, ifNotExists); TaskBeanDao.createTable(db, ifNotExists); } - /** Drops underlying database table using DAOs. */ + /** + * Drops underlying database table using DAOs. + */ public static void dropAllTables(Database db, boolean ifExists) { LabelBeanDao.dropTable(db, ifExists); SmallLabelBeanDao.dropTable(db, ifExists); @@ -81,7 +86,9 @@ } } - /** WARNING: Drops all table on Upgrade! Use only during development. */ + /** + * WARNING: Drops all table on Upgrade! Use only during development. + */ public static class DevOpenHelper extends OpenHelper { public DevOpenHelper(Context context, String name) { super(context, name); diff --git a/app/src/main/java/com/casic/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/detector/model/CalculateResult.kt new file mode 100644 index 0000000..02cb0a0 --- /dev/null +++ b/app/src/main/java/com/casic/detector/model/CalculateResult.kt @@ -0,0 +1,3 @@ +package com.casic.detector.model + +data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 43a8484..cae51d5 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -82,25 +82,21 @@ */ @GET("/ems/rs/task/update-task-mark") suspend fun uploadMarker( - @Query("taskDetailId") taskId: String, + @Query("taskDetailId") taskId: String ): String /** * 新建自由巡检任务 * */ - @GET("") + @GET("ems/rs/task/addAppTask") suspend fun createFreeTask( @Query("patrollerId") patrollerId: String, - @Query("description") description: String, + @Query("description") description: String ): String /** * 上传自由巡检过程中发现的标识器 * */ - @Multipart - @POST("") - suspend fun uploadTaskMarker( - @Field("taskId") taskId: String, - @Body requestBody: RequestBody, - ): String + @POST("ems/event/uploadAppMarker.do") + suspend fun uploadTaskMarker(@Body requestBody: RequestBody): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 8ae0794..ac06760 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -1,9 +1,9 @@ package com.casic.detector.retrofit +import com.casic.detector.extensions.reformat import com.casic.detector.utils.LocaleConstant import com.google.gson.Gson import com.google.gson.JsonObject -import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType @@ -16,7 +16,6 @@ object RetrofitServiceManager { private val gson by lazy { Gson() } - private val typeToken = object : TypeToken>() {}.type private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String @@ -233,12 +232,13 @@ /** * 上传自由巡检过程中发现的标识器 */ - suspend fun uploadTaskMarker(taskId: String, models: List): String { + suspend fun uploadTaskMarker(taskId: String, models: ArrayList): String { val param = JsonObject() - param.add("markers", gson.toJsonTree(models, typeToken).asJsonArray) + param.addProperty("taskId", taskId) + param.addProperty("ids", models.reformat()) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return createApi().uploadTaskMarker(taskId, requestBody) + return createApi().uploadTaskMarker(requestBody) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt index 1c7d95b..7e627a4 100644 --- a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt @@ -105,7 +105,7 @@ fun queryTaskLabelByIdAndState(identifierId: String, state: String): TaskBean? { return taskBeanDao.queryBuilder() .where( - TaskBeanDao.Properties.MarkerRealId.eq(identifierId), + TaskBeanDao.Properties.MarkerId.eq(identifierId), TaskBeanDao.Properties.State.eq(state) ).list().firstOrNull() } diff --git a/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt b/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt new file mode 100644 index 0000000..c235471 --- /dev/null +++ b/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt @@ -0,0 +1,119 @@ +package com.casic.detector.utils + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.lifecycleScope +import com.casic.detector.base.BaseApplication +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.IOException + +class SerialPortManager(private val listener: OnSerialPortListener) : LifecycleOwner { + + private val kTag = "SerialPortManager" + private val registry = LifecycleRegistry(this) + + init { + //读取串口数据 + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + val buffer = ByteArray(72) + var size: Int + serialPorts?.forEach { + val stream = it.inputStream + while (true) { + try { + size = stream.read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + listener.onDataReceived(buffer) + } + } + } catch (e: IOException) { + e.printStackTrace() + return@launch + } + } + } + } + } + + /** + * 探测 + * */ + fun detectMarker() { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + while (size >= 1) { + val outStream = this[0].outputStream + try { + // 发送读标识器ID指令 + outStream?.write('2'.code) + outStream?.flush() + delay(100) + + outStream.write('6'.code) + outStream.flush() + delay(100) + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + } + + /** + * 发送探测深度指令 + * */ + fun detectDepth(markerTag: Char) { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + val outStream = this[0].outputStream + try { + // 发送测距指令 + outStream?.write(markerTag.code) + outStream?.flush() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + + /** + * 发送读标识器ID指令 + * */ + fun searchMarkerSignal() { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + val outStream = this[0].outputStream + try { + // 发送读标识器ID指令 + outStream?.write('2'.code) + outStream?.flush() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + + fun closeSerialPort() { + BaseApplication.get().closeSerialPort() + } + + interface OnSerialPortListener { + fun onDataReceived(buffer: ByteArray) + } + + override fun getLifecycle(): Lifecycle { + return registry + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index 68d54b2..5bac324 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -2,16 +2,12 @@ import android.annotation.SuppressLint import android.app.DatePickerDialog -import android.content.Context import android.content.DialogInterface import android.content.Intent import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle -import android.os.Handler -import android.os.Message import android.provider.Settings -import android.util.Log import android.view.KeyEvent import android.view.View import android.view.WindowManager @@ -19,7 +15,6 @@ import com.amap.api.location.AMapLocation import com.casic.detector.R import com.casic.detector.adapter.EditableImageAdapter -import com.casic.detector.base.SerialPortActivity import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener @@ -31,29 +26,39 @@ 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.* +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.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.LoadState import com.pengxh.kt.lite.utils.SaveKeyValues -import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import java.io.File -import java.io.IOException import java.util.* @SuppressLint("SetTextI18n") -class InstallLabelActivity : SerialPortActivity(), Handler.Callback { +class InstallLabelActivity : KotlinBaseActivity(), + SerialPortManager.OnSerialPortListener { private val kTag = "InstallLabelActivity" - private val context: Context = this@InstallLabelActivity + private val context = this@InstallLabelActivity + private val serialPortManager by lazy { SerialPortManager(this) } private val calendar by lazy { Calendar.getInstance() } - private lateinit var imageAdapter: EditableImageAdapter - private val realPaths: ArrayList = ArrayList() //真实图片路径 - private lateinit var taskViewModel: TaskViewModel - private lateinit var soundPool: SoundPool - private var soundResId = 0 - private val gpioManager by lazy { GpioManager() } + private val audioAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ALARM) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + private val realPaths = ArrayList() //真实图片路径 private val locationHub by lazy { LocationHub(this) } - private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var imageAdapter: EditableImageAdapter + private lateinit var taskViewModel: TaskViewModel + private var soundPool: SoundPool? = null override fun initViewBinding(): ActivityInstallLabelBinding { return ActivityInstallLabelBinding.inflate(layoutInflater) @@ -79,13 +84,6 @@ binding.objectInclude.ownerView.setText("ownerView".getDefaultValue()) binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue()) binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue()) - - weakReferenceHandler = WeakReferenceHandler(this) - - val audioAttributes = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA) - .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() - soundPool = - SoundPool.Builder().setMaxStreams(16).setAudioAttributes(audioAttributes).build() } override fun initEvent() { @@ -247,6 +245,14 @@ return@setOnClickListener } + //查本地库 + val markerId = binding.identifierInclude.identifierIdView.text.toString() + val result = DataBaseManager.get.queryLabelById(markerId) + if (result.isEmpty()) { + "".show(this) + return@setOnClickListener + } + //先存本地再上传服务器 saveLabelInLocal() @@ -268,7 +274,7 @@ binding.objectInclude.constructDateView.text.toString(), binding.objectInclude.ownerView.text.toString(), objectId, - binding.identifierInclude.identifierIdView.text.toString(), + markerId, binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(), "${binding.identifierInclude.identifierDeepView.text}mm", binding.identifierInclude.personDeptView.text.toString(), @@ -305,25 +311,35 @@ } binding.readLabelButton.setOnClickListener { - gpioManager.setGpioHigh("18") - LoadingDialogHub.show(this, "标识器读取中,请稍后...") - soundResId = soundPool.load(this, R.raw.ring3, 1) - soundPool.setOnLoadCompleteListener { soundPool, _, _ -> - soundPool.play(soundResId, 1f, 1f, 0, -1, 1f) + soundPool = SoundPool.Builder() + .setMaxStreams(16) + .setAudioAttributes(audioAttributes) + .build() + soundPool?.apply { + val soundResId = load(context, R.raw.ring3, 1) + setOnLoadCompleteListener { soundPool, _, _ -> + soundPool.play(soundResId, 1f, 1f, 0, -1, 1f) + } } - // 1000ms后发送读标识器或搜索信号 - weakReferenceHandler.postDelayed({ - try { - // 发送读标识器或搜索信号 - outStream?.write("2".toByteArray()) - outStream?.flush() - } catch (e: IOException) { - e.printStackTrace() - } - }, 1000) + serialPortManager.searchMarkerSignal() + } + } + + override fun onDataReceived(buffer: ByteArray) { + LoadingDialogHub.dismiss() + soundPool?.release() + + val hex = buffer.toHex() +// Log.d(kTag, "$kTag => $hex") + if (hex.length >= 20) { + val markerId = hex.take(20).hexToString() + if (markerId.isNumber()) { + binding.identifierInclude.identifierIdView.text = markerId + serialPortManager.closeSerialPort() + } } } @@ -363,41 +379,6 @@ DataBaseManager.get.insertTaskLabel(labelBean) } - override fun onDataReceived(buffer: ByteArray?, size: Int) { - Log.d(kTag, "onDataReceived => " + buffer.contentToString()) - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023061601 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } - } - - override fun handleMessage(msg: Message): Boolean { - if (msg.what == 2023061601) { - soundPool.release() - - val buffer = msg.obj as ByteArray - val hex = buffer.toHex() - //3030303839383735313400000000000000000000000000000000000000000000 - if (hex.length >= 20) { - val identifierId = hex.substring(0, 20).hexToString() - - gpioManager.setGpioLow("18") - - //查本地库 - val result = DataBaseManager.get.queryLabelById(identifierId) - if (result.isEmpty()) { - binding.identifierInclude.identifierIdView.text = identifierId - } else { - "此标识器已安装,请更换标识器!".show(this) - } - LoadingDialogHub.dismiss() - } - } - return true - } - private fun takePicture() { PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) .forResult(object : OnResultCallbackListener { @@ -451,14 +432,14 @@ } override fun onDestroy() { - soundPool.release() - gpioManager.setGpioLow("18") super.onDestroy() + soundPool?.release() + locationHub.stopLocation() } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { if (keyCode == KeyEvent.KEYCODE_BACK) { - soundPool.release() + soundPool?.release() } return super.onKeyDown(keyCode, event) } diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/ArrayList.kt b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt new file mode 100644 index 0000000..52f8ac9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt @@ -0,0 +1,20 @@ +package com.casic.detector.extensions + +/** + * ArrayList扩展方法 + */ + +//将集合格式化成满足上传格式的数据 +fun ArrayList.reformat(): String { + if (this.isEmpty()) return "" + val builder = StringBuilder() + //循环遍历元素,同时得到元素index(下标) + this.forEachIndexed { index, s -> + if (index == this.size - 1) { + builder.append(s) + } else { + builder.append(s).append(",") + } + } + return builder.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index b76d83d..785b89f 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -122,4 +122,9 @@ } } return sb.toString() +} + +fun String.isNumber(): Boolean { + val regex = Regex("[-+]?\\d+(\\.\\d+)?") + return this.matches(regex) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java index cab23bb..682c3f8 100644 --- a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java +++ b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java @@ -13,20 +13,25 @@ // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + /** * Master of DAO (schema version 1): knows all DAOs. */ public class DaoMaster extends AbstractDaoMaster { public static final int SCHEMA_VERSION = 1; - /** Creates underlying database table using DAOs. */ + /** + * Creates underlying database table using DAOs. + */ public static void createAllTables(Database db, boolean ifNotExists) { LabelBeanDao.createTable(db, ifNotExists); SmallLabelBeanDao.createTable(db, ifNotExists); TaskBeanDao.createTable(db, ifNotExists); } - /** Drops underlying database table using DAOs. */ + /** + * Drops underlying database table using DAOs. + */ public static void dropAllTables(Database db, boolean ifExists) { LabelBeanDao.dropTable(db, ifExists); SmallLabelBeanDao.dropTable(db, ifExists); @@ -81,7 +86,9 @@ } } - /** WARNING: Drops all table on Upgrade! Use only during development. */ + /** + * WARNING: Drops all table on Upgrade! Use only during development. + */ public static class DevOpenHelper extends OpenHelper { public DevOpenHelper(Context context, String name) { super(context, name); diff --git a/app/src/main/java/com/casic/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/detector/model/CalculateResult.kt new file mode 100644 index 0000000..02cb0a0 --- /dev/null +++ b/app/src/main/java/com/casic/detector/model/CalculateResult.kt @@ -0,0 +1,3 @@ +package com.casic.detector.model + +data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 43a8484..cae51d5 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -82,25 +82,21 @@ */ @GET("/ems/rs/task/update-task-mark") suspend fun uploadMarker( - @Query("taskDetailId") taskId: String, + @Query("taskDetailId") taskId: String ): String /** * 新建自由巡检任务 * */ - @GET("") + @GET("ems/rs/task/addAppTask") suspend fun createFreeTask( @Query("patrollerId") patrollerId: String, - @Query("description") description: String, + @Query("description") description: String ): String /** * 上传自由巡检过程中发现的标识器 * */ - @Multipart - @POST("") - suspend fun uploadTaskMarker( - @Field("taskId") taskId: String, - @Body requestBody: RequestBody, - ): String + @POST("ems/event/uploadAppMarker.do") + suspend fun uploadTaskMarker(@Body requestBody: RequestBody): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 8ae0794..ac06760 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -1,9 +1,9 @@ package com.casic.detector.retrofit +import com.casic.detector.extensions.reformat import com.casic.detector.utils.LocaleConstant import com.google.gson.Gson import com.google.gson.JsonObject -import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType @@ -16,7 +16,6 @@ object RetrofitServiceManager { private val gson by lazy { Gson() } - private val typeToken = object : TypeToken>() {}.type private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String @@ -233,12 +232,13 @@ /** * 上传自由巡检过程中发现的标识器 */ - suspend fun uploadTaskMarker(taskId: String, models: List): String { + suspend fun uploadTaskMarker(taskId: String, models: ArrayList): String { val param = JsonObject() - param.add("markers", gson.toJsonTree(models, typeToken).asJsonArray) + param.addProperty("taskId", taskId) + param.addProperty("ids", models.reformat()) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return createApi().uploadTaskMarker(taskId, requestBody) + return createApi().uploadTaskMarker(requestBody) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt index 1c7d95b..7e627a4 100644 --- a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt @@ -105,7 +105,7 @@ fun queryTaskLabelByIdAndState(identifierId: String, state: String): TaskBean? { return taskBeanDao.queryBuilder() .where( - TaskBeanDao.Properties.MarkerRealId.eq(identifierId), + TaskBeanDao.Properties.MarkerId.eq(identifierId), TaskBeanDao.Properties.State.eq(state) ).list().firstOrNull() } diff --git a/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt b/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt new file mode 100644 index 0000000..c235471 --- /dev/null +++ b/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt @@ -0,0 +1,119 @@ +package com.casic.detector.utils + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.lifecycleScope +import com.casic.detector.base.BaseApplication +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.IOException + +class SerialPortManager(private val listener: OnSerialPortListener) : LifecycleOwner { + + private val kTag = "SerialPortManager" + private val registry = LifecycleRegistry(this) + + init { + //读取串口数据 + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + val buffer = ByteArray(72) + var size: Int + serialPorts?.forEach { + val stream = it.inputStream + while (true) { + try { + size = stream.read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + listener.onDataReceived(buffer) + } + } + } catch (e: IOException) { + e.printStackTrace() + return@launch + } + } + } + } + } + + /** + * 探测 + * */ + fun detectMarker() { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + while (size >= 1) { + val outStream = this[0].outputStream + try { + // 发送读标识器ID指令 + outStream?.write('2'.code) + outStream?.flush() + delay(100) + + outStream.write('6'.code) + outStream.flush() + delay(100) + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + } + + /** + * 发送探测深度指令 + * */ + fun detectDepth(markerTag: Char) { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + val outStream = this[0].outputStream + try { + // 发送测距指令 + outStream?.write(markerTag.code) + outStream?.flush() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + + /** + * 发送读标识器ID指令 + * */ + fun searchMarkerSignal() { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + val outStream = this[0].outputStream + try { + // 发送读标识器ID指令 + outStream?.write('2'.code) + outStream?.flush() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + + fun closeSerialPort() { + BaseApplication.get().closeSerialPort() + } + + interface OnSerialPortListener { + fun onDataReceived(buffer: ByteArray) + } + + override fun getLifecycle(): Lifecycle { + return registry + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index 68d54b2..5bac324 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -2,16 +2,12 @@ import android.annotation.SuppressLint import android.app.DatePickerDialog -import android.content.Context import android.content.DialogInterface import android.content.Intent import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle -import android.os.Handler -import android.os.Message import android.provider.Settings -import android.util.Log import android.view.KeyEvent import android.view.View import android.view.WindowManager @@ -19,7 +15,6 @@ import com.amap.api.location.AMapLocation import com.casic.detector.R import com.casic.detector.adapter.EditableImageAdapter -import com.casic.detector.base.SerialPortActivity import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener @@ -31,29 +26,39 @@ 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.* +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.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.LoadState import com.pengxh.kt.lite.utils.SaveKeyValues -import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import java.io.File -import java.io.IOException import java.util.* @SuppressLint("SetTextI18n") -class InstallLabelActivity : SerialPortActivity(), Handler.Callback { +class InstallLabelActivity : KotlinBaseActivity(), + SerialPortManager.OnSerialPortListener { private val kTag = "InstallLabelActivity" - private val context: Context = this@InstallLabelActivity + private val context = this@InstallLabelActivity + private val serialPortManager by lazy { SerialPortManager(this) } private val calendar by lazy { Calendar.getInstance() } - private lateinit var imageAdapter: EditableImageAdapter - private val realPaths: ArrayList = ArrayList() //真实图片路径 - private lateinit var taskViewModel: TaskViewModel - private lateinit var soundPool: SoundPool - private var soundResId = 0 - private val gpioManager by lazy { GpioManager() } + private val audioAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ALARM) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + private val realPaths = ArrayList() //真实图片路径 private val locationHub by lazy { LocationHub(this) } - private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var imageAdapter: EditableImageAdapter + private lateinit var taskViewModel: TaskViewModel + private var soundPool: SoundPool? = null override fun initViewBinding(): ActivityInstallLabelBinding { return ActivityInstallLabelBinding.inflate(layoutInflater) @@ -79,13 +84,6 @@ binding.objectInclude.ownerView.setText("ownerView".getDefaultValue()) binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue()) binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue()) - - weakReferenceHandler = WeakReferenceHandler(this) - - val audioAttributes = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA) - .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() - soundPool = - SoundPool.Builder().setMaxStreams(16).setAudioAttributes(audioAttributes).build() } override fun initEvent() { @@ -247,6 +245,14 @@ return@setOnClickListener } + //查本地库 + val markerId = binding.identifierInclude.identifierIdView.text.toString() + val result = DataBaseManager.get.queryLabelById(markerId) + if (result.isEmpty()) { + "".show(this) + return@setOnClickListener + } + //先存本地再上传服务器 saveLabelInLocal() @@ -268,7 +274,7 @@ binding.objectInclude.constructDateView.text.toString(), binding.objectInclude.ownerView.text.toString(), objectId, - binding.identifierInclude.identifierIdView.text.toString(), + markerId, binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(), "${binding.identifierInclude.identifierDeepView.text}mm", binding.identifierInclude.personDeptView.text.toString(), @@ -305,25 +311,35 @@ } binding.readLabelButton.setOnClickListener { - gpioManager.setGpioHigh("18") - LoadingDialogHub.show(this, "标识器读取中,请稍后...") - soundResId = soundPool.load(this, R.raw.ring3, 1) - soundPool.setOnLoadCompleteListener { soundPool, _, _ -> - soundPool.play(soundResId, 1f, 1f, 0, -1, 1f) + soundPool = SoundPool.Builder() + .setMaxStreams(16) + .setAudioAttributes(audioAttributes) + .build() + soundPool?.apply { + val soundResId = load(context, R.raw.ring3, 1) + setOnLoadCompleteListener { soundPool, _, _ -> + soundPool.play(soundResId, 1f, 1f, 0, -1, 1f) + } } - // 1000ms后发送读标识器或搜索信号 - weakReferenceHandler.postDelayed({ - try { - // 发送读标识器或搜索信号 - outStream?.write("2".toByteArray()) - outStream?.flush() - } catch (e: IOException) { - e.printStackTrace() - } - }, 1000) + serialPortManager.searchMarkerSignal() + } + } + + override fun onDataReceived(buffer: ByteArray) { + LoadingDialogHub.dismiss() + soundPool?.release() + + val hex = buffer.toHex() +// Log.d(kTag, "$kTag => $hex") + if (hex.length >= 20) { + val markerId = hex.take(20).hexToString() + if (markerId.isNumber()) { + binding.identifierInclude.identifierIdView.text = markerId + serialPortManager.closeSerialPort() + } } } @@ -363,41 +379,6 @@ DataBaseManager.get.insertTaskLabel(labelBean) } - override fun onDataReceived(buffer: ByteArray?, size: Int) { - Log.d(kTag, "onDataReceived => " + buffer.contentToString()) - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023061601 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } - } - - override fun handleMessage(msg: Message): Boolean { - if (msg.what == 2023061601) { - soundPool.release() - - val buffer = msg.obj as ByteArray - val hex = buffer.toHex() - //3030303839383735313400000000000000000000000000000000000000000000 - if (hex.length >= 20) { - val identifierId = hex.substring(0, 20).hexToString() - - gpioManager.setGpioLow("18") - - //查本地库 - val result = DataBaseManager.get.queryLabelById(identifierId) - if (result.isEmpty()) { - binding.identifierInclude.identifierIdView.text = identifierId - } else { - "此标识器已安装,请更换标识器!".show(this) - } - LoadingDialogHub.dismiss() - } - } - return true - } - private fun takePicture() { PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) .forResult(object : OnResultCallbackListener { @@ -451,14 +432,14 @@ } override fun onDestroy() { - soundPool.release() - gpioManager.setGpioLow("18") super.onDestroy() + soundPool?.release() + locationHub.stopLocation() } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { if (keyCode == KeyEvent.KEYCODE_BACK) { - soundPool.release() + soundPool?.release() } return super.onKeyDown(keyCode, event) } diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index d590626..7c6446a 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -1,17 +1,19 @@ package com.casic.detector.view -import android.content.Context import android.content.Intent import android.graphics.BitmapFactory import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.media.AudioAttributes +import android.media.SoundPool import android.os.Bundle -import android.os.PowerManager import android.provider.Settings import android.util.Log import android.view.KeyEvent +import android.view.View 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 @@ -32,81 +34,89 @@ import com.casic.detector.databinding.ActivityMainBinding import com.casic.detector.extensions.appendDownloadUrl import com.casic.detector.extensions.drawCircle -import com.casic.detector.extensions.initLayoutImmersionBar +import com.casic.detector.extensions.hexToString +import com.casic.detector.extensions.initImmersionBar +import com.casic.detector.extensions.isNumber +import com.casic.detector.extensions.toHex import com.casic.detector.model.TaskModel import com.casic.detector.utils.DataBaseManager import com.casic.detector.utils.ExcelHub import com.casic.detector.utils.FileType +import com.casic.detector.utils.GpioManager import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub import com.casic.detector.utils.RouteOnMap +import com.casic.detector.utils.SerialPortManager import com.casic.detector.vm.TaskViewModel import com.casic.detector.widgets.QueryMarkerDialog import com.casic.detector.widgets.SamplePopupWindow import com.google.gson.Gson import com.google.gson.reflect.TypeToken -import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.callback.OnDownloadListener +import com.pengxh.kt.lite.extensions.convertDrawable import com.pengxh.kt.lite.extensions.createDownloadFileDir -import com.pengxh.kt.lite.extensions.downloadFile import com.pengxh.kt.lite.extensions.dp2px 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.toJson +import com.pengxh.kt.lite.utils.FileDownloadManager +import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.SaveKeyValues -import com.pengxh.kt.lite.vm.LoadState import com.pengxh.kt.lite.widget.dialog.AlertControlDialog +import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog import com.pengxh.kt.lite.widget.dialog.BottomActionSheet import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File -class MainActivity : KotlinBaseActivity() { +class MainActivity : KotlinBaseActivity(), + SerialPortManager.OnSerialPortListener { private val kTag = "MainActivity" - private val context: Context = this@MainActivity - private var clickTime: Long = 0 - private lateinit var aMap: AMap - private lateinit var taskViewModel: TaskViewModel + private val context = this@MainActivity + private val serialPortManager by lazy { SerialPortManager(this) } + private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } + private val gson by lazy { Gson() } + private val locationHub by lazy { LocationHub(this) } + private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } + private val backDrawables by lazy { HashMap() } + private val audioAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ALARM) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + private var clickTime: Long = 0 private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null - private val backDrawables = HashMap() - private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private var latitude: Double = 0.0 private var longitude: Double = 0.0 - private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub.obtainInstance(this) } - private lateinit var wakeLock: PowerManager.WakeLock + private var ids = ArrayList() + private lateinit var aMap: AMap + private lateinit var soundPool: SoundPool + private lateinit var taskViewModel: TaskViewModel private lateinit var taskBean: TaskBean + private lateinit var taskId: String override fun initViewBinding(): ActivityMainBinding { return ActivityMainBinding.inflate(layoutInflater) } override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).statusBarColor(R.color.themeColor).init() - initLayoutImmersionBar(binding.rootView) + binding.rootView.initImmersionBar(this, false, R.color.themeColor) } override fun initOnCreate(savedInstanceState: Bundle?) { - val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager - wakeLock = powerManager.run { - newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this@MainActivity.localClassName).apply { - acquire(60 * 60 * 1000L) - } - } - initMapConfig(savedInstanceState) + //调高串口电位 + gpioManager.setGpioHigh("18") + samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -119,12 +129,14 @@ val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) Log.d(kTag, "downloadUrl => $downloadUrl") - downloadUrl.downloadFile( - createDownloadFileDir().toString(), - object : OnDownloadListener { - override fun onDownloadEnd(file: File?) { - CoroutineScope(Dispatchers.Main).launch { - labelBeans = ExcelHub.read(file?.absolutePath) + FileDownloadManager.Builder() + .setDownloadFileSource(downloadUrl) + .setFileSuffix("xls") + .setFileSaveDirectory(createDownloadFileDir()) + .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadEnd(file: File) { + lifecycleScope.launch(Dispatchers.Main) { + labelBeans = ExcelHub.read(file.absolutePath) withContext(Dispatchers.IO) { labelBeans.forEach { label -> DataBaseManager.get.insertTaskLabel(label) @@ -135,14 +147,16 @@ } } - override fun onDownloadStart(totalBytes: Long) { + override fun onFailure(throwable: Throwable) { } - override fun onProgressChanged(currentBytes: Long) { + override fun onProgressChanged(progress: Int) { } }) + .build() + .start() } } taskViewModel.taskResult.observe(this) { @@ -159,19 +173,26 @@ }).build().show() } } + + taskViewModel.freeTaskResult.observe(this) { taskId = it } + + taskViewModel.uploadTaskMarkerResult.observe(this) { + "自由巡检任务已完成".show(this) + ids.clear() + } } override fun initEvent() { binding.rightImageView.setOnClickListener { - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { val labels = withContext(Dispatchers.IO) { DataBaseManager.get.queryLabelById("0") } if (labels.isNotEmpty()) { samplePopupWindow.setShowPosition(4) } - val x = binding.rightImageView.width - samplePopupWindow.width - 1f.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1f.dp2px(context)) + val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -201,7 +222,7 @@ QueryMarkerDialog.OnDialogButtonClickListener { override fun onConfirmClick(selectedItem: String, value: String) { //查询数据库 - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabelByCondition( selectedItem, value @@ -282,12 +303,14 @@ } }).build().show() } else { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") - .setMessage("现有任务已完成,请点击右上角菜单按钮下载新工单!") - .setPositiveButton("知道了").setOnDialogButtonClickListener(object : + AlertMessageDialog.Builder() + .setContext(this) + .setTitle("温馨提示") + .setMessage("现有任务已完成,请点击右上角菜单下载新工单或者开始自由巡检") + .setPositiveButton("开始自由巡检").setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { override fun onConfirmClick() { - + startFreeTask() } }).build().show() } @@ -297,6 +320,69 @@ binding.detectionButton.setOnClickListener { navigatePageTo() } + + //自由巡检 + binding.stopFreeTaskButton.setOnLongClickListener { + AlertMessageDialog.Builder() + .setContext(this) + .setTitle("温馨提示") + .setMessage("是否确定结束此次自由巡检任务?") + .setPositiveButton("是") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + soundPool.release() + serialPortManager.closeSerialPort() + + taskViewModel.uploadTaskMarker(taskId, ids) + binding.stopFreeTaskButton.visibility = View.GONE + } + }).build().show() + true + } + } + + private fun startFreeTask() { + AlertInputDialog.Builder() + .setContext(this) + .setTitle("新建自由巡检任务") + .setHintMessage("请输入自由巡检任务简要描述") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { + override fun onConfirmClick(value: String) { + val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String + taskViewModel.createFreeTask(userId, value) + + soundPool = SoundPool.Builder() + .setMaxStreams(16) + .setAudioAttributes(audioAttributes) + .build() + soundPool.load(context, R.raw.ring3, 1) + soundPool.setOnLoadCompleteListener { soundPool, sampleId, _ -> + soundPool.play(sampleId, 1f, 1f, 0, -1, 1f) + } + + //自由巡检 + serialPortManager.searchMarkerSignal() + + binding.stopFreeTaskButton.visibility = View.VISIBLE + } + + override fun onCancelClick() {} + }).build().show() + } + + override fun onDataReceived(buffer: ByteArray) { + val hex = buffer.toHex() +// Log.d(kTag, "$kTag => $hex") + if (hex.length >= 20) { + val markerId = hex.take(20).hexToString() + if (markerId.isNumber()) { + "标识器${markerId}已探测".show(this) + ids.add(markerId) + } + } } override fun observeRequestState() { @@ -342,7 +428,7 @@ aMap.setOnMapLongClickListener { //协程异步显示默认数据 - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadTaskLabels() as ArrayList } @@ -381,7 +467,7 @@ userName, messageModel.description, info.taskId.toString(), - info.taskCode.toString(), + info.id.toString(), info.markerId.toString(), info.markerIdReal.toString(), info.longitude.toString(), @@ -412,7 +498,7 @@ clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) clusterOverlay?.setClusterRender { clusterNum -> - val radius = 80f.dp2px(context) + val radius = 80.dp2px(context) if (clusterNum == 0) { var bitmapDrawable = backDrawables[0] if (bitmapDrawable == null) { @@ -426,7 +512,7 @@ if (clusterNum == 1) { var bitmapDrawable = backDrawables[1] if (bitmapDrawable == null) { - bitmapDrawable = resources.getDrawable(R.mipmap.label) + bitmapDrawable = R.mipmap.label.convertDrawable(this)!! backDrawables[1] = bitmapDrawable } bitmapDrawable @@ -478,9 +564,13 @@ val latLngBounds = builder.build() aMap.animateCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds, 0)) - AlertControlDialog.Builder().setContext(this).setTitle("提示") - .setMessage("请选择操作方式").setNegativeButton("标识器信息") - .setPositiveButton("到这里去").setOnDialogButtonClickListener(object : + AlertControlDialog.Builder() + .setContext(this) + .setTitle("提示") + .setMessage("请选择操作方式") + .setNegativeButton("标识器信息") + .setPositiveButton("到这里去") + .setOnDialogButtonClickListener(object : AlertControlDialog.OnDialogButtonClickListener { override fun onConfirmClick() { RouteOnMap.startNavigation(context, item.title, latLng) @@ -510,13 +600,13 @@ BitmapDescriptorFactory.fromBitmap( BitmapFactory.decodeResource(resources, R.mipmap.label_red1) ) - ).period(99).title("工单标识器").snippet(it.markerRealId) + ).period(99).title("工单标识器").snippet(it.markerId) } else { otMarkerOptions.icon( BitmapDescriptorFactory.fromBitmap( BitmapFactory.decodeResource(resources, R.mipmap.label_blue1) ) - ).period(99).title("工单标识器").snippet(it.markerRealId) + ).period(99).title("工单标识器").snippet(it.markerId) } aMap.addMarker(otMarkerOptions) } @@ -665,7 +755,7 @@ super.onResume() binding.mapView.onResume() //协程异步显示默认数据 - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadTaskLabels() as ArrayList } @@ -684,8 +774,10 @@ } override fun onDestroy() { - wakeLock.release() super.onDestroy() binding.mapView.onDestroy() + locationHub.stopLocation() + //降低串口电位 + gpioManager.setGpioLow("18") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/ArrayList.kt b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt new file mode 100644 index 0000000..52f8ac9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt @@ -0,0 +1,20 @@ +package com.casic.detector.extensions + +/** + * ArrayList扩展方法 + */ + +//将集合格式化成满足上传格式的数据 +fun ArrayList.reformat(): String { + if (this.isEmpty()) return "" + val builder = StringBuilder() + //循环遍历元素,同时得到元素index(下标) + this.forEachIndexed { index, s -> + if (index == this.size - 1) { + builder.append(s) + } else { + builder.append(s).append(",") + } + } + return builder.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index b76d83d..785b89f 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -122,4 +122,9 @@ } } return sb.toString() +} + +fun String.isNumber(): Boolean { + val regex = Regex("[-+]?\\d+(\\.\\d+)?") + return this.matches(regex) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java index cab23bb..682c3f8 100644 --- a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java +++ b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java @@ -13,20 +13,25 @@ // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + /** * Master of DAO (schema version 1): knows all DAOs. */ public class DaoMaster extends AbstractDaoMaster { public static final int SCHEMA_VERSION = 1; - /** Creates underlying database table using DAOs. */ + /** + * Creates underlying database table using DAOs. + */ public static void createAllTables(Database db, boolean ifNotExists) { LabelBeanDao.createTable(db, ifNotExists); SmallLabelBeanDao.createTable(db, ifNotExists); TaskBeanDao.createTable(db, ifNotExists); } - /** Drops underlying database table using DAOs. */ + /** + * Drops underlying database table using DAOs. + */ public static void dropAllTables(Database db, boolean ifExists) { LabelBeanDao.dropTable(db, ifExists); SmallLabelBeanDao.dropTable(db, ifExists); @@ -81,7 +86,9 @@ } } - /** WARNING: Drops all table on Upgrade! Use only during development. */ + /** + * WARNING: Drops all table on Upgrade! Use only during development. + */ public static class DevOpenHelper extends OpenHelper { public DevOpenHelper(Context context, String name) { super(context, name); diff --git a/app/src/main/java/com/casic/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/detector/model/CalculateResult.kt new file mode 100644 index 0000000..02cb0a0 --- /dev/null +++ b/app/src/main/java/com/casic/detector/model/CalculateResult.kt @@ -0,0 +1,3 @@ +package com.casic.detector.model + +data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 43a8484..cae51d5 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -82,25 +82,21 @@ */ @GET("/ems/rs/task/update-task-mark") suspend fun uploadMarker( - @Query("taskDetailId") taskId: String, + @Query("taskDetailId") taskId: String ): String /** * 新建自由巡检任务 * */ - @GET("") + @GET("ems/rs/task/addAppTask") suspend fun createFreeTask( @Query("patrollerId") patrollerId: String, - @Query("description") description: String, + @Query("description") description: String ): String /** * 上传自由巡检过程中发现的标识器 * */ - @Multipart - @POST("") - suspend fun uploadTaskMarker( - @Field("taskId") taskId: String, - @Body requestBody: RequestBody, - ): String + @POST("ems/event/uploadAppMarker.do") + suspend fun uploadTaskMarker(@Body requestBody: RequestBody): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 8ae0794..ac06760 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -1,9 +1,9 @@ package com.casic.detector.retrofit +import com.casic.detector.extensions.reformat import com.casic.detector.utils.LocaleConstant import com.google.gson.Gson import com.google.gson.JsonObject -import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType @@ -16,7 +16,6 @@ object RetrofitServiceManager { private val gson by lazy { Gson() } - private val typeToken = object : TypeToken>() {}.type private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String @@ -233,12 +232,13 @@ /** * 上传自由巡检过程中发现的标识器 */ - suspend fun uploadTaskMarker(taskId: String, models: List): String { + suspend fun uploadTaskMarker(taskId: String, models: ArrayList): String { val param = JsonObject() - param.add("markers", gson.toJsonTree(models, typeToken).asJsonArray) + param.addProperty("taskId", taskId) + param.addProperty("ids", models.reformat()) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return createApi().uploadTaskMarker(taskId, requestBody) + return createApi().uploadTaskMarker(requestBody) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt index 1c7d95b..7e627a4 100644 --- a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt @@ -105,7 +105,7 @@ fun queryTaskLabelByIdAndState(identifierId: String, state: String): TaskBean? { return taskBeanDao.queryBuilder() .where( - TaskBeanDao.Properties.MarkerRealId.eq(identifierId), + TaskBeanDao.Properties.MarkerId.eq(identifierId), TaskBeanDao.Properties.State.eq(state) ).list().firstOrNull() } diff --git a/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt b/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt new file mode 100644 index 0000000..c235471 --- /dev/null +++ b/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt @@ -0,0 +1,119 @@ +package com.casic.detector.utils + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.lifecycleScope +import com.casic.detector.base.BaseApplication +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.IOException + +class SerialPortManager(private val listener: OnSerialPortListener) : LifecycleOwner { + + private val kTag = "SerialPortManager" + private val registry = LifecycleRegistry(this) + + init { + //读取串口数据 + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + val buffer = ByteArray(72) + var size: Int + serialPorts?.forEach { + val stream = it.inputStream + while (true) { + try { + size = stream.read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + listener.onDataReceived(buffer) + } + } + } catch (e: IOException) { + e.printStackTrace() + return@launch + } + } + } + } + } + + /** + * 探测 + * */ + fun detectMarker() { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + while (size >= 1) { + val outStream = this[0].outputStream + try { + // 发送读标识器ID指令 + outStream?.write('2'.code) + outStream?.flush() + delay(100) + + outStream.write('6'.code) + outStream.flush() + delay(100) + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + } + + /** + * 发送探测深度指令 + * */ + fun detectDepth(markerTag: Char) { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + val outStream = this[0].outputStream + try { + // 发送测距指令 + outStream?.write(markerTag.code) + outStream?.flush() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + + /** + * 发送读标识器ID指令 + * */ + fun searchMarkerSignal() { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + val outStream = this[0].outputStream + try { + // 发送读标识器ID指令 + outStream?.write('2'.code) + outStream?.flush() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + + fun closeSerialPort() { + BaseApplication.get().closeSerialPort() + } + + interface OnSerialPortListener { + fun onDataReceived(buffer: ByteArray) + } + + override fun getLifecycle(): Lifecycle { + return registry + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index 68d54b2..5bac324 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -2,16 +2,12 @@ import android.annotation.SuppressLint import android.app.DatePickerDialog -import android.content.Context import android.content.DialogInterface import android.content.Intent import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle -import android.os.Handler -import android.os.Message import android.provider.Settings -import android.util.Log import android.view.KeyEvent import android.view.View import android.view.WindowManager @@ -19,7 +15,6 @@ import com.amap.api.location.AMapLocation import com.casic.detector.R import com.casic.detector.adapter.EditableImageAdapter -import com.casic.detector.base.SerialPortActivity import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener @@ -31,29 +26,39 @@ 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.* +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.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.LoadState import com.pengxh.kt.lite.utils.SaveKeyValues -import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import java.io.File -import java.io.IOException import java.util.* @SuppressLint("SetTextI18n") -class InstallLabelActivity : SerialPortActivity(), Handler.Callback { +class InstallLabelActivity : KotlinBaseActivity(), + SerialPortManager.OnSerialPortListener { private val kTag = "InstallLabelActivity" - private val context: Context = this@InstallLabelActivity + private val context = this@InstallLabelActivity + private val serialPortManager by lazy { SerialPortManager(this) } private val calendar by lazy { Calendar.getInstance() } - private lateinit var imageAdapter: EditableImageAdapter - private val realPaths: ArrayList = ArrayList() //真实图片路径 - private lateinit var taskViewModel: TaskViewModel - private lateinit var soundPool: SoundPool - private var soundResId = 0 - private val gpioManager by lazy { GpioManager() } + private val audioAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ALARM) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + private val realPaths = ArrayList() //真实图片路径 private val locationHub by lazy { LocationHub(this) } - private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var imageAdapter: EditableImageAdapter + private lateinit var taskViewModel: TaskViewModel + private var soundPool: SoundPool? = null override fun initViewBinding(): ActivityInstallLabelBinding { return ActivityInstallLabelBinding.inflate(layoutInflater) @@ -79,13 +84,6 @@ binding.objectInclude.ownerView.setText("ownerView".getDefaultValue()) binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue()) binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue()) - - weakReferenceHandler = WeakReferenceHandler(this) - - val audioAttributes = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA) - .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() - soundPool = - SoundPool.Builder().setMaxStreams(16).setAudioAttributes(audioAttributes).build() } override fun initEvent() { @@ -247,6 +245,14 @@ return@setOnClickListener } + //查本地库 + val markerId = binding.identifierInclude.identifierIdView.text.toString() + val result = DataBaseManager.get.queryLabelById(markerId) + if (result.isEmpty()) { + "".show(this) + return@setOnClickListener + } + //先存本地再上传服务器 saveLabelInLocal() @@ -268,7 +274,7 @@ binding.objectInclude.constructDateView.text.toString(), binding.objectInclude.ownerView.text.toString(), objectId, - binding.identifierInclude.identifierIdView.text.toString(), + markerId, binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(), "${binding.identifierInclude.identifierDeepView.text}mm", binding.identifierInclude.personDeptView.text.toString(), @@ -305,25 +311,35 @@ } binding.readLabelButton.setOnClickListener { - gpioManager.setGpioHigh("18") - LoadingDialogHub.show(this, "标识器读取中,请稍后...") - soundResId = soundPool.load(this, R.raw.ring3, 1) - soundPool.setOnLoadCompleteListener { soundPool, _, _ -> - soundPool.play(soundResId, 1f, 1f, 0, -1, 1f) + soundPool = SoundPool.Builder() + .setMaxStreams(16) + .setAudioAttributes(audioAttributes) + .build() + soundPool?.apply { + val soundResId = load(context, R.raw.ring3, 1) + setOnLoadCompleteListener { soundPool, _, _ -> + soundPool.play(soundResId, 1f, 1f, 0, -1, 1f) + } } - // 1000ms后发送读标识器或搜索信号 - weakReferenceHandler.postDelayed({ - try { - // 发送读标识器或搜索信号 - outStream?.write("2".toByteArray()) - outStream?.flush() - } catch (e: IOException) { - e.printStackTrace() - } - }, 1000) + serialPortManager.searchMarkerSignal() + } + } + + override fun onDataReceived(buffer: ByteArray) { + LoadingDialogHub.dismiss() + soundPool?.release() + + val hex = buffer.toHex() +// Log.d(kTag, "$kTag => $hex") + if (hex.length >= 20) { + val markerId = hex.take(20).hexToString() + if (markerId.isNumber()) { + binding.identifierInclude.identifierIdView.text = markerId + serialPortManager.closeSerialPort() + } } } @@ -363,41 +379,6 @@ DataBaseManager.get.insertTaskLabel(labelBean) } - override fun onDataReceived(buffer: ByteArray?, size: Int) { - Log.d(kTag, "onDataReceived => " + buffer.contentToString()) - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023061601 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } - } - - override fun handleMessage(msg: Message): Boolean { - if (msg.what == 2023061601) { - soundPool.release() - - val buffer = msg.obj as ByteArray - val hex = buffer.toHex() - //3030303839383735313400000000000000000000000000000000000000000000 - if (hex.length >= 20) { - val identifierId = hex.substring(0, 20).hexToString() - - gpioManager.setGpioLow("18") - - //查本地库 - val result = DataBaseManager.get.queryLabelById(identifierId) - if (result.isEmpty()) { - binding.identifierInclude.identifierIdView.text = identifierId - } else { - "此标识器已安装,请更换标识器!".show(this) - } - LoadingDialogHub.dismiss() - } - } - return true - } - private fun takePicture() { PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) .forResult(object : OnResultCallbackListener { @@ -451,14 +432,14 @@ } override fun onDestroy() { - soundPool.release() - gpioManager.setGpioLow("18") super.onDestroy() + soundPool?.release() + locationHub.stopLocation() } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { if (keyCode == KeyEvent.KEYCODE_BACK) { - soundPool.release() + soundPool?.release() } return super.onKeyDown(keyCode, event) } diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index d590626..7c6446a 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -1,17 +1,19 @@ package com.casic.detector.view -import android.content.Context import android.content.Intent import android.graphics.BitmapFactory import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.media.AudioAttributes +import android.media.SoundPool import android.os.Bundle -import android.os.PowerManager import android.provider.Settings import android.util.Log import android.view.KeyEvent +import android.view.View 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 @@ -32,81 +34,89 @@ import com.casic.detector.databinding.ActivityMainBinding import com.casic.detector.extensions.appendDownloadUrl import com.casic.detector.extensions.drawCircle -import com.casic.detector.extensions.initLayoutImmersionBar +import com.casic.detector.extensions.hexToString +import com.casic.detector.extensions.initImmersionBar +import com.casic.detector.extensions.isNumber +import com.casic.detector.extensions.toHex import com.casic.detector.model.TaskModel import com.casic.detector.utils.DataBaseManager import com.casic.detector.utils.ExcelHub import com.casic.detector.utils.FileType +import com.casic.detector.utils.GpioManager import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub import com.casic.detector.utils.RouteOnMap +import com.casic.detector.utils.SerialPortManager import com.casic.detector.vm.TaskViewModel import com.casic.detector.widgets.QueryMarkerDialog import com.casic.detector.widgets.SamplePopupWindow import com.google.gson.Gson import com.google.gson.reflect.TypeToken -import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.callback.OnDownloadListener +import com.pengxh.kt.lite.extensions.convertDrawable import com.pengxh.kt.lite.extensions.createDownloadFileDir -import com.pengxh.kt.lite.extensions.downloadFile import com.pengxh.kt.lite.extensions.dp2px 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.toJson +import com.pengxh.kt.lite.utils.FileDownloadManager +import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.SaveKeyValues -import com.pengxh.kt.lite.vm.LoadState import com.pengxh.kt.lite.widget.dialog.AlertControlDialog +import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog import com.pengxh.kt.lite.widget.dialog.BottomActionSheet import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File -class MainActivity : KotlinBaseActivity() { +class MainActivity : KotlinBaseActivity(), + SerialPortManager.OnSerialPortListener { private val kTag = "MainActivity" - private val context: Context = this@MainActivity - private var clickTime: Long = 0 - private lateinit var aMap: AMap - private lateinit var taskViewModel: TaskViewModel + private val context = this@MainActivity + private val serialPortManager by lazy { SerialPortManager(this) } + private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } + private val gson by lazy { Gson() } + private val locationHub by lazy { LocationHub(this) } + private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } + private val backDrawables by lazy { HashMap() } + private val audioAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ALARM) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + private var clickTime: Long = 0 private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null - private val backDrawables = HashMap() - private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private var latitude: Double = 0.0 private var longitude: Double = 0.0 - private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub.obtainInstance(this) } - private lateinit var wakeLock: PowerManager.WakeLock + private var ids = ArrayList() + private lateinit var aMap: AMap + private lateinit var soundPool: SoundPool + private lateinit var taskViewModel: TaskViewModel private lateinit var taskBean: TaskBean + private lateinit var taskId: String override fun initViewBinding(): ActivityMainBinding { return ActivityMainBinding.inflate(layoutInflater) } override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).statusBarColor(R.color.themeColor).init() - initLayoutImmersionBar(binding.rootView) + binding.rootView.initImmersionBar(this, false, R.color.themeColor) } override fun initOnCreate(savedInstanceState: Bundle?) { - val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager - wakeLock = powerManager.run { - newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this@MainActivity.localClassName).apply { - acquire(60 * 60 * 1000L) - } - } - initMapConfig(savedInstanceState) + //调高串口电位 + gpioManager.setGpioHigh("18") + samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -119,12 +129,14 @@ val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) Log.d(kTag, "downloadUrl => $downloadUrl") - downloadUrl.downloadFile( - createDownloadFileDir().toString(), - object : OnDownloadListener { - override fun onDownloadEnd(file: File?) { - CoroutineScope(Dispatchers.Main).launch { - labelBeans = ExcelHub.read(file?.absolutePath) + FileDownloadManager.Builder() + .setDownloadFileSource(downloadUrl) + .setFileSuffix("xls") + .setFileSaveDirectory(createDownloadFileDir()) + .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadEnd(file: File) { + lifecycleScope.launch(Dispatchers.Main) { + labelBeans = ExcelHub.read(file.absolutePath) withContext(Dispatchers.IO) { labelBeans.forEach { label -> DataBaseManager.get.insertTaskLabel(label) @@ -135,14 +147,16 @@ } } - override fun onDownloadStart(totalBytes: Long) { + override fun onFailure(throwable: Throwable) { } - override fun onProgressChanged(currentBytes: Long) { + override fun onProgressChanged(progress: Int) { } }) + .build() + .start() } } taskViewModel.taskResult.observe(this) { @@ -159,19 +173,26 @@ }).build().show() } } + + taskViewModel.freeTaskResult.observe(this) { taskId = it } + + taskViewModel.uploadTaskMarkerResult.observe(this) { + "自由巡检任务已完成".show(this) + ids.clear() + } } override fun initEvent() { binding.rightImageView.setOnClickListener { - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { val labels = withContext(Dispatchers.IO) { DataBaseManager.get.queryLabelById("0") } if (labels.isNotEmpty()) { samplePopupWindow.setShowPosition(4) } - val x = binding.rightImageView.width - samplePopupWindow.width - 1f.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1f.dp2px(context)) + val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -201,7 +222,7 @@ QueryMarkerDialog.OnDialogButtonClickListener { override fun onConfirmClick(selectedItem: String, value: String) { //查询数据库 - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabelByCondition( selectedItem, value @@ -282,12 +303,14 @@ } }).build().show() } else { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") - .setMessage("现有任务已完成,请点击右上角菜单按钮下载新工单!") - .setPositiveButton("知道了").setOnDialogButtonClickListener(object : + AlertMessageDialog.Builder() + .setContext(this) + .setTitle("温馨提示") + .setMessage("现有任务已完成,请点击右上角菜单下载新工单或者开始自由巡检") + .setPositiveButton("开始自由巡检").setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { override fun onConfirmClick() { - + startFreeTask() } }).build().show() } @@ -297,6 +320,69 @@ binding.detectionButton.setOnClickListener { navigatePageTo() } + + //自由巡检 + binding.stopFreeTaskButton.setOnLongClickListener { + AlertMessageDialog.Builder() + .setContext(this) + .setTitle("温馨提示") + .setMessage("是否确定结束此次自由巡检任务?") + .setPositiveButton("是") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + soundPool.release() + serialPortManager.closeSerialPort() + + taskViewModel.uploadTaskMarker(taskId, ids) + binding.stopFreeTaskButton.visibility = View.GONE + } + }).build().show() + true + } + } + + private fun startFreeTask() { + AlertInputDialog.Builder() + .setContext(this) + .setTitle("新建自由巡检任务") + .setHintMessage("请输入自由巡检任务简要描述") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { + override fun onConfirmClick(value: String) { + val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String + taskViewModel.createFreeTask(userId, value) + + soundPool = SoundPool.Builder() + .setMaxStreams(16) + .setAudioAttributes(audioAttributes) + .build() + soundPool.load(context, R.raw.ring3, 1) + soundPool.setOnLoadCompleteListener { soundPool, sampleId, _ -> + soundPool.play(sampleId, 1f, 1f, 0, -1, 1f) + } + + //自由巡检 + serialPortManager.searchMarkerSignal() + + binding.stopFreeTaskButton.visibility = View.VISIBLE + } + + override fun onCancelClick() {} + }).build().show() + } + + override fun onDataReceived(buffer: ByteArray) { + val hex = buffer.toHex() +// Log.d(kTag, "$kTag => $hex") + if (hex.length >= 20) { + val markerId = hex.take(20).hexToString() + if (markerId.isNumber()) { + "标识器${markerId}已探测".show(this) + ids.add(markerId) + } + } } override fun observeRequestState() { @@ -342,7 +428,7 @@ aMap.setOnMapLongClickListener { //协程异步显示默认数据 - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadTaskLabels() as ArrayList } @@ -381,7 +467,7 @@ userName, messageModel.description, info.taskId.toString(), - info.taskCode.toString(), + info.id.toString(), info.markerId.toString(), info.markerIdReal.toString(), info.longitude.toString(), @@ -412,7 +498,7 @@ clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) clusterOverlay?.setClusterRender { clusterNum -> - val radius = 80f.dp2px(context) + val radius = 80.dp2px(context) if (clusterNum == 0) { var bitmapDrawable = backDrawables[0] if (bitmapDrawable == null) { @@ -426,7 +512,7 @@ if (clusterNum == 1) { var bitmapDrawable = backDrawables[1] if (bitmapDrawable == null) { - bitmapDrawable = resources.getDrawable(R.mipmap.label) + bitmapDrawable = R.mipmap.label.convertDrawable(this)!! backDrawables[1] = bitmapDrawable } bitmapDrawable @@ -478,9 +564,13 @@ val latLngBounds = builder.build() aMap.animateCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds, 0)) - AlertControlDialog.Builder().setContext(this).setTitle("提示") - .setMessage("请选择操作方式").setNegativeButton("标识器信息") - .setPositiveButton("到这里去").setOnDialogButtonClickListener(object : + AlertControlDialog.Builder() + .setContext(this) + .setTitle("提示") + .setMessage("请选择操作方式") + .setNegativeButton("标识器信息") + .setPositiveButton("到这里去") + .setOnDialogButtonClickListener(object : AlertControlDialog.OnDialogButtonClickListener { override fun onConfirmClick() { RouteOnMap.startNavigation(context, item.title, latLng) @@ -510,13 +600,13 @@ BitmapDescriptorFactory.fromBitmap( BitmapFactory.decodeResource(resources, R.mipmap.label_red1) ) - ).period(99).title("工单标识器").snippet(it.markerRealId) + ).period(99).title("工单标识器").snippet(it.markerId) } else { otMarkerOptions.icon( BitmapDescriptorFactory.fromBitmap( BitmapFactory.decodeResource(resources, R.mipmap.label_blue1) ) - ).period(99).title("工单标识器").snippet(it.markerRealId) + ).period(99).title("工单标识器").snippet(it.markerId) } aMap.addMarker(otMarkerOptions) } @@ -665,7 +755,7 @@ super.onResume() binding.mapView.onResume() //协程异步显示默认数据 - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadTaskLabels() as ArrayList } @@ -684,8 +774,10 @@ } override fun onDestroy() { - wakeLock.release() super.onDestroy() binding.mapView.onDestroy() + locationHub.stopLocation() + //降低串口电位 + gpioManager.setGpioLow("18") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/SearchLabelActivity.kt b/app/src/main/java/com/casic/detector/view/SearchLabelActivity.kt index dcf39b4..426aed3 100644 --- a/app/src/main/java/com/casic/detector/view/SearchLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/SearchLabelActivity.kt @@ -4,80 +4,59 @@ import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle -import android.os.Handler -import android.os.Message -import android.util.Log +import android.os.CountDownTimer import android.view.animation.Animation import android.view.animation.RotateAnimation +import androidx.activity.OnBackPressedCallback import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope import com.casic.detector.R -import com.casic.detector.base.SerialPortActivity import com.casic.detector.bean.TaskBean import com.casic.detector.databinding.ActivitySearchLabelBinding import com.casic.detector.extensions.hexToString +import com.casic.detector.extensions.isNumber import com.casic.detector.extensions.toHex import com.casic.detector.utils.DataBaseManager -import com.casic.detector.utils.GpioManager import com.casic.detector.utils.LoadingDialogHub -import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub +import com.casic.detector.utils.SerialPortManager import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.base.KotlinBaseActivity 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.LoadState -import com.pengxh.kt.lite.utils.SaveKeyValues -import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import java.io.IOException import java.text.DecimalFormat -import java.util.Timer -import java.util.TimerTask -class SearchLabelActivity : SerialPortActivity(), Handler.Callback { +class SearchLabelActivity : KotlinBaseActivity(), + SerialPortManager.OnSerialPortListener { private val kTag = "SearchLabelActivity" + private val serialPortManager by lazy { SerialPortManager(this) } + private val decimal by lazy { DecimalFormat("0.0") } + private val degreeCache by lazy { HashMap() } + private val locationHub by lazy { LocationHub(this) } + private val audioAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + private lateinit var taskViewModel: TaskViewModel private lateinit var slowSoundPool: SoundPool private lateinit var fastSoundPool: SoundPool private var slowResId = 0 private var fastResId = 0 - private val gpioManager by lazy { GpioManager() } - private val weakReferenceHandler by lazy { WeakReferenceHandler(this) } - private val detectTimer by lazy { Timer() } - private val decimal by lazy { DecimalFormat("0.0") } - private var identifierId = "" - private val lastDegreeMap by lazy { HashMap() } - private val locationHub by lazy { LocationHub(this) } - private var isPlaying = false - private var isDetectDepth = false - private lateinit var taskViewModel: TaskViewModel + private var markerId = "" private var taskLabel: TaskBean? = null - private val dataReceivedCode = 2023110301 + private var isPlaying = false override fun initOnCreate(savedInstanceState: Bundle?) { - gpioManager.setGpioHigh("18") - //角度 - lastDegreeMap["lastDegree"] = 0f + initSoundResource() + serialPortManager.detectMarker() + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] - - val audioAttributes = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA) - .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() - /** - * 声音效果速度 - * ling '7' @@ -137,149 +93,146 @@ } else { // 发送读取标识器埋设深度指令 LoadingDialogHub.show(this, "正在测距,请稍后...") - try { - outStream?.write(tag.code) - outStream?.flush() - } catch (e: IOException) { - e.printStackTrace() - } + serialPortManager.detectDepth(tag) + object : CountDownTimer(15 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + "请重试".show(this@SearchLabelActivity) +// initSoundResource() +// serialPortManager.detectMarker() + } + }.start() } } else { - "标识器未安装,安装成功后即可读取埋深!".show(this) + "标识器未安装,安装成功后才可读取埋深!".show(this) } } binding.markerInfoButton.setOnClickListener { //查库 - val result = DataBaseManager.get.queryLabelById(identifierId) + val result = DataBaseManager.get.queryLabelById(markerId) if (result.isNotEmpty()) { navigatePageTo(result.first().toJson()) } else { - navigatePageTo(identifierId) + navigatePageTo(markerId) } } + + //返回键监听,替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + slowSoundPool.release() + fastSoundPool.release() + serialPortManager.closeSerialPort() + finish() + } + }) } - override fun onDataReceived(buffer: ByteArray?, size: Int) { - val message = weakReferenceHandler.obtainMessage() - message.what = dataReceivedCode - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } - - override fun handleMessage(msg: Message): Boolean { - if (msg.what == dataReceivedCode) { - val buffer = msg.obj as ByteArray - val hex = buffer.toHex() - - //能量强度 - //4E30363634000000000000000000000000000000000000000000000000000000 - - //ID - //3030303839383735313400000000000000000000000000000000000000000000 - - //埋深 - //5330303736000000000000000000000000000000000000000000000000000000 - if (hex.startsWith("4E")) { - try { - //4E转为String为N,代表能量值 - //用能量值转动表盘 - val energyResponse = hex.substring(0, 10).hexToString() - //去掉前缀并缩小100倍 - var energy = energyResponse.substring(1).toInt() / 100 - if (energy >= 50) { - //测试过程最大值(5189)---> 5200 - energy = 50 + override fun onDataReceived(buffer: ByteArray) { + val hex = buffer.toHex() +// Log.d(kTag, "$kTag => $hex") + if (hex.startsWith("4E")) { + try { + //4E转为String为N,代表能量值 + //用能量值转动表盘 + val energyResponse = hex.take(10).hexToString() + val energy = energyResponse.substring(1).toInt() + if (energy >= 4000) { + isPlaying = if (!isPlaying) { + fastSoundPool.play(fastResId, 1f, 1f, 0, 0, 1f) + true + } else { + fastSoundPool.stop(fastResId) + false } + } else { + isPlaying = if (!isPlaying) { + slowSoundPool.play(slowResId, 1f, 1f, 0, 0, 1f) + true + } else { + slowSoundPool.stop(slowResId) + false + } + } - binding.resultTextView.text = "信号能量值:${energyResponse}" + binding.resultTextView.text = "信号能量值:${energyResponse}" - //转换为转动的角度 - val degree = (energy.toFloat() / 50) * 180 - binding.energyValueView.text = decimal.format(degree) + //转换为转动的角度 + val degree = (energy.toFloat() / (50 * 100)) * 180 + binding.energyValueView.text = decimal.format(degree) + degreeCache["lastDegree"]?.apply { val animation = RotateAnimation( - lastDegreeMap["lastDegree"]!!, - degree, - Animation.RELATIVE_TO_SELF, - 0.5f, - Animation.RELATIVE_TO_SELF, - 0.5f + this, degree, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f ) animation.duration = 0 animation.fillAfter = true binding.needleView.startAnimation(animation) - - //保存旋转后的角度 - lastDegreeMap["lastDegree"] = degree - - if (energy >= 41) { - isPlaying = if (!isPlaying) { - fastSoundPool.play(fastResId, 1f, 1f, 0, 0, 1f) - true - } else { - fastSoundPool.stop(fastResId) - false - } - } else { - isPlaying = if (!isPlaying) { - slowSoundPool.play(slowResId, 1f, 1f, 0, 0, 1f) - true - } else { - slowSoundPool.stop(slowResId) - false - } - } - - if (energy <= 7) {//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 >= 41) {//148° - binding.energyTipsView.text = "标识器信号极强,可能在正下方" - binding.energyTipsView.setTextColor(Color.parseColor("#428d00")) - binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green) - } else {//[18°,148°] - 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")) { - try { - LoadingDialogHub.dismiss() - //53转为String为S,代表深度 - val depthResponse = hex.substring(0, 10).hexToString() - val depth = depthResponse.substring(1).toInt() - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") - .setMessage("标识器埋深:${depth}厘米").setPositiveButton("知道了") - .setOnDialogButtonClickListener(object : - AlertMessageDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - isDetectDepth = false - } - }).build().show() - } catch (e: NumberFormatException) { - e.printStackTrace() + + //保存旋转后的角度 + degreeCache["lastDegree"] = degree + + 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) {//148° + binding.energyTipsView.text = "标识器信号极强,可能在正下方" + binding.energyTipsView.setTextColor(Color.parseColor("#428d00")) + binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green) + } else {//[18°,148°] + binding.energyTipsView.text = "已靠近标识器,请继续移动位置" + binding.energyTipsView.setTextColor(Color.parseColor("#8C5700")) + binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow) } - } else { - val id = hex.substring(0, 20).hexToString() - val regex = "^[a-z0-9A-Z]+$" - if (id.matches(Regex(regex))) { + } catch (e: NumberFormatException) { + e.printStackTrace() + } + } else if (hex.startsWith("53")) { + LoadingDialogHub.dismiss() + try { + val depthResponse = hex.take(10).hexToString() + val depth = depthResponse.drop(4) + AlertMessageDialog.Builder() + .setContext(this@SearchLabelActivity) + .setTitle("温馨提示") + .setMessage("标识器埋深:${depth}厘米") + .setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { +// initSoundResource() +// serialPortManager.detectMarker() + } + }).build().show() + } catch (e: NumberFormatException) { + e.printStackTrace() + } + } else { + if (hex.length >= 20) { + val id = hex.take(20).hexToString() + if (markerId.isNumber()) { + markerId = id + binding.depthButton.isEnabled = true binding.depthButton.setTextColor(Color.WHITE) binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable) @@ -292,21 +245,36 @@ binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green) //自动上传标识器 - taskLabel = DataBaseManager.get.queryTaskLabelByIdAndState(id, "未开始") - if (taskLabel != null) { - val userName = SaveKeyValues.getValue( - LocaleConstant.USER_NAME, "" - ).toString() - taskViewModel.uploadMarker(userName, id) + taskLabel = DataBaseManager.get.queryTaskLabelByIdAndState( + markerId, "未开始" + ) + taskLabel?.apply { + /** + * 此taskCode是 [com.casic.detector.model.TaskModel.MessageModel.TaskDetailInfosModel] 里面的主键,也就是这个标签在数据库里面的主键 + * */ + taskViewModel.uploadMarker(taskCode) } - - this.identifierId = id - } else { - Log.d(kTag, "handleMessage => $id") } } } - return true + } + + private fun initSoundResource() { + /** + * 声音效果速度 + * ling() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/ArrayList.kt b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt new file mode 100644 index 0000000..52f8ac9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt @@ -0,0 +1,20 @@ +package com.casic.detector.extensions + +/** + * ArrayList扩展方法 + */ + +//将集合格式化成满足上传格式的数据 +fun ArrayList.reformat(): String { + if (this.isEmpty()) return "" + val builder = StringBuilder() + //循环遍历元素,同时得到元素index(下标) + this.forEachIndexed { index, s -> + if (index == this.size - 1) { + builder.append(s) + } else { + builder.append(s).append(",") + } + } + return builder.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index b76d83d..785b89f 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -122,4 +122,9 @@ } } return sb.toString() +} + +fun String.isNumber(): Boolean { + val regex = Regex("[-+]?\\d+(\\.\\d+)?") + return this.matches(regex) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java index cab23bb..682c3f8 100644 --- a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java +++ b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java @@ -13,20 +13,25 @@ // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + /** * Master of DAO (schema version 1): knows all DAOs. */ public class DaoMaster extends AbstractDaoMaster { public static final int SCHEMA_VERSION = 1; - /** Creates underlying database table using DAOs. */ + /** + * Creates underlying database table using DAOs. + */ public static void createAllTables(Database db, boolean ifNotExists) { LabelBeanDao.createTable(db, ifNotExists); SmallLabelBeanDao.createTable(db, ifNotExists); TaskBeanDao.createTable(db, ifNotExists); } - /** Drops underlying database table using DAOs. */ + /** + * Drops underlying database table using DAOs. + */ public static void dropAllTables(Database db, boolean ifExists) { LabelBeanDao.dropTable(db, ifExists); SmallLabelBeanDao.dropTable(db, ifExists); @@ -81,7 +86,9 @@ } } - /** WARNING: Drops all table on Upgrade! Use only during development. */ + /** + * WARNING: Drops all table on Upgrade! Use only during development. + */ public static class DevOpenHelper extends OpenHelper { public DevOpenHelper(Context context, String name) { super(context, name); diff --git a/app/src/main/java/com/casic/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/detector/model/CalculateResult.kt new file mode 100644 index 0000000..02cb0a0 --- /dev/null +++ b/app/src/main/java/com/casic/detector/model/CalculateResult.kt @@ -0,0 +1,3 @@ +package com.casic.detector.model + +data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 43a8484..cae51d5 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -82,25 +82,21 @@ */ @GET("/ems/rs/task/update-task-mark") suspend fun uploadMarker( - @Query("taskDetailId") taskId: String, + @Query("taskDetailId") taskId: String ): String /** * 新建自由巡检任务 * */ - @GET("") + @GET("ems/rs/task/addAppTask") suspend fun createFreeTask( @Query("patrollerId") patrollerId: String, - @Query("description") description: String, + @Query("description") description: String ): String /** * 上传自由巡检过程中发现的标识器 * */ - @Multipart - @POST("") - suspend fun uploadTaskMarker( - @Field("taskId") taskId: String, - @Body requestBody: RequestBody, - ): String + @POST("ems/event/uploadAppMarker.do") + suspend fun uploadTaskMarker(@Body requestBody: RequestBody): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 8ae0794..ac06760 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -1,9 +1,9 @@ package com.casic.detector.retrofit +import com.casic.detector.extensions.reformat import com.casic.detector.utils.LocaleConstant import com.google.gson.Gson import com.google.gson.JsonObject -import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType @@ -16,7 +16,6 @@ object RetrofitServiceManager { private val gson by lazy { Gson() } - private val typeToken = object : TypeToken>() {}.type private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String @@ -233,12 +232,13 @@ /** * 上传自由巡检过程中发现的标识器 */ - suspend fun uploadTaskMarker(taskId: String, models: List): String { + suspend fun uploadTaskMarker(taskId: String, models: ArrayList): String { val param = JsonObject() - param.add("markers", gson.toJsonTree(models, typeToken).asJsonArray) + param.addProperty("taskId", taskId) + param.addProperty("ids", models.reformat()) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return createApi().uploadTaskMarker(taskId, requestBody) + return createApi().uploadTaskMarker(requestBody) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt index 1c7d95b..7e627a4 100644 --- a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt @@ -105,7 +105,7 @@ fun queryTaskLabelByIdAndState(identifierId: String, state: String): TaskBean? { return taskBeanDao.queryBuilder() .where( - TaskBeanDao.Properties.MarkerRealId.eq(identifierId), + TaskBeanDao.Properties.MarkerId.eq(identifierId), TaskBeanDao.Properties.State.eq(state) ).list().firstOrNull() } diff --git a/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt b/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt new file mode 100644 index 0000000..c235471 --- /dev/null +++ b/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt @@ -0,0 +1,119 @@ +package com.casic.detector.utils + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.lifecycleScope +import com.casic.detector.base.BaseApplication +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.IOException + +class SerialPortManager(private val listener: OnSerialPortListener) : LifecycleOwner { + + private val kTag = "SerialPortManager" + private val registry = LifecycleRegistry(this) + + init { + //读取串口数据 + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + val buffer = ByteArray(72) + var size: Int + serialPorts?.forEach { + val stream = it.inputStream + while (true) { + try { + size = stream.read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + listener.onDataReceived(buffer) + } + } + } catch (e: IOException) { + e.printStackTrace() + return@launch + } + } + } + } + } + + /** + * 探测 + * */ + fun detectMarker() { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + while (size >= 1) { + val outStream = this[0].outputStream + try { + // 发送读标识器ID指令 + outStream?.write('2'.code) + outStream?.flush() + delay(100) + + outStream.write('6'.code) + outStream.flush() + delay(100) + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + } + + /** + * 发送探测深度指令 + * */ + fun detectDepth(markerTag: Char) { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + val outStream = this[0].outputStream + try { + // 发送测距指令 + outStream?.write(markerTag.code) + outStream?.flush() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + + /** + * 发送读标识器ID指令 + * */ + fun searchMarkerSignal() { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + val outStream = this[0].outputStream + try { + // 发送读标识器ID指令 + outStream?.write('2'.code) + outStream?.flush() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + + fun closeSerialPort() { + BaseApplication.get().closeSerialPort() + } + + interface OnSerialPortListener { + fun onDataReceived(buffer: ByteArray) + } + + override fun getLifecycle(): Lifecycle { + return registry + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index 68d54b2..5bac324 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -2,16 +2,12 @@ import android.annotation.SuppressLint import android.app.DatePickerDialog -import android.content.Context import android.content.DialogInterface import android.content.Intent import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle -import android.os.Handler -import android.os.Message import android.provider.Settings -import android.util.Log import android.view.KeyEvent import android.view.View import android.view.WindowManager @@ -19,7 +15,6 @@ import com.amap.api.location.AMapLocation import com.casic.detector.R import com.casic.detector.adapter.EditableImageAdapter -import com.casic.detector.base.SerialPortActivity import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener @@ -31,29 +26,39 @@ 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.* +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.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.LoadState import com.pengxh.kt.lite.utils.SaveKeyValues -import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import java.io.File -import java.io.IOException import java.util.* @SuppressLint("SetTextI18n") -class InstallLabelActivity : SerialPortActivity(), Handler.Callback { +class InstallLabelActivity : KotlinBaseActivity(), + SerialPortManager.OnSerialPortListener { private val kTag = "InstallLabelActivity" - private val context: Context = this@InstallLabelActivity + private val context = this@InstallLabelActivity + private val serialPortManager by lazy { SerialPortManager(this) } private val calendar by lazy { Calendar.getInstance() } - private lateinit var imageAdapter: EditableImageAdapter - private val realPaths: ArrayList = ArrayList() //真实图片路径 - private lateinit var taskViewModel: TaskViewModel - private lateinit var soundPool: SoundPool - private var soundResId = 0 - private val gpioManager by lazy { GpioManager() } + private val audioAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ALARM) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + private val realPaths = ArrayList() //真实图片路径 private val locationHub by lazy { LocationHub(this) } - private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var imageAdapter: EditableImageAdapter + private lateinit var taskViewModel: TaskViewModel + private var soundPool: SoundPool? = null override fun initViewBinding(): ActivityInstallLabelBinding { return ActivityInstallLabelBinding.inflate(layoutInflater) @@ -79,13 +84,6 @@ binding.objectInclude.ownerView.setText("ownerView".getDefaultValue()) binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue()) binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue()) - - weakReferenceHandler = WeakReferenceHandler(this) - - val audioAttributes = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA) - .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() - soundPool = - SoundPool.Builder().setMaxStreams(16).setAudioAttributes(audioAttributes).build() } override fun initEvent() { @@ -247,6 +245,14 @@ return@setOnClickListener } + //查本地库 + val markerId = binding.identifierInclude.identifierIdView.text.toString() + val result = DataBaseManager.get.queryLabelById(markerId) + if (result.isEmpty()) { + "".show(this) + return@setOnClickListener + } + //先存本地再上传服务器 saveLabelInLocal() @@ -268,7 +274,7 @@ binding.objectInclude.constructDateView.text.toString(), binding.objectInclude.ownerView.text.toString(), objectId, - binding.identifierInclude.identifierIdView.text.toString(), + markerId, binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(), "${binding.identifierInclude.identifierDeepView.text}mm", binding.identifierInclude.personDeptView.text.toString(), @@ -305,25 +311,35 @@ } binding.readLabelButton.setOnClickListener { - gpioManager.setGpioHigh("18") - LoadingDialogHub.show(this, "标识器读取中,请稍后...") - soundResId = soundPool.load(this, R.raw.ring3, 1) - soundPool.setOnLoadCompleteListener { soundPool, _, _ -> - soundPool.play(soundResId, 1f, 1f, 0, -1, 1f) + soundPool = SoundPool.Builder() + .setMaxStreams(16) + .setAudioAttributes(audioAttributes) + .build() + soundPool?.apply { + val soundResId = load(context, R.raw.ring3, 1) + setOnLoadCompleteListener { soundPool, _, _ -> + soundPool.play(soundResId, 1f, 1f, 0, -1, 1f) + } } - // 1000ms后发送读标识器或搜索信号 - weakReferenceHandler.postDelayed({ - try { - // 发送读标识器或搜索信号 - outStream?.write("2".toByteArray()) - outStream?.flush() - } catch (e: IOException) { - e.printStackTrace() - } - }, 1000) + serialPortManager.searchMarkerSignal() + } + } + + override fun onDataReceived(buffer: ByteArray) { + LoadingDialogHub.dismiss() + soundPool?.release() + + val hex = buffer.toHex() +// Log.d(kTag, "$kTag => $hex") + if (hex.length >= 20) { + val markerId = hex.take(20).hexToString() + if (markerId.isNumber()) { + binding.identifierInclude.identifierIdView.text = markerId + serialPortManager.closeSerialPort() + } } } @@ -363,41 +379,6 @@ DataBaseManager.get.insertTaskLabel(labelBean) } - override fun onDataReceived(buffer: ByteArray?, size: Int) { - Log.d(kTag, "onDataReceived => " + buffer.contentToString()) - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023061601 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } - } - - override fun handleMessage(msg: Message): Boolean { - if (msg.what == 2023061601) { - soundPool.release() - - val buffer = msg.obj as ByteArray - val hex = buffer.toHex() - //3030303839383735313400000000000000000000000000000000000000000000 - if (hex.length >= 20) { - val identifierId = hex.substring(0, 20).hexToString() - - gpioManager.setGpioLow("18") - - //查本地库 - val result = DataBaseManager.get.queryLabelById(identifierId) - if (result.isEmpty()) { - binding.identifierInclude.identifierIdView.text = identifierId - } else { - "此标识器已安装,请更换标识器!".show(this) - } - LoadingDialogHub.dismiss() - } - } - return true - } - private fun takePicture() { PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) .forResult(object : OnResultCallbackListener { @@ -451,14 +432,14 @@ } override fun onDestroy() { - soundPool.release() - gpioManager.setGpioLow("18") super.onDestroy() + soundPool?.release() + locationHub.stopLocation() } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { if (keyCode == KeyEvent.KEYCODE_BACK) { - soundPool.release() + soundPool?.release() } return super.onKeyDown(keyCode, event) } diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index d590626..7c6446a 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -1,17 +1,19 @@ package com.casic.detector.view -import android.content.Context import android.content.Intent import android.graphics.BitmapFactory import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.media.AudioAttributes +import android.media.SoundPool import android.os.Bundle -import android.os.PowerManager import android.provider.Settings import android.util.Log import android.view.KeyEvent +import android.view.View 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 @@ -32,81 +34,89 @@ import com.casic.detector.databinding.ActivityMainBinding import com.casic.detector.extensions.appendDownloadUrl import com.casic.detector.extensions.drawCircle -import com.casic.detector.extensions.initLayoutImmersionBar +import com.casic.detector.extensions.hexToString +import com.casic.detector.extensions.initImmersionBar +import com.casic.detector.extensions.isNumber +import com.casic.detector.extensions.toHex import com.casic.detector.model.TaskModel import com.casic.detector.utils.DataBaseManager import com.casic.detector.utils.ExcelHub import com.casic.detector.utils.FileType +import com.casic.detector.utils.GpioManager import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub import com.casic.detector.utils.RouteOnMap +import com.casic.detector.utils.SerialPortManager import com.casic.detector.vm.TaskViewModel import com.casic.detector.widgets.QueryMarkerDialog import com.casic.detector.widgets.SamplePopupWindow import com.google.gson.Gson import com.google.gson.reflect.TypeToken -import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.callback.OnDownloadListener +import com.pengxh.kt.lite.extensions.convertDrawable import com.pengxh.kt.lite.extensions.createDownloadFileDir -import com.pengxh.kt.lite.extensions.downloadFile import com.pengxh.kt.lite.extensions.dp2px 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.toJson +import com.pengxh.kt.lite.utils.FileDownloadManager +import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.SaveKeyValues -import com.pengxh.kt.lite.vm.LoadState import com.pengxh.kt.lite.widget.dialog.AlertControlDialog +import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog import com.pengxh.kt.lite.widget.dialog.BottomActionSheet import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File -class MainActivity : KotlinBaseActivity() { +class MainActivity : KotlinBaseActivity(), + SerialPortManager.OnSerialPortListener { private val kTag = "MainActivity" - private val context: Context = this@MainActivity - private var clickTime: Long = 0 - private lateinit var aMap: AMap - private lateinit var taskViewModel: TaskViewModel + private val context = this@MainActivity + private val serialPortManager by lazy { SerialPortManager(this) } + private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } + private val gson by lazy { Gson() } + private val locationHub by lazy { LocationHub(this) } + private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } + private val backDrawables by lazy { HashMap() } + private val audioAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ALARM) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + private var clickTime: Long = 0 private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null - private val backDrawables = HashMap() - private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private var latitude: Double = 0.0 private var longitude: Double = 0.0 - private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub.obtainInstance(this) } - private lateinit var wakeLock: PowerManager.WakeLock + private var ids = ArrayList() + private lateinit var aMap: AMap + private lateinit var soundPool: SoundPool + private lateinit var taskViewModel: TaskViewModel private lateinit var taskBean: TaskBean + private lateinit var taskId: String override fun initViewBinding(): ActivityMainBinding { return ActivityMainBinding.inflate(layoutInflater) } override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).statusBarColor(R.color.themeColor).init() - initLayoutImmersionBar(binding.rootView) + binding.rootView.initImmersionBar(this, false, R.color.themeColor) } override fun initOnCreate(savedInstanceState: Bundle?) { - val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager - wakeLock = powerManager.run { - newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this@MainActivity.localClassName).apply { - acquire(60 * 60 * 1000L) - } - } - initMapConfig(savedInstanceState) + //调高串口电位 + gpioManager.setGpioHigh("18") + samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -119,12 +129,14 @@ val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) Log.d(kTag, "downloadUrl => $downloadUrl") - downloadUrl.downloadFile( - createDownloadFileDir().toString(), - object : OnDownloadListener { - override fun onDownloadEnd(file: File?) { - CoroutineScope(Dispatchers.Main).launch { - labelBeans = ExcelHub.read(file?.absolutePath) + FileDownloadManager.Builder() + .setDownloadFileSource(downloadUrl) + .setFileSuffix("xls") + .setFileSaveDirectory(createDownloadFileDir()) + .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadEnd(file: File) { + lifecycleScope.launch(Dispatchers.Main) { + labelBeans = ExcelHub.read(file.absolutePath) withContext(Dispatchers.IO) { labelBeans.forEach { label -> DataBaseManager.get.insertTaskLabel(label) @@ -135,14 +147,16 @@ } } - override fun onDownloadStart(totalBytes: Long) { + override fun onFailure(throwable: Throwable) { } - override fun onProgressChanged(currentBytes: Long) { + override fun onProgressChanged(progress: Int) { } }) + .build() + .start() } } taskViewModel.taskResult.observe(this) { @@ -159,19 +173,26 @@ }).build().show() } } + + taskViewModel.freeTaskResult.observe(this) { taskId = it } + + taskViewModel.uploadTaskMarkerResult.observe(this) { + "自由巡检任务已完成".show(this) + ids.clear() + } } override fun initEvent() { binding.rightImageView.setOnClickListener { - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { val labels = withContext(Dispatchers.IO) { DataBaseManager.get.queryLabelById("0") } if (labels.isNotEmpty()) { samplePopupWindow.setShowPosition(4) } - val x = binding.rightImageView.width - samplePopupWindow.width - 1f.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1f.dp2px(context)) + val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -201,7 +222,7 @@ QueryMarkerDialog.OnDialogButtonClickListener { override fun onConfirmClick(selectedItem: String, value: String) { //查询数据库 - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabelByCondition( selectedItem, value @@ -282,12 +303,14 @@ } }).build().show() } else { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") - .setMessage("现有任务已完成,请点击右上角菜单按钮下载新工单!") - .setPositiveButton("知道了").setOnDialogButtonClickListener(object : + AlertMessageDialog.Builder() + .setContext(this) + .setTitle("温馨提示") + .setMessage("现有任务已完成,请点击右上角菜单下载新工单或者开始自由巡检") + .setPositiveButton("开始自由巡检").setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { override fun onConfirmClick() { - + startFreeTask() } }).build().show() } @@ -297,6 +320,69 @@ binding.detectionButton.setOnClickListener { navigatePageTo() } + + //自由巡检 + binding.stopFreeTaskButton.setOnLongClickListener { + AlertMessageDialog.Builder() + .setContext(this) + .setTitle("温馨提示") + .setMessage("是否确定结束此次自由巡检任务?") + .setPositiveButton("是") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + soundPool.release() + serialPortManager.closeSerialPort() + + taskViewModel.uploadTaskMarker(taskId, ids) + binding.stopFreeTaskButton.visibility = View.GONE + } + }).build().show() + true + } + } + + private fun startFreeTask() { + AlertInputDialog.Builder() + .setContext(this) + .setTitle("新建自由巡检任务") + .setHintMessage("请输入自由巡检任务简要描述") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { + override fun onConfirmClick(value: String) { + val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String + taskViewModel.createFreeTask(userId, value) + + soundPool = SoundPool.Builder() + .setMaxStreams(16) + .setAudioAttributes(audioAttributes) + .build() + soundPool.load(context, R.raw.ring3, 1) + soundPool.setOnLoadCompleteListener { soundPool, sampleId, _ -> + soundPool.play(sampleId, 1f, 1f, 0, -1, 1f) + } + + //自由巡检 + serialPortManager.searchMarkerSignal() + + binding.stopFreeTaskButton.visibility = View.VISIBLE + } + + override fun onCancelClick() {} + }).build().show() + } + + override fun onDataReceived(buffer: ByteArray) { + val hex = buffer.toHex() +// Log.d(kTag, "$kTag => $hex") + if (hex.length >= 20) { + val markerId = hex.take(20).hexToString() + if (markerId.isNumber()) { + "标识器${markerId}已探测".show(this) + ids.add(markerId) + } + } } override fun observeRequestState() { @@ -342,7 +428,7 @@ aMap.setOnMapLongClickListener { //协程异步显示默认数据 - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadTaskLabels() as ArrayList } @@ -381,7 +467,7 @@ userName, messageModel.description, info.taskId.toString(), - info.taskCode.toString(), + info.id.toString(), info.markerId.toString(), info.markerIdReal.toString(), info.longitude.toString(), @@ -412,7 +498,7 @@ clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) clusterOverlay?.setClusterRender { clusterNum -> - val radius = 80f.dp2px(context) + val radius = 80.dp2px(context) if (clusterNum == 0) { var bitmapDrawable = backDrawables[0] if (bitmapDrawable == null) { @@ -426,7 +512,7 @@ if (clusterNum == 1) { var bitmapDrawable = backDrawables[1] if (bitmapDrawable == null) { - bitmapDrawable = resources.getDrawable(R.mipmap.label) + bitmapDrawable = R.mipmap.label.convertDrawable(this)!! backDrawables[1] = bitmapDrawable } bitmapDrawable @@ -478,9 +564,13 @@ val latLngBounds = builder.build() aMap.animateCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds, 0)) - AlertControlDialog.Builder().setContext(this).setTitle("提示") - .setMessage("请选择操作方式").setNegativeButton("标识器信息") - .setPositiveButton("到这里去").setOnDialogButtonClickListener(object : + AlertControlDialog.Builder() + .setContext(this) + .setTitle("提示") + .setMessage("请选择操作方式") + .setNegativeButton("标识器信息") + .setPositiveButton("到这里去") + .setOnDialogButtonClickListener(object : AlertControlDialog.OnDialogButtonClickListener { override fun onConfirmClick() { RouteOnMap.startNavigation(context, item.title, latLng) @@ -510,13 +600,13 @@ BitmapDescriptorFactory.fromBitmap( BitmapFactory.decodeResource(resources, R.mipmap.label_red1) ) - ).period(99).title("工单标识器").snippet(it.markerRealId) + ).period(99).title("工单标识器").snippet(it.markerId) } else { otMarkerOptions.icon( BitmapDescriptorFactory.fromBitmap( BitmapFactory.decodeResource(resources, R.mipmap.label_blue1) ) - ).period(99).title("工单标识器").snippet(it.markerRealId) + ).period(99).title("工单标识器").snippet(it.markerId) } aMap.addMarker(otMarkerOptions) } @@ -665,7 +755,7 @@ super.onResume() binding.mapView.onResume() //协程异步显示默认数据 - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadTaskLabels() as ArrayList } @@ -684,8 +774,10 @@ } override fun onDestroy() { - wakeLock.release() super.onDestroy() binding.mapView.onDestroy() + locationHub.stopLocation() + //降低串口电位 + gpioManager.setGpioLow("18") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/SearchLabelActivity.kt b/app/src/main/java/com/casic/detector/view/SearchLabelActivity.kt index dcf39b4..426aed3 100644 --- a/app/src/main/java/com/casic/detector/view/SearchLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/SearchLabelActivity.kt @@ -4,80 +4,59 @@ import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle -import android.os.Handler -import android.os.Message -import android.util.Log +import android.os.CountDownTimer import android.view.animation.Animation import android.view.animation.RotateAnimation +import androidx.activity.OnBackPressedCallback import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope import com.casic.detector.R -import com.casic.detector.base.SerialPortActivity import com.casic.detector.bean.TaskBean import com.casic.detector.databinding.ActivitySearchLabelBinding import com.casic.detector.extensions.hexToString +import com.casic.detector.extensions.isNumber import com.casic.detector.extensions.toHex import com.casic.detector.utils.DataBaseManager -import com.casic.detector.utils.GpioManager import com.casic.detector.utils.LoadingDialogHub -import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub +import com.casic.detector.utils.SerialPortManager import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.base.KotlinBaseActivity 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.LoadState -import com.pengxh.kt.lite.utils.SaveKeyValues -import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import java.io.IOException import java.text.DecimalFormat -import java.util.Timer -import java.util.TimerTask -class SearchLabelActivity : SerialPortActivity(), Handler.Callback { +class SearchLabelActivity : KotlinBaseActivity(), + SerialPortManager.OnSerialPortListener { private val kTag = "SearchLabelActivity" + private val serialPortManager by lazy { SerialPortManager(this) } + private val decimal by lazy { DecimalFormat("0.0") } + private val degreeCache by lazy { HashMap() } + private val locationHub by lazy { LocationHub(this) } + private val audioAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + private lateinit var taskViewModel: TaskViewModel private lateinit var slowSoundPool: SoundPool private lateinit var fastSoundPool: SoundPool private var slowResId = 0 private var fastResId = 0 - private val gpioManager by lazy { GpioManager() } - private val weakReferenceHandler by lazy { WeakReferenceHandler(this) } - private val detectTimer by lazy { Timer() } - private val decimal by lazy { DecimalFormat("0.0") } - private var identifierId = "" - private val lastDegreeMap by lazy { HashMap() } - private val locationHub by lazy { LocationHub(this) } - private var isPlaying = false - private var isDetectDepth = false - private lateinit var taskViewModel: TaskViewModel + private var markerId = "" private var taskLabel: TaskBean? = null - private val dataReceivedCode = 2023110301 + private var isPlaying = false override fun initOnCreate(savedInstanceState: Bundle?) { - gpioManager.setGpioHigh("18") - //角度 - lastDegreeMap["lastDegree"] = 0f + initSoundResource() + serialPortManager.detectMarker() + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] - - val audioAttributes = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA) - .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() - /** - * 声音效果速度 - * ling '7' @@ -137,149 +93,146 @@ } else { // 发送读取标识器埋设深度指令 LoadingDialogHub.show(this, "正在测距,请稍后...") - try { - outStream?.write(tag.code) - outStream?.flush() - } catch (e: IOException) { - e.printStackTrace() - } + serialPortManager.detectDepth(tag) + object : CountDownTimer(15 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + "请重试".show(this@SearchLabelActivity) +// initSoundResource() +// serialPortManager.detectMarker() + } + }.start() } } else { - "标识器未安装,安装成功后即可读取埋深!".show(this) + "标识器未安装,安装成功后才可读取埋深!".show(this) } } binding.markerInfoButton.setOnClickListener { //查库 - val result = DataBaseManager.get.queryLabelById(identifierId) + val result = DataBaseManager.get.queryLabelById(markerId) if (result.isNotEmpty()) { navigatePageTo(result.first().toJson()) } else { - navigatePageTo(identifierId) + navigatePageTo(markerId) } } + + //返回键监听,替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + slowSoundPool.release() + fastSoundPool.release() + serialPortManager.closeSerialPort() + finish() + } + }) } - override fun onDataReceived(buffer: ByteArray?, size: Int) { - val message = weakReferenceHandler.obtainMessage() - message.what = dataReceivedCode - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } - - override fun handleMessage(msg: Message): Boolean { - if (msg.what == dataReceivedCode) { - val buffer = msg.obj as ByteArray - val hex = buffer.toHex() - - //能量强度 - //4E30363634000000000000000000000000000000000000000000000000000000 - - //ID - //3030303839383735313400000000000000000000000000000000000000000000 - - //埋深 - //5330303736000000000000000000000000000000000000000000000000000000 - if (hex.startsWith("4E")) { - try { - //4E转为String为N,代表能量值 - //用能量值转动表盘 - val energyResponse = hex.substring(0, 10).hexToString() - //去掉前缀并缩小100倍 - var energy = energyResponse.substring(1).toInt() / 100 - if (energy >= 50) { - //测试过程最大值(5189)---> 5200 - energy = 50 + override fun onDataReceived(buffer: ByteArray) { + val hex = buffer.toHex() +// Log.d(kTag, "$kTag => $hex") + if (hex.startsWith("4E")) { + try { + //4E转为String为N,代表能量值 + //用能量值转动表盘 + val energyResponse = hex.take(10).hexToString() + val energy = energyResponse.substring(1).toInt() + if (energy >= 4000) { + isPlaying = if (!isPlaying) { + fastSoundPool.play(fastResId, 1f, 1f, 0, 0, 1f) + true + } else { + fastSoundPool.stop(fastResId) + false } + } else { + isPlaying = if (!isPlaying) { + slowSoundPool.play(slowResId, 1f, 1f, 0, 0, 1f) + true + } else { + slowSoundPool.stop(slowResId) + false + } + } - binding.resultTextView.text = "信号能量值:${energyResponse}" + binding.resultTextView.text = "信号能量值:${energyResponse}" - //转换为转动的角度 - val degree = (energy.toFloat() / 50) * 180 - binding.energyValueView.text = decimal.format(degree) + //转换为转动的角度 + val degree = (energy.toFloat() / (50 * 100)) * 180 + binding.energyValueView.text = decimal.format(degree) + degreeCache["lastDegree"]?.apply { val animation = RotateAnimation( - lastDegreeMap["lastDegree"]!!, - degree, - Animation.RELATIVE_TO_SELF, - 0.5f, - Animation.RELATIVE_TO_SELF, - 0.5f + this, degree, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f ) animation.duration = 0 animation.fillAfter = true binding.needleView.startAnimation(animation) - - //保存旋转后的角度 - lastDegreeMap["lastDegree"] = degree - - if (energy >= 41) { - isPlaying = if (!isPlaying) { - fastSoundPool.play(fastResId, 1f, 1f, 0, 0, 1f) - true - } else { - fastSoundPool.stop(fastResId) - false - } - } else { - isPlaying = if (!isPlaying) { - slowSoundPool.play(slowResId, 1f, 1f, 0, 0, 1f) - true - } else { - slowSoundPool.stop(slowResId) - false - } - } - - if (energy <= 7) {//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 >= 41) {//148° - binding.energyTipsView.text = "标识器信号极强,可能在正下方" - binding.energyTipsView.setTextColor(Color.parseColor("#428d00")) - binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green) - } else {//[18°,148°] - 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")) { - try { - LoadingDialogHub.dismiss() - //53转为String为S,代表深度 - val depthResponse = hex.substring(0, 10).hexToString() - val depth = depthResponse.substring(1).toInt() - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") - .setMessage("标识器埋深:${depth}厘米").setPositiveButton("知道了") - .setOnDialogButtonClickListener(object : - AlertMessageDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - isDetectDepth = false - } - }).build().show() - } catch (e: NumberFormatException) { - e.printStackTrace() + + //保存旋转后的角度 + degreeCache["lastDegree"] = degree + + 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) {//148° + binding.energyTipsView.text = "标识器信号极强,可能在正下方" + binding.energyTipsView.setTextColor(Color.parseColor("#428d00")) + binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green) + } else {//[18°,148°] + binding.energyTipsView.text = "已靠近标识器,请继续移动位置" + binding.energyTipsView.setTextColor(Color.parseColor("#8C5700")) + binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow) } - } else { - val id = hex.substring(0, 20).hexToString() - val regex = "^[a-z0-9A-Z]+$" - if (id.matches(Regex(regex))) { + } catch (e: NumberFormatException) { + e.printStackTrace() + } + } else if (hex.startsWith("53")) { + LoadingDialogHub.dismiss() + try { + val depthResponse = hex.take(10).hexToString() + val depth = depthResponse.drop(4) + AlertMessageDialog.Builder() + .setContext(this@SearchLabelActivity) + .setTitle("温馨提示") + .setMessage("标识器埋深:${depth}厘米") + .setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { +// initSoundResource() +// serialPortManager.detectMarker() + } + }).build().show() + } catch (e: NumberFormatException) { + e.printStackTrace() + } + } else { + if (hex.length >= 20) { + val id = hex.take(20).hexToString() + if (markerId.isNumber()) { + markerId = id + binding.depthButton.isEnabled = true binding.depthButton.setTextColor(Color.WHITE) binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable) @@ -292,21 +245,36 @@ binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green) //自动上传标识器 - taskLabel = DataBaseManager.get.queryTaskLabelByIdAndState(id, "未开始") - if (taskLabel != null) { - val userName = SaveKeyValues.getValue( - LocaleConstant.USER_NAME, "" - ).toString() - taskViewModel.uploadMarker(userName, id) + taskLabel = DataBaseManager.get.queryTaskLabelByIdAndState( + markerId, "未开始" + ) + taskLabel?.apply { + /** + * 此taskCode是 [com.casic.detector.model.TaskModel.MessageModel.TaskDetailInfosModel] 里面的主键,也就是这个标签在数据库里面的主键 + * */ + taskViewModel.uploadMarker(taskCode) } - - this.identifierId = id - } else { - Log.d(kTag, "handleMessage => $id") } } } - return true + } + + private fun initSoundResource() { + /** + * 声音效果速度 + * ling() val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() + val uploadTaskMarkerResult = MutableLiveData() fun createFreeTask(patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { -// freeTaskResult.value = + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { response.getResponseMessage().show(BaseApplication.get()) } @@ -35,18 +39,17 @@ it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: List) = launch({ - loadState.value = LoadState.Loading + fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { - loadState.value = LoadState.Success + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { response.getResponseMessage().show(BaseApplication.get()) - loadState.value = LoadState.Fail } }, { it.printStackTrace() - loadState.value = LoadState.Fail }) fun getMarkerFile(userId: String, companyId: String) = launch({ diff --git a/app/src/main/java/com/casic/detector/base/BaseApplication.kt b/app/src/main/java/com/casic/detector/base/BaseApplication.kt index 30ccb6b..87ef650 100644 --- a/app/src/main/java/com/casic/detector/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/detector/base/BaseApplication.kt @@ -15,21 +15,29 @@ private val kTag = "BaseApplication" private val suffix = "/dev/ttysWK" - private var serialPorts = ArrayList() + private var serialPorts: ArrayList? = null @Throws(SecurityException::class, IOException::class, InvalidParameterException::class) - fun getSerialPorts(): ArrayList { - if (serialPorts.isEmpty()) { - /** - * Open the serial port - * */ - serialPorts.add(SerialPort(File("${suffix}1"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}2"), 9600, 0)) - serialPorts.add(SerialPort(File("${suffix}0"), 9600, 0)) + fun getSerialPorts(): ArrayList? { + serialPorts = ArrayList() + /** + * Open the serial port + * */ + serialPorts?.apply { + add(SerialPort(File("${suffix}1"), 9600, 0)) + add(SerialPort(File("${suffix}2"), 9600, 0)) + add(SerialPort(File("${suffix}0"), 9600, 0)) } return serialPorts } + + fun closeSerialPort() { + serialPorts?.forEach { + it.close() + } + } + companion object { private var application: BaseApplication by Delegates.notNull() @@ -50,11 +58,4 @@ fun getDaoSession(): DaoSession { return daoSession } - - fun closeSerialPort() { - serialPorts.forEach { - it.close() - } - serialPorts.clear() - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/bean/TaskBean.java b/app/src/main/java/com/casic/detector/bean/TaskBean.java index d6e1101..7ada7a5 100644 --- a/app/src/main/java/com/casic/detector/bean/TaskBean.java +++ b/app/src/main/java/com/casic/detector/bean/TaskBean.java @@ -1,5 +1,7 @@ package com.casic.detector.bean; +import com.casic.detector.model.TaskModel; + import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; @@ -12,6 +14,9 @@ private String scanner; private String desc; private String taskId; + /** + * 用 {@link TaskModel.MessageModel.TaskDetailInfosModel#id} 存 + * */ private String taskCode; private String markerId; private String markerRealId; diff --git a/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt new file mode 100644 index 0000000..09203d9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/AMapLocation.kt @@ -0,0 +1,59 @@ +package com.casic.detector.extensions + +import com.amap.api.location.AMapLocation +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.LatLng +import com.casic.detector.model.CalculateResult +import kotlin.math.acos + +/** + * 计算两个经纬度之间连线的方位角,因为距离很近(一般是3米内),球面近似为平面 + * C B + * |-------/ + * | / + * | / + * | / + * | / + * | / + * | / + * |/ + * A + * */ +fun AMapLocation.calculateAngle(target: LatLng): CalculateResult { + //构造直角辅助点 + val auxiliaryPoint = LatLng(target.latitude, this.longitude) + + //AB线段长度 + val distance = AMapUtils.calculateLineDistance( + LatLng(this.latitude, this.longitude), target + ) + + //AC线段长度 + val auxiliaryDistance = AMapUtils.calculateLineDistance( + LatLng(auxiliaryPoint.latitude, auxiliaryPoint.longitude), target + ) + + //求余弦值 + val cosine = auxiliaryDistance / distance + + //反余弦得弧度 + val radian = acos(cosine) + + //弧度转角度,度=弧度×180°/π + val angle = (radian * 180) / Math.PI + + //判断方位 + val direction = if (target.latitude > this.latitude && target.longitude > this.longitude) { + //东北方 + "东偏北" + } else if (target.latitude < this.latitude && target.longitude < this.longitude) { + //西南方 + "西偏南" + } else if (target.latitude > this.latitude && target.longitude < this.longitude) { + //西北方 + "西偏北" + } else { + "东偏南" + } + return CalculateResult(angle.toInt(), direction, distance.toInt()) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/ArrayList.kt b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt new file mode 100644 index 0000000..52f8ac9 --- /dev/null +++ b/app/src/main/java/com/casic/detector/extensions/ArrayList.kt @@ -0,0 +1,20 @@ +package com.casic.detector.extensions + +/** + * ArrayList扩展方法 + */ + +//将集合格式化成满足上传格式的数据 +fun ArrayList.reformat(): String { + if (this.isEmpty()) return "" + val builder = StringBuilder() + //循环遍历元素,同时得到元素index(下标) + this.forEachIndexed { index, s -> + if (index == this.size - 1) { + builder.append(s) + } else { + builder.append(s).append(",") + } + } + return builder.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index b76d83d..785b89f 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -122,4 +122,9 @@ } } return sb.toString() +} + +fun String.isNumber(): Boolean { + val regex = Regex("[-+]?\\d+(\\.\\d+)?") + return this.matches(regex) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java index cab23bb..682c3f8 100644 --- a/app/src/main/java/com/casic/detector/greendao/DaoMaster.java +++ b/app/src/main/java/com/casic/detector/greendao/DaoMaster.java @@ -13,20 +13,25 @@ // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + /** * Master of DAO (schema version 1): knows all DAOs. */ public class DaoMaster extends AbstractDaoMaster { public static final int SCHEMA_VERSION = 1; - /** Creates underlying database table using DAOs. */ + /** + * Creates underlying database table using DAOs. + */ public static void createAllTables(Database db, boolean ifNotExists) { LabelBeanDao.createTable(db, ifNotExists); SmallLabelBeanDao.createTable(db, ifNotExists); TaskBeanDao.createTable(db, ifNotExists); } - /** Drops underlying database table using DAOs. */ + /** + * Drops underlying database table using DAOs. + */ public static void dropAllTables(Database db, boolean ifExists) { LabelBeanDao.dropTable(db, ifExists); SmallLabelBeanDao.dropTable(db, ifExists); @@ -81,7 +86,9 @@ } } - /** WARNING: Drops all table on Upgrade! Use only during development. */ + /** + * WARNING: Drops all table on Upgrade! Use only during development. + */ public static class DevOpenHelper extends OpenHelper { public DevOpenHelper(Context context, String name) { super(context, name); diff --git a/app/src/main/java/com/casic/detector/model/CalculateResult.kt b/app/src/main/java/com/casic/detector/model/CalculateResult.kt new file mode 100644 index 0000000..02cb0a0 --- /dev/null +++ b/app/src/main/java/com/casic/detector/model/CalculateResult.kt @@ -0,0 +1,3 @@ +package com.casic.detector.model + +data class CalculateResult(val angle: Int, val direction: String, val distance: Int) diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 43a8484..cae51d5 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -82,25 +82,21 @@ */ @GET("/ems/rs/task/update-task-mark") suspend fun uploadMarker( - @Query("taskDetailId") taskId: String, + @Query("taskDetailId") taskId: String ): String /** * 新建自由巡检任务 * */ - @GET("") + @GET("ems/rs/task/addAppTask") suspend fun createFreeTask( @Query("patrollerId") patrollerId: String, - @Query("description") description: String, + @Query("description") description: String ): String /** * 上传自由巡检过程中发现的标识器 * */ - @Multipart - @POST("") - suspend fun uploadTaskMarker( - @Field("taskId") taskId: String, - @Body requestBody: RequestBody, - ): String + @POST("ems/event/uploadAppMarker.do") + suspend fun uploadTaskMarker(@Body requestBody: RequestBody): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 8ae0794..ac06760 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -1,9 +1,9 @@ package com.casic.detector.retrofit +import com.casic.detector.extensions.reformat import com.casic.detector.utils.LocaleConstant import com.google.gson.Gson import com.google.gson.JsonObject -import com.google.gson.reflect.TypeToken import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType @@ -16,7 +16,6 @@ object RetrofitServiceManager { private val gson by lazy { Gson() } - private val typeToken = object : TypeToken>() {}.type private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String @@ -233,12 +232,13 @@ /** * 上传自由巡检过程中发现的标识器 */ - suspend fun uploadTaskMarker(taskId: String, models: List): String { + suspend fun uploadTaskMarker(taskId: String, models: ArrayList): String { val param = JsonObject() - param.add("markers", gson.toJsonTree(models, typeToken).asJsonArray) + param.addProperty("taskId", taskId) + param.addProperty("ids", models.reformat()) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return createApi().uploadTaskMarker(taskId, requestBody) + return createApi().uploadTaskMarker(requestBody) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt index 1c7d95b..7e627a4 100644 --- a/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt +++ b/app/src/main/java/com/casic/detector/utils/DataBaseManager.kt @@ -105,7 +105,7 @@ fun queryTaskLabelByIdAndState(identifierId: String, state: String): TaskBean? { return taskBeanDao.queryBuilder() .where( - TaskBeanDao.Properties.MarkerRealId.eq(identifierId), + TaskBeanDao.Properties.MarkerId.eq(identifierId), TaskBeanDao.Properties.State.eq(state) ).list().firstOrNull() } diff --git a/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt b/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt new file mode 100644 index 0000000..c235471 --- /dev/null +++ b/app/src/main/java/com/casic/detector/utils/SerialPortManager.kt @@ -0,0 +1,119 @@ +package com.casic.detector.utils + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.lifecycleScope +import com.casic.detector.base.BaseApplication +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.IOException + +class SerialPortManager(private val listener: OnSerialPortListener) : LifecycleOwner { + + private val kTag = "SerialPortManager" + private val registry = LifecycleRegistry(this) + + init { + //读取串口数据 + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + val buffer = ByteArray(72) + var size: Int + serialPorts?.forEach { + val stream = it.inputStream + while (true) { + try { + size = stream.read(buffer) + if (size > 0) { + withContext(Dispatchers.Main) { + listener.onDataReceived(buffer) + } + } + } catch (e: IOException) { + e.printStackTrace() + return@launch + } + } + } + } + } + + /** + * 探测 + * */ + fun detectMarker() { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + while (size >= 1) { + val outStream = this[0].outputStream + try { + // 发送读标识器ID指令 + outStream?.write('2'.code) + outStream?.flush() + delay(100) + + outStream.write('6'.code) + outStream.flush() + delay(100) + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + } + + /** + * 发送探测深度指令 + * */ + fun detectDepth(markerTag: Char) { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + val outStream = this[0].outputStream + try { + // 发送测距指令 + outStream?.write(markerTag.code) + outStream?.flush() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + + /** + * 发送读标识器ID指令 + * */ + fun searchMarkerSignal() { + lifecycleScope.launch(Dispatchers.IO) { + val serialPorts = BaseApplication.get().getSerialPorts() + serialPorts?.apply { + val outStream = this[0].outputStream + try { + // 发送读标识器ID指令 + outStream?.write('2'.code) + outStream?.flush() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + } + + fun closeSerialPort() { + BaseApplication.get().closeSerialPort() + } + + interface OnSerialPortListener { + fun onDataReceived(buffer: ByteArray) + } + + override fun getLifecycle(): Lifecycle { + return registry + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index 68d54b2..5bac324 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -2,16 +2,12 @@ import android.annotation.SuppressLint import android.app.DatePickerDialog -import android.content.Context import android.content.DialogInterface import android.content.Intent import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle -import android.os.Handler -import android.os.Message import android.provider.Settings -import android.util.Log import android.view.KeyEvent import android.view.View import android.view.WindowManager @@ -19,7 +15,6 @@ import com.amap.api.location.AMapLocation import com.casic.detector.R import com.casic.detector.adapter.EditableImageAdapter -import com.casic.detector.base.SerialPortActivity import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener @@ -31,29 +26,39 @@ 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.* +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.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.LoadState import com.pengxh.kt.lite.utils.SaveKeyValues -import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import java.io.File -import java.io.IOException import java.util.* @SuppressLint("SetTextI18n") -class InstallLabelActivity : SerialPortActivity(), Handler.Callback { +class InstallLabelActivity : KotlinBaseActivity(), + SerialPortManager.OnSerialPortListener { private val kTag = "InstallLabelActivity" - private val context: Context = this@InstallLabelActivity + private val context = this@InstallLabelActivity + private val serialPortManager by lazy { SerialPortManager(this) } private val calendar by lazy { Calendar.getInstance() } - private lateinit var imageAdapter: EditableImageAdapter - private val realPaths: ArrayList = ArrayList() //真实图片路径 - private lateinit var taskViewModel: TaskViewModel - private lateinit var soundPool: SoundPool - private var soundResId = 0 - private val gpioManager by lazy { GpioManager() } + private val audioAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ALARM) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + private val realPaths = ArrayList() //真实图片路径 private val locationHub by lazy { LocationHub(this) } - private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var imageAdapter: EditableImageAdapter + private lateinit var taskViewModel: TaskViewModel + private var soundPool: SoundPool? = null override fun initViewBinding(): ActivityInstallLabelBinding { return ActivityInstallLabelBinding.inflate(layoutInflater) @@ -79,13 +84,6 @@ binding.objectInclude.ownerView.setText("ownerView".getDefaultValue()) binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue()) binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue()) - - weakReferenceHandler = WeakReferenceHandler(this) - - val audioAttributes = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA) - .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() - soundPool = - SoundPool.Builder().setMaxStreams(16).setAudioAttributes(audioAttributes).build() } override fun initEvent() { @@ -247,6 +245,14 @@ return@setOnClickListener } + //查本地库 + val markerId = binding.identifierInclude.identifierIdView.text.toString() + val result = DataBaseManager.get.queryLabelById(markerId) + if (result.isEmpty()) { + "".show(this) + return@setOnClickListener + } + //先存本地再上传服务器 saveLabelInLocal() @@ -268,7 +274,7 @@ binding.objectInclude.constructDateView.text.toString(), binding.objectInclude.ownerView.text.toString(), objectId, - binding.identifierInclude.identifierIdView.text.toString(), + markerId, binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(), "${binding.identifierInclude.identifierDeepView.text}mm", binding.identifierInclude.personDeptView.text.toString(), @@ -305,25 +311,35 @@ } binding.readLabelButton.setOnClickListener { - gpioManager.setGpioHigh("18") - LoadingDialogHub.show(this, "标识器读取中,请稍后...") - soundResId = soundPool.load(this, R.raw.ring3, 1) - soundPool.setOnLoadCompleteListener { soundPool, _, _ -> - soundPool.play(soundResId, 1f, 1f, 0, -1, 1f) + soundPool = SoundPool.Builder() + .setMaxStreams(16) + .setAudioAttributes(audioAttributes) + .build() + soundPool?.apply { + val soundResId = load(context, R.raw.ring3, 1) + setOnLoadCompleteListener { soundPool, _, _ -> + soundPool.play(soundResId, 1f, 1f, 0, -1, 1f) + } } - // 1000ms后发送读标识器或搜索信号 - weakReferenceHandler.postDelayed({ - try { - // 发送读标识器或搜索信号 - outStream?.write("2".toByteArray()) - outStream?.flush() - } catch (e: IOException) { - e.printStackTrace() - } - }, 1000) + serialPortManager.searchMarkerSignal() + } + } + + override fun onDataReceived(buffer: ByteArray) { + LoadingDialogHub.dismiss() + soundPool?.release() + + val hex = buffer.toHex() +// Log.d(kTag, "$kTag => $hex") + if (hex.length >= 20) { + val markerId = hex.take(20).hexToString() + if (markerId.isNumber()) { + binding.identifierInclude.identifierIdView.text = markerId + serialPortManager.closeSerialPort() + } } } @@ -363,41 +379,6 @@ DataBaseManager.get.insertTaskLabel(labelBean) } - override fun onDataReceived(buffer: ByteArray?, size: Int) { - Log.d(kTag, "onDataReceived => " + buffer.contentToString()) - if (buffer != null) { - val message = weakReferenceHandler.obtainMessage() - message.what = 2023061601 - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } - } - - override fun handleMessage(msg: Message): Boolean { - if (msg.what == 2023061601) { - soundPool.release() - - val buffer = msg.obj as ByteArray - val hex = buffer.toHex() - //3030303839383735313400000000000000000000000000000000000000000000 - if (hex.length >= 20) { - val identifierId = hex.substring(0, 20).hexToString() - - gpioManager.setGpioLow("18") - - //查本地库 - val result = DataBaseManager.get.queryLabelById(identifierId) - if (result.isEmpty()) { - binding.identifierInclude.identifierIdView.text = identifierId - } else { - "此标识器已安装,请更换标识器!".show(this) - } - LoadingDialogHub.dismiss() - } - } - return true - } - private fun takePicture() { PictureSelector.create(this).openCamera(SelectMimeType.ofImage()) .forResult(object : OnResultCallbackListener { @@ -451,14 +432,14 @@ } override fun onDestroy() { - soundPool.release() - gpioManager.setGpioLow("18") super.onDestroy() + soundPool?.release() + locationHub.stopLocation() } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { if (keyCode == KeyEvent.KEYCODE_BACK) { - soundPool.release() + soundPool?.release() } return super.onKeyDown(keyCode, event) } diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index d590626..7c6446a 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -1,17 +1,19 @@ package com.casic.detector.view -import android.content.Context import android.content.Intent import android.graphics.BitmapFactory import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.media.AudioAttributes +import android.media.SoundPool import android.os.Bundle -import android.os.PowerManager import android.provider.Settings import android.util.Log import android.view.KeyEvent +import android.view.View 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 @@ -32,81 +34,89 @@ import com.casic.detector.databinding.ActivityMainBinding import com.casic.detector.extensions.appendDownloadUrl import com.casic.detector.extensions.drawCircle -import com.casic.detector.extensions.initLayoutImmersionBar +import com.casic.detector.extensions.hexToString +import com.casic.detector.extensions.initImmersionBar +import com.casic.detector.extensions.isNumber +import com.casic.detector.extensions.toHex import com.casic.detector.model.TaskModel import com.casic.detector.utils.DataBaseManager import com.casic.detector.utils.ExcelHub import com.casic.detector.utils.FileType +import com.casic.detector.utils.GpioManager import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub import com.casic.detector.utils.RouteOnMap +import com.casic.detector.utils.SerialPortManager import com.casic.detector.vm.TaskViewModel import com.casic.detector.widgets.QueryMarkerDialog import com.casic.detector.widgets.SamplePopupWindow import com.google.gson.Gson import com.google.gson.reflect.TypeToken -import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.callback.OnDownloadListener +import com.pengxh.kt.lite.extensions.convertDrawable import com.pengxh.kt.lite.extensions.createDownloadFileDir -import com.pengxh.kt.lite.extensions.downloadFile import com.pengxh.kt.lite.extensions.dp2px 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.toJson +import com.pengxh.kt.lite.utils.FileDownloadManager +import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.SaveKeyValues -import com.pengxh.kt.lite.vm.LoadState import com.pengxh.kt.lite.widget.dialog.AlertControlDialog +import com.pengxh.kt.lite.widget.dialog.AlertInputDialog import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog import com.pengxh.kt.lite.widget.dialog.BottomActionSheet import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File -class MainActivity : KotlinBaseActivity() { +class MainActivity : KotlinBaseActivity(), + SerialPortManager.OnSerialPortListener { private val kTag = "MainActivity" - private val context: Context = this@MainActivity - private var clickTime: Long = 0 - private lateinit var aMap: AMap - private lateinit var taskViewModel: TaskViewModel + private val context = this@MainActivity + private val serialPortManager by lazy { SerialPortManager(this) } + private val gpioManager by lazy { GpioManager() } private val samplePopupWindow by lazy { SamplePopupWindow(this) } + private val gson by lazy { Gson() } + private val locationHub by lazy { LocationHub(this) } + private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } + private val backDrawables by lazy { HashMap() } + private val audioAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ALARM) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + private var clickTime: Long = 0 private var labelBeans = ArrayList() private var clusterOverlay: ClusterOverlay? = null - private val backDrawables = HashMap() - private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) } private var latitude: Double = 0.0 private var longitude: Double = 0.0 - private val gson by lazy { Gson() } - private val locationHub by lazy { LocationHub.obtainInstance(this) } - private lateinit var wakeLock: PowerManager.WakeLock + private var ids = ArrayList() + private lateinit var aMap: AMap + private lateinit var soundPool: SoundPool + private lateinit var taskViewModel: TaskViewModel private lateinit var taskBean: TaskBean + private lateinit var taskId: String override fun initViewBinding(): ActivityMainBinding { return ActivityMainBinding.inflate(layoutInflater) } override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).statusBarColor(R.color.themeColor).init() - initLayoutImmersionBar(binding.rootView) + binding.rootView.initImmersionBar(this, false, R.color.themeColor) } override fun initOnCreate(savedInstanceState: Bundle?) { - val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager - wakeLock = powerManager.run { - newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this@MainActivity.localClassName).apply { - acquire(60 * 60 * 1000L) - } - } - initMapConfig(savedInstanceState) + //调高串口电位 + gpioManager.setGpioHigh("18") + samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -119,12 +129,14 @@ val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) Log.d(kTag, "downloadUrl => $downloadUrl") - downloadUrl.downloadFile( - createDownloadFileDir().toString(), - object : OnDownloadListener { - override fun onDownloadEnd(file: File?) { - CoroutineScope(Dispatchers.Main).launch { - labelBeans = ExcelHub.read(file?.absolutePath) + FileDownloadManager.Builder() + .setDownloadFileSource(downloadUrl) + .setFileSuffix("xls") + .setFileSaveDirectory(createDownloadFileDir()) + .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadEnd(file: File) { + lifecycleScope.launch(Dispatchers.Main) { + labelBeans = ExcelHub.read(file.absolutePath) withContext(Dispatchers.IO) { labelBeans.forEach { label -> DataBaseManager.get.insertTaskLabel(label) @@ -135,14 +147,16 @@ } } - override fun onDownloadStart(totalBytes: Long) { + override fun onFailure(throwable: Throwable) { } - override fun onProgressChanged(currentBytes: Long) { + override fun onProgressChanged(progress: Int) { } }) + .build() + .start() } } taskViewModel.taskResult.observe(this) { @@ -159,19 +173,26 @@ }).build().show() } } + + taskViewModel.freeTaskResult.observe(this) { taskId = it } + + taskViewModel.uploadTaskMarkerResult.observe(this) { + "自由巡检任务已完成".show(this) + ids.clear() + } } override fun initEvent() { binding.rightImageView.setOnClickListener { - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { val labels = withContext(Dispatchers.IO) { DataBaseManager.get.queryLabelById("0") } if (labels.isNotEmpty()) { samplePopupWindow.setShowPosition(4) } - val x = binding.rightImageView.width - samplePopupWindow.width - 1f.dp2px(context) - samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1f.dp2px(context)) + val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context) + samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context)) } } @@ -201,7 +222,7 @@ QueryMarkerDialog.OnDialogButtonClickListener { override fun onConfirmClick(selectedItem: String, value: String) { //查询数据库 - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadLabelByCondition( selectedItem, value @@ -282,12 +303,14 @@ } }).build().show() } else { - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") - .setMessage("现有任务已完成,请点击右上角菜单按钮下载新工单!") - .setPositiveButton("知道了").setOnDialogButtonClickListener(object : + AlertMessageDialog.Builder() + .setContext(this) + .setTitle("温馨提示") + .setMessage("现有任务已完成,请点击右上角菜单下载新工单或者开始自由巡检") + .setPositiveButton("开始自由巡检").setOnDialogButtonClickListener(object : AlertMessageDialog.OnDialogButtonClickListener { override fun onConfirmClick() { - + startFreeTask() } }).build().show() } @@ -297,6 +320,69 @@ binding.detectionButton.setOnClickListener { navigatePageTo() } + + //自由巡检 + binding.stopFreeTaskButton.setOnLongClickListener { + AlertMessageDialog.Builder() + .setContext(this) + .setTitle("温馨提示") + .setMessage("是否确定结束此次自由巡检任务?") + .setPositiveButton("是") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + soundPool.release() + serialPortManager.closeSerialPort() + + taskViewModel.uploadTaskMarker(taskId, ids) + binding.stopFreeTaskButton.visibility = View.GONE + } + }).build().show() + true + } + } + + private fun startFreeTask() { + AlertInputDialog.Builder() + .setContext(this) + .setTitle("新建自由巡检任务") + .setHintMessage("请输入自由巡检任务简要描述") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener { + override fun onConfirmClick(value: String) { + val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String + taskViewModel.createFreeTask(userId, value) + + soundPool = SoundPool.Builder() + .setMaxStreams(16) + .setAudioAttributes(audioAttributes) + .build() + soundPool.load(context, R.raw.ring3, 1) + soundPool.setOnLoadCompleteListener { soundPool, sampleId, _ -> + soundPool.play(sampleId, 1f, 1f, 0, -1, 1f) + } + + //自由巡检 + serialPortManager.searchMarkerSignal() + + binding.stopFreeTaskButton.visibility = View.VISIBLE + } + + override fun onCancelClick() {} + }).build().show() + } + + override fun onDataReceived(buffer: ByteArray) { + val hex = buffer.toHex() +// Log.d(kTag, "$kTag => $hex") + if (hex.length >= 20) { + val markerId = hex.take(20).hexToString() + if (markerId.isNumber()) { + "标识器${markerId}已探测".show(this) + ids.add(markerId) + } + } } override fun observeRequestState() { @@ -342,7 +428,7 @@ aMap.setOnMapLongClickListener { //协程异步显示默认数据 - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadTaskLabels() as ArrayList } @@ -381,7 +467,7 @@ userName, messageModel.description, info.taskId.toString(), - info.taskCode.toString(), + info.id.toString(), info.markerId.toString(), info.markerIdReal.toString(), info.longitude.toString(), @@ -412,7 +498,7 @@ clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius) clusterOverlay?.setClusterRender { clusterNum -> - val radius = 80f.dp2px(context) + val radius = 80.dp2px(context) if (clusterNum == 0) { var bitmapDrawable = backDrawables[0] if (bitmapDrawable == null) { @@ -426,7 +512,7 @@ if (clusterNum == 1) { var bitmapDrawable = backDrawables[1] if (bitmapDrawable == null) { - bitmapDrawable = resources.getDrawable(R.mipmap.label) + bitmapDrawable = R.mipmap.label.convertDrawable(this)!! backDrawables[1] = bitmapDrawable } bitmapDrawable @@ -478,9 +564,13 @@ val latLngBounds = builder.build() aMap.animateCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds, 0)) - AlertControlDialog.Builder().setContext(this).setTitle("提示") - .setMessage("请选择操作方式").setNegativeButton("标识器信息") - .setPositiveButton("到这里去").setOnDialogButtonClickListener(object : + AlertControlDialog.Builder() + .setContext(this) + .setTitle("提示") + .setMessage("请选择操作方式") + .setNegativeButton("标识器信息") + .setPositiveButton("到这里去") + .setOnDialogButtonClickListener(object : AlertControlDialog.OnDialogButtonClickListener { override fun onConfirmClick() { RouteOnMap.startNavigation(context, item.title, latLng) @@ -510,13 +600,13 @@ BitmapDescriptorFactory.fromBitmap( BitmapFactory.decodeResource(resources, R.mipmap.label_red1) ) - ).period(99).title("工单标识器").snippet(it.markerRealId) + ).period(99).title("工单标识器").snippet(it.markerId) } else { otMarkerOptions.icon( BitmapDescriptorFactory.fromBitmap( BitmapFactory.decodeResource(resources, R.mipmap.label_blue1) ) - ).period(99).title("工单标识器").snippet(it.markerRealId) + ).period(99).title("工单标识器").snippet(it.markerId) } aMap.addMarker(otMarkerOptions) } @@ -665,7 +755,7 @@ super.onResume() binding.mapView.onResume() //协程异步显示默认数据 - CoroutineScope(Dispatchers.Main).launch { + lifecycleScope.launch(Dispatchers.Main) { labelBeans = withContext(Dispatchers.IO) { DataBaseManager.get.loadTaskLabels() as ArrayList } @@ -684,8 +774,10 @@ } override fun onDestroy() { - wakeLock.release() super.onDestroy() binding.mapView.onDestroy() + locationHub.stopLocation() + //降低串口电位 + gpioManager.setGpioLow("18") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/SearchLabelActivity.kt b/app/src/main/java/com/casic/detector/view/SearchLabelActivity.kt index dcf39b4..426aed3 100644 --- a/app/src/main/java/com/casic/detector/view/SearchLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/SearchLabelActivity.kt @@ -4,80 +4,59 @@ import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle -import android.os.Handler -import android.os.Message -import android.util.Log +import android.os.CountDownTimer import android.view.animation.Animation import android.view.animation.RotateAnimation +import androidx.activity.OnBackPressedCallback import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope import com.casic.detector.R -import com.casic.detector.base.SerialPortActivity import com.casic.detector.bean.TaskBean import com.casic.detector.databinding.ActivitySearchLabelBinding import com.casic.detector.extensions.hexToString +import com.casic.detector.extensions.isNumber import com.casic.detector.extensions.toHex import com.casic.detector.utils.DataBaseManager -import com.casic.detector.utils.GpioManager import com.casic.detector.utils.LoadingDialogHub -import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub +import com.casic.detector.utils.SerialPortManager import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.base.KotlinBaseActivity 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.LoadState -import com.pengxh.kt.lite.utils.SaveKeyValues -import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import java.io.IOException import java.text.DecimalFormat -import java.util.Timer -import java.util.TimerTask -class SearchLabelActivity : SerialPortActivity(), Handler.Callback { +class SearchLabelActivity : KotlinBaseActivity(), + SerialPortManager.OnSerialPortListener { private val kTag = "SearchLabelActivity" + private val serialPortManager by lazy { SerialPortManager(this) } + private val decimal by lazy { DecimalFormat("0.0") } + private val degreeCache by lazy { HashMap() } + private val locationHub by lazy { LocationHub(this) } + private val audioAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + private lateinit var taskViewModel: TaskViewModel private lateinit var slowSoundPool: SoundPool private lateinit var fastSoundPool: SoundPool private var slowResId = 0 private var fastResId = 0 - private val gpioManager by lazy { GpioManager() } - private val weakReferenceHandler by lazy { WeakReferenceHandler(this) } - private val detectTimer by lazy { Timer() } - private val decimal by lazy { DecimalFormat("0.0") } - private var identifierId = "" - private val lastDegreeMap by lazy { HashMap() } - private val locationHub by lazy { LocationHub(this) } - private var isPlaying = false - private var isDetectDepth = false - private lateinit var taskViewModel: TaskViewModel + private var markerId = "" private var taskLabel: TaskBean? = null - private val dataReceivedCode = 2023110301 + private var isPlaying = false override fun initOnCreate(savedInstanceState: Bundle?) { - gpioManager.setGpioHigh("18") - //角度 - lastDegreeMap["lastDegree"] = 0f + initSoundResource() + serialPortManager.detectMarker() + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] - - val audioAttributes = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA) - .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() - /** - * 声音效果速度 - * ling '7' @@ -137,149 +93,146 @@ } else { // 发送读取标识器埋设深度指令 LoadingDialogHub.show(this, "正在测距,请稍后...") - try { - outStream?.write(tag.code) - outStream?.flush() - } catch (e: IOException) { - e.printStackTrace() - } + serialPortManager.detectDepth(tag) + object : CountDownTimer(15 * 1000, 1000) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + LoadingDialogHub.dismiss() + "请重试".show(this@SearchLabelActivity) +// initSoundResource() +// serialPortManager.detectMarker() + } + }.start() } } else { - "标识器未安装,安装成功后即可读取埋深!".show(this) + "标识器未安装,安装成功后才可读取埋深!".show(this) } } binding.markerInfoButton.setOnClickListener { //查库 - val result = DataBaseManager.get.queryLabelById(identifierId) + val result = DataBaseManager.get.queryLabelById(markerId) if (result.isNotEmpty()) { navigatePageTo(result.first().toJson()) } else { - navigatePageTo(identifierId) + navigatePageTo(markerId) } } + + //返回键监听,替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + slowSoundPool.release() + fastSoundPool.release() + serialPortManager.closeSerialPort() + finish() + } + }) } - override fun onDataReceived(buffer: ByteArray?, size: Int) { - val message = weakReferenceHandler.obtainMessage() - message.what = dataReceivedCode - message.obj = buffer - weakReferenceHandler.sendMessage(message) - } - - override fun handleMessage(msg: Message): Boolean { - if (msg.what == dataReceivedCode) { - val buffer = msg.obj as ByteArray - val hex = buffer.toHex() - - //能量强度 - //4E30363634000000000000000000000000000000000000000000000000000000 - - //ID - //3030303839383735313400000000000000000000000000000000000000000000 - - //埋深 - //5330303736000000000000000000000000000000000000000000000000000000 - if (hex.startsWith("4E")) { - try { - //4E转为String为N,代表能量值 - //用能量值转动表盘 - val energyResponse = hex.substring(0, 10).hexToString() - //去掉前缀并缩小100倍 - var energy = energyResponse.substring(1).toInt() / 100 - if (energy >= 50) { - //测试过程最大值(5189)---> 5200 - energy = 50 + override fun onDataReceived(buffer: ByteArray) { + val hex = buffer.toHex() +// Log.d(kTag, "$kTag => $hex") + if (hex.startsWith("4E")) { + try { + //4E转为String为N,代表能量值 + //用能量值转动表盘 + val energyResponse = hex.take(10).hexToString() + val energy = energyResponse.substring(1).toInt() + if (energy >= 4000) { + isPlaying = if (!isPlaying) { + fastSoundPool.play(fastResId, 1f, 1f, 0, 0, 1f) + true + } else { + fastSoundPool.stop(fastResId) + false } + } else { + isPlaying = if (!isPlaying) { + slowSoundPool.play(slowResId, 1f, 1f, 0, 0, 1f) + true + } else { + slowSoundPool.stop(slowResId) + false + } + } - binding.resultTextView.text = "信号能量值:${energyResponse}" + binding.resultTextView.text = "信号能量值:${energyResponse}" - //转换为转动的角度 - val degree = (energy.toFloat() / 50) * 180 - binding.energyValueView.text = decimal.format(degree) + //转换为转动的角度 + val degree = (energy.toFloat() / (50 * 100)) * 180 + binding.energyValueView.text = decimal.format(degree) + degreeCache["lastDegree"]?.apply { val animation = RotateAnimation( - lastDegreeMap["lastDegree"]!!, - degree, - Animation.RELATIVE_TO_SELF, - 0.5f, - Animation.RELATIVE_TO_SELF, - 0.5f + this, degree, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f ) animation.duration = 0 animation.fillAfter = true binding.needleView.startAnimation(animation) - - //保存旋转后的角度 - lastDegreeMap["lastDegree"] = degree - - if (energy >= 41) { - isPlaying = if (!isPlaying) { - fastSoundPool.play(fastResId, 1f, 1f, 0, 0, 1f) - true - } else { - fastSoundPool.stop(fastResId) - false - } - } else { - isPlaying = if (!isPlaying) { - slowSoundPool.play(slowResId, 1f, 1f, 0, 0, 1f) - true - } else { - slowSoundPool.stop(slowResId) - false - } - } - - if (energy <= 7) {//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 >= 41) {//148° - binding.energyTipsView.text = "标识器信号极强,可能在正下方" - binding.energyTipsView.setTextColor(Color.parseColor("#428d00")) - binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green) - } else {//[18°,148°] - 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")) { - try { - LoadingDialogHub.dismiss() - //53转为String为S,代表深度 - val depthResponse = hex.substring(0, 10).hexToString() - val depth = depthResponse.substring(1).toInt() - AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示") - .setMessage("标识器埋深:${depth}厘米").setPositiveButton("知道了") - .setOnDialogButtonClickListener(object : - AlertMessageDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - isDetectDepth = false - } - }).build().show() - } catch (e: NumberFormatException) { - e.printStackTrace() + + //保存旋转后的角度 + degreeCache["lastDegree"] = degree + + 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) {//148° + binding.energyTipsView.text = "标识器信号极强,可能在正下方" + binding.energyTipsView.setTextColor(Color.parseColor("#428d00")) + binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green) + } else {//[18°,148°] + binding.energyTipsView.text = "已靠近标识器,请继续移动位置" + binding.energyTipsView.setTextColor(Color.parseColor("#8C5700")) + binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow) } - } else { - val id = hex.substring(0, 20).hexToString() - val regex = "^[a-z0-9A-Z]+$" - if (id.matches(Regex(regex))) { + } catch (e: NumberFormatException) { + e.printStackTrace() + } + } else if (hex.startsWith("53")) { + LoadingDialogHub.dismiss() + try { + val depthResponse = hex.take(10).hexToString() + val depth = depthResponse.drop(4) + AlertMessageDialog.Builder() + .setContext(this@SearchLabelActivity) + .setTitle("温馨提示") + .setMessage("标识器埋深:${depth}厘米") + .setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { +// initSoundResource() +// serialPortManager.detectMarker() + } + }).build().show() + } catch (e: NumberFormatException) { + e.printStackTrace() + } + } else { + if (hex.length >= 20) { + val id = hex.take(20).hexToString() + if (markerId.isNumber()) { + markerId = id + binding.depthButton.isEnabled = true binding.depthButton.setTextColor(Color.WHITE) binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable) @@ -292,21 +245,36 @@ binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green) //自动上传标识器 - taskLabel = DataBaseManager.get.queryTaskLabelByIdAndState(id, "未开始") - if (taskLabel != null) { - val userName = SaveKeyValues.getValue( - LocaleConstant.USER_NAME, "" - ).toString() - taskViewModel.uploadMarker(userName, id) + taskLabel = DataBaseManager.get.queryTaskLabelByIdAndState( + markerId, "未开始" + ) + taskLabel?.apply { + /** + * 此taskCode是 [com.casic.detector.model.TaskModel.MessageModel.TaskDetailInfosModel] 里面的主键,也就是这个标签在数据库里面的主键 + * */ + taskViewModel.uploadMarker(taskCode) } - - this.identifierId = id - } else { - Log.d(kTag, "handleMessage => $id") } } } - return true + } + + private fun initSoundResource() { + /** + * 声音效果速度 + * ling() val taskResult = MutableLiveData() val freeTaskResult = MutableLiveData() + val uploadTaskMarkerResult = MutableLiveData() fun createFreeTask(patrollerId: String, description: String) = launch({ val response = RetrofitServiceManager.createFreeTask(patrollerId, description) if (response.getResponseState()) { -// freeTaskResult.value = + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + freeTaskResult.value = jsonObject.get("taskId").asInt.toString() } else { response.getResponseMessage().show(BaseApplication.get()) } @@ -35,18 +39,17 @@ it.printStackTrace() }) - fun uploadTaskMarker(taskId: String, models: List) = launch({ - loadState.value = LoadState.Loading + fun uploadTaskMarker(taskId: String, models: ArrayList) = launch({ val response = RetrofitServiceManager.uploadTaskMarker(taskId, models) if (response.getResponseState()) { - loadState.value = LoadState.Success + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + uploadTaskMarkerResult.value = jsonObject.get("success").asString } else { response.getResponseMessage().show(BaseApplication.get()) - loadState.value = LoadState.Fail } }, { it.printStackTrace() - loadState.value = LoadState.Fail }) fun getMarkerFile(userId: String, companyId: String) = launch({ diff --git a/app/src/main/res/layout/activity_search_label.xml b/app/src/main/res/layout/activity_search_label.xml index 52d761a..ef54017 100644 --- a/app/src/main/res/layout/activity_search_label.xml +++ b/app/src/main/res/layout/activity_search_label.xml @@ -119,4 +119,17 @@ android:textColor="#CCCCCC" android:textSize="@dimen/sp_22" /> + + \ No newline at end of file