diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt index 62af5a5..3e2703d 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt @@ -1,6 +1,5 @@ package com.casic.common.detector.gd.view -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -22,7 +21,6 @@ class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" - private val context: Context = this private lateinit var marker: MarkerLocalBean override fun initViewBinding(): ActivityObjectDetailBinding { @@ -86,7 +84,7 @@ binding.showImageView.setOnClickListener { //查数据库 if (marker.imagePath.isNullOrEmpty()) { - "此标识器无图片".show(context) + "此标识器无图片".show(this) } else { val realPaths: ArrayList = ArrayList() //真实图片路径 @@ -97,12 +95,12 @@ if (imagePath.contains(",")) { val list = imagePath.split(",") list.forEach { path -> - val url = path.appendDownloadUrl(FileType.IMAGE) + val url = path.appendDownloadUrl(FileType.Image) realPaths.add(url) } } else { //只有一张图片 - val url = imagePath.appendDownloadUrl(FileType.IMAGE) + val url = imagePath.appendDownloadUrl(FileType.Image) realPaths.add(url) } navigatePageTo(0, realPaths) diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt index 62af5a5..3e2703d 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt @@ -1,6 +1,5 @@ package com.casic.common.detector.gd.view -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -22,7 +21,6 @@ class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" - private val context: Context = this private lateinit var marker: MarkerLocalBean override fun initViewBinding(): ActivityObjectDetailBinding { @@ -86,7 +84,7 @@ binding.showImageView.setOnClickListener { //查数据库 if (marker.imagePath.isNullOrEmpty()) { - "此标识器无图片".show(context) + "此标识器无图片".show(this) } else { val realPaths: ArrayList = ArrayList() //真实图片路径 @@ -97,12 +95,12 @@ if (imagePath.contains(",")) { val list = imagePath.split(",") list.forEach { path -> - val url = path.appendDownloadUrl(FileType.IMAGE) + val url = path.appendDownloadUrl(FileType.Image) realPaths.add(url) } } else { //只有一张图片 - val url = imagePath.appendDownloadUrl(FileType.IMAGE) + val url = imagePath.appendDownloadUrl(FileType.Image) realPaths.add(url) } navigatePageTo(0, realPaths) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt index 94e6c46..9f2d5cd 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt @@ -51,8 +51,8 @@ window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) window.decorView.setBackgroundColor(Color.TRANSPARENT) val params = window.attributes - params.width = (getScreenWidth() * 0.965).roundToInt() - params.height = (getScreenHeight() * 0.775).roundToInt() + params.width = (getScreenWidth() * 0.97).roundToInt() + params.height = (getScreenHeight() * 0.75).roundToInt() window.attributes = params if (ActivityCompat.checkSelfPermission( diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt index 62af5a5..3e2703d 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt @@ -1,6 +1,5 @@ package com.casic.common.detector.gd.view -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -22,7 +21,6 @@ class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" - private val context: Context = this private lateinit var marker: MarkerLocalBean override fun initViewBinding(): ActivityObjectDetailBinding { @@ -86,7 +84,7 @@ binding.showImageView.setOnClickListener { //查数据库 if (marker.imagePath.isNullOrEmpty()) { - "此标识器无图片".show(context) + "此标识器无图片".show(this) } else { val realPaths: ArrayList = ArrayList() //真实图片路径 @@ -97,12 +95,12 @@ if (imagePath.contains(",")) { val list = imagePath.split(",") list.forEach { path -> - val url = path.appendDownloadUrl(FileType.IMAGE) + val url = path.appendDownloadUrl(FileType.Image) realPaths.add(url) } } else { //只有一张图片 - val url = imagePath.appendDownloadUrl(FileType.IMAGE) + val url = imagePath.appendDownloadUrl(FileType.Image) realPaths.add(url) } navigatePageTo(0, realPaths) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt index 94e6c46..9f2d5cd 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt @@ -51,8 +51,8 @@ window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) window.decorView.setBackgroundColor(Color.TRANSPARENT) val params = window.attributes - params.width = (getScreenWidth() * 0.965).roundToInt() - params.height = (getScreenHeight() * 0.775).roundToInt() + params.width = (getScreenWidth() * 0.97).roundToInt() + params.height = (getScreenHeight() * 0.75).roundToInt() window.attributes = params if (ActivityCompat.checkSelfPermission( diff --git a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt index f4aadf8..ddc5a32 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt @@ -1,11 +1,11 @@ package com.casic.common.detector.gd.view -import android.app.ProgressDialog +import android.content.ActivityNotFoundException +import android.content.ClipData import android.content.Intent -import android.net.Uri -import android.os.Build import android.os.Bundle import android.util.Log +import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import androidx.lifecycle.ViewModelProvider import com.casic.common.detector.gd.BuildConfig @@ -13,13 +13,13 @@ import com.casic.common.detector.gd.databinding.ActivityVersionControlBinding import com.casic.common.detector.gd.extensions.appendDownloadUrl import com.casic.common.detector.gd.extensions.initImmersionBar +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType -import com.casic.common.detector.gd.utils.LocaleConstant import com.casic.common.detector.gd.vm.VersionViewModel +import com.casic.common.detector.gd.widgets.ProgressDialog import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.createDownloadFileDir import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.TitleBarView @@ -29,19 +29,11 @@ class VersionControlActivity : KotlinBaseActivity() { private val kTag = "VersionControlActivity" - private val progressDialog by lazy { ProgressDialog(this) } private lateinit var versionViewModel: VersionViewModel override fun initOnCreate(savedInstanceState: Bundle?) { binding.versionView.text = "Version ${BuildConfig.VERSION_NAME}" - //初始化下载对话框 - progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) - progressDialog.setProgressDrawable(resources.getDrawable(R.drawable.download_progress)) - progressDialog.setCanceledOnTouchOutside(false) - progressDialog.setCancelable(false) - progressDialog.max = 0 - versionViewModel = ViewModelProvider(this)[VersionViewModel::class.java] versionViewModel.versionResult.observe(this) { if (it.version.toInt() > BuildConfig.VERSION_CODE) { @@ -101,60 +93,57 @@ } private fun downloadApk(url: String?) { - progressDialog.setMessage("下载新版本中...") - progressDialog.show() - if (url.toString().isBlank()) { - "抱歉,版本下载失败".show(this) + if (url.isNullOrBlank()) { + "下载路径为空,版本下载失败".show(this) return } + val progressDialog = ProgressDialog(this) + progressDialog.show() /** * http://139.198.18.188:8090/ems/apk/EMSCJTX202011052026(V3.14.0).apk * */ - val downloadPath = url!!.appendDownloadUrl(FileType.APK) + val downloadPath = url.appendDownloadUrl(FileType.Apk) Log.d(kTag, "downloadApk => $downloadPath") - //开始下载 FileDownloadManager.Builder() .setDownloadFileSource(downloadPath) .setFileSuffix("apk") .setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + progressDialog.setMaxProgress(total) + } + override fun onDownloadEnd(file: File) { progressDialog.dismiss() - progressDialog.progress = 0 - //安装APK installApk(file) } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() + progressDialog.dismiss() } - override fun onProgressChanged(progress: Int) { - progressDialog.progress = progress + override fun onProgressChanged(progress: Long) { + progressDialog.updateProgress(progress) } - }) - .build() - .start() + }).build().start() } - private fun installApk(apkPackage: File?) { - if (apkPackage == null) { - "安装文件异常,无法安装".show(this) - return + private fun installApk(file: File) { + val apkUri = FileProvider.getUriForFile(this, "${packageName}.provider", file) + val mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension("apk") ?: "application/vnd.android.package-archive" + val intent = Intent(Intent.ACTION_VIEW).apply { + setDataAndType(apkUri, mimeType) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) + // 授予持久化 URI 权限 + clipData = ClipData.newRawUri("", apkUri) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) } - val intent = Intent(Intent.ACTION_VIEW) - val data: Uri - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //判断版本大于等于7.0 - data = FileProvider.getUriForFile(this, LocaleConstant.APP_AUTHORITY, apkPackage) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 给目标应用一个临时授权 - } else { - data = Uri.fromFile(apkPackage) + try { + this.startActivity(intent) + } catch (e: ActivityNotFoundException) { + e.printStackTrace() } - /** - * android 10 - * content://com.casic.app.smartwell.fileprovider/smartWell/Download/1.0.1.apk - * */ - intent.setDataAndType(data, "application/vnd.android.package-archive") - startActivity(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt index 62af5a5..3e2703d 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt @@ -1,6 +1,5 @@ package com.casic.common.detector.gd.view -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -22,7 +21,6 @@ class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" - private val context: Context = this private lateinit var marker: MarkerLocalBean override fun initViewBinding(): ActivityObjectDetailBinding { @@ -86,7 +84,7 @@ binding.showImageView.setOnClickListener { //查数据库 if (marker.imagePath.isNullOrEmpty()) { - "此标识器无图片".show(context) + "此标识器无图片".show(this) } else { val realPaths: ArrayList = ArrayList() //真实图片路径 @@ -97,12 +95,12 @@ if (imagePath.contains(",")) { val list = imagePath.split(",") list.forEach { path -> - val url = path.appendDownloadUrl(FileType.IMAGE) + val url = path.appendDownloadUrl(FileType.Image) realPaths.add(url) } } else { //只有一张图片 - val url = imagePath.appendDownloadUrl(FileType.IMAGE) + val url = imagePath.appendDownloadUrl(FileType.Image) realPaths.add(url) } navigatePageTo(0, realPaths) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt index 94e6c46..9f2d5cd 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt @@ -51,8 +51,8 @@ window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) window.decorView.setBackgroundColor(Color.TRANSPARENT) val params = window.attributes - params.width = (getScreenWidth() * 0.965).roundToInt() - params.height = (getScreenHeight() * 0.775).roundToInt() + params.width = (getScreenWidth() * 0.97).roundToInt() + params.height = (getScreenHeight() * 0.75).roundToInt() window.attributes = params if (ActivityCompat.checkSelfPermission( diff --git a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt index f4aadf8..ddc5a32 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt @@ -1,11 +1,11 @@ package com.casic.common.detector.gd.view -import android.app.ProgressDialog +import android.content.ActivityNotFoundException +import android.content.ClipData import android.content.Intent -import android.net.Uri -import android.os.Build import android.os.Bundle import android.util.Log +import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import androidx.lifecycle.ViewModelProvider import com.casic.common.detector.gd.BuildConfig @@ -13,13 +13,13 @@ import com.casic.common.detector.gd.databinding.ActivityVersionControlBinding import com.casic.common.detector.gd.extensions.appendDownloadUrl import com.casic.common.detector.gd.extensions.initImmersionBar +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType -import com.casic.common.detector.gd.utils.LocaleConstant import com.casic.common.detector.gd.vm.VersionViewModel +import com.casic.common.detector.gd.widgets.ProgressDialog import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.createDownloadFileDir import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.TitleBarView @@ -29,19 +29,11 @@ class VersionControlActivity : KotlinBaseActivity() { private val kTag = "VersionControlActivity" - private val progressDialog by lazy { ProgressDialog(this) } private lateinit var versionViewModel: VersionViewModel override fun initOnCreate(savedInstanceState: Bundle?) { binding.versionView.text = "Version ${BuildConfig.VERSION_NAME}" - //初始化下载对话框 - progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) - progressDialog.setProgressDrawable(resources.getDrawable(R.drawable.download_progress)) - progressDialog.setCanceledOnTouchOutside(false) - progressDialog.setCancelable(false) - progressDialog.max = 0 - versionViewModel = ViewModelProvider(this)[VersionViewModel::class.java] versionViewModel.versionResult.observe(this) { if (it.version.toInt() > BuildConfig.VERSION_CODE) { @@ -101,60 +93,57 @@ } private fun downloadApk(url: String?) { - progressDialog.setMessage("下载新版本中...") - progressDialog.show() - if (url.toString().isBlank()) { - "抱歉,版本下载失败".show(this) + if (url.isNullOrBlank()) { + "下载路径为空,版本下载失败".show(this) return } + val progressDialog = ProgressDialog(this) + progressDialog.show() /** * http://139.198.18.188:8090/ems/apk/EMSCJTX202011052026(V3.14.0).apk * */ - val downloadPath = url!!.appendDownloadUrl(FileType.APK) + val downloadPath = url.appendDownloadUrl(FileType.Apk) Log.d(kTag, "downloadApk => $downloadPath") - //开始下载 FileDownloadManager.Builder() .setDownloadFileSource(downloadPath) .setFileSuffix("apk") .setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + progressDialog.setMaxProgress(total) + } + override fun onDownloadEnd(file: File) { progressDialog.dismiss() - progressDialog.progress = 0 - //安装APK installApk(file) } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() + progressDialog.dismiss() } - override fun onProgressChanged(progress: Int) { - progressDialog.progress = progress + override fun onProgressChanged(progress: Long) { + progressDialog.updateProgress(progress) } - }) - .build() - .start() + }).build().start() } - private fun installApk(apkPackage: File?) { - if (apkPackage == null) { - "安装文件异常,无法安装".show(this) - return + private fun installApk(file: File) { + val apkUri = FileProvider.getUriForFile(this, "${packageName}.provider", file) + val mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension("apk") ?: "application/vnd.android.package-archive" + val intent = Intent(Intent.ACTION_VIEW).apply { + setDataAndType(apkUri, mimeType) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) + // 授予持久化 URI 权限 + clipData = ClipData.newRawUri("", apkUri) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) } - val intent = Intent(Intent.ACTION_VIEW) - val data: Uri - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //判断版本大于等于7.0 - data = FileProvider.getUriForFile(this, LocaleConstant.APP_AUTHORITY, apkPackage) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 给目标应用一个临时授权 - } else { - data = Uri.fromFile(apkPackage) + try { + this.startActivity(intent) + } catch (e: ActivityNotFoundException) { + e.printStackTrace() } - /** - * android 10 - * content://com.casic.app.smartwell.fileprovider/smartWell/Download/1.0.1.apk - * */ - intent.setDataAndType(data, "application/vnd.android.package-archive") - startActivity(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt new file mode 100644 index 0000000..af480b0 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt @@ -0,0 +1,36 @@ +package com.casic.common.detector.gd.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.casic.common.detector.gd.databinding.DialogProgressBinding +import com.pengxh.kt.lite.R +import com.pengxh.kt.lite.extensions.binding +import com.pengxh.kt.lite.extensions.initDialogLayoutParams + +class ProgressDialog(context: Context) : Dialog(context, R.style.UserDefinedDialogStyle) { + + private val binding: DialogProgressBinding by binding() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(0.5f) + setCanceledOnTouchOutside(false) + setCancelable(false) + binding.progressBar.progress = 0 + binding.progressText.text = "0 %" + } + + fun setMaxProgress(maxProgress: Long) { + binding.progressBar.max = maxProgress.toInt() + } + + private fun getMaxProgress() = binding.progressBar.max + + fun updateProgress(progress: Long) { + binding.progressBar.progress = progress.toInt() + + val percent = (progress.toFloat() / getMaxProgress()) * 100 + binding.progressText.text = String.format("%.2f %%", percent) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt index 62af5a5..3e2703d 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt @@ -1,6 +1,5 @@ package com.casic.common.detector.gd.view -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -22,7 +21,6 @@ class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" - private val context: Context = this private lateinit var marker: MarkerLocalBean override fun initViewBinding(): ActivityObjectDetailBinding { @@ -86,7 +84,7 @@ binding.showImageView.setOnClickListener { //查数据库 if (marker.imagePath.isNullOrEmpty()) { - "此标识器无图片".show(context) + "此标识器无图片".show(this) } else { val realPaths: ArrayList = ArrayList() //真实图片路径 @@ -97,12 +95,12 @@ if (imagePath.contains(",")) { val list = imagePath.split(",") list.forEach { path -> - val url = path.appendDownloadUrl(FileType.IMAGE) + val url = path.appendDownloadUrl(FileType.Image) realPaths.add(url) } } else { //只有一张图片 - val url = imagePath.appendDownloadUrl(FileType.IMAGE) + val url = imagePath.appendDownloadUrl(FileType.Image) realPaths.add(url) } navigatePageTo(0, realPaths) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt index 94e6c46..9f2d5cd 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt @@ -51,8 +51,8 @@ window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) window.decorView.setBackgroundColor(Color.TRANSPARENT) val params = window.attributes - params.width = (getScreenWidth() * 0.965).roundToInt() - params.height = (getScreenHeight() * 0.775).roundToInt() + params.width = (getScreenWidth() * 0.97).roundToInt() + params.height = (getScreenHeight() * 0.75).roundToInt() window.attributes = params if (ActivityCompat.checkSelfPermission( diff --git a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt index f4aadf8..ddc5a32 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt @@ -1,11 +1,11 @@ package com.casic.common.detector.gd.view -import android.app.ProgressDialog +import android.content.ActivityNotFoundException +import android.content.ClipData import android.content.Intent -import android.net.Uri -import android.os.Build import android.os.Bundle import android.util.Log +import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import androidx.lifecycle.ViewModelProvider import com.casic.common.detector.gd.BuildConfig @@ -13,13 +13,13 @@ import com.casic.common.detector.gd.databinding.ActivityVersionControlBinding import com.casic.common.detector.gd.extensions.appendDownloadUrl import com.casic.common.detector.gd.extensions.initImmersionBar +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType -import com.casic.common.detector.gd.utils.LocaleConstant import com.casic.common.detector.gd.vm.VersionViewModel +import com.casic.common.detector.gd.widgets.ProgressDialog import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.createDownloadFileDir import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.TitleBarView @@ -29,19 +29,11 @@ class VersionControlActivity : KotlinBaseActivity() { private val kTag = "VersionControlActivity" - private val progressDialog by lazy { ProgressDialog(this) } private lateinit var versionViewModel: VersionViewModel override fun initOnCreate(savedInstanceState: Bundle?) { binding.versionView.text = "Version ${BuildConfig.VERSION_NAME}" - //初始化下载对话框 - progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) - progressDialog.setProgressDrawable(resources.getDrawable(R.drawable.download_progress)) - progressDialog.setCanceledOnTouchOutside(false) - progressDialog.setCancelable(false) - progressDialog.max = 0 - versionViewModel = ViewModelProvider(this)[VersionViewModel::class.java] versionViewModel.versionResult.observe(this) { if (it.version.toInt() > BuildConfig.VERSION_CODE) { @@ -101,60 +93,57 @@ } private fun downloadApk(url: String?) { - progressDialog.setMessage("下载新版本中...") - progressDialog.show() - if (url.toString().isBlank()) { - "抱歉,版本下载失败".show(this) + if (url.isNullOrBlank()) { + "下载路径为空,版本下载失败".show(this) return } + val progressDialog = ProgressDialog(this) + progressDialog.show() /** * http://139.198.18.188:8090/ems/apk/EMSCJTX202011052026(V3.14.0).apk * */ - val downloadPath = url!!.appendDownloadUrl(FileType.APK) + val downloadPath = url.appendDownloadUrl(FileType.Apk) Log.d(kTag, "downloadApk => $downloadPath") - //开始下载 FileDownloadManager.Builder() .setDownloadFileSource(downloadPath) .setFileSuffix("apk") .setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + progressDialog.setMaxProgress(total) + } + override fun onDownloadEnd(file: File) { progressDialog.dismiss() - progressDialog.progress = 0 - //安装APK installApk(file) } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() + progressDialog.dismiss() } - override fun onProgressChanged(progress: Int) { - progressDialog.progress = progress + override fun onProgressChanged(progress: Long) { + progressDialog.updateProgress(progress) } - }) - .build() - .start() + }).build().start() } - private fun installApk(apkPackage: File?) { - if (apkPackage == null) { - "安装文件异常,无法安装".show(this) - return + private fun installApk(file: File) { + val apkUri = FileProvider.getUriForFile(this, "${packageName}.provider", file) + val mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension("apk") ?: "application/vnd.android.package-archive" + val intent = Intent(Intent.ACTION_VIEW).apply { + setDataAndType(apkUri, mimeType) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) + // 授予持久化 URI 权限 + clipData = ClipData.newRawUri("", apkUri) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) } - val intent = Intent(Intent.ACTION_VIEW) - val data: Uri - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //判断版本大于等于7.0 - data = FileProvider.getUriForFile(this, LocaleConstant.APP_AUTHORITY, apkPackage) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 给目标应用一个临时授权 - } else { - data = Uri.fromFile(apkPackage) + try { + this.startActivity(intent) + } catch (e: ActivityNotFoundException) { + e.printStackTrace() } - /** - * android 10 - * content://com.casic.app.smartwell.fileprovider/smartWell/Download/1.0.1.apk - * */ - intent.setDataAndType(data, "application/vnd.android.package-archive") - startActivity(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt new file mode 100644 index 0000000..af480b0 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt @@ -0,0 +1,36 @@ +package com.casic.common.detector.gd.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.casic.common.detector.gd.databinding.DialogProgressBinding +import com.pengxh.kt.lite.R +import com.pengxh.kt.lite.extensions.binding +import com.pengxh.kt.lite.extensions.initDialogLayoutParams + +class ProgressDialog(context: Context) : Dialog(context, R.style.UserDefinedDialogStyle) { + + private val binding: DialogProgressBinding by binding() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(0.5f) + setCanceledOnTouchOutside(false) + setCancelable(false) + binding.progressBar.progress = 0 + binding.progressText.text = "0 %" + } + + fun setMaxProgress(maxProgress: Long) { + binding.progressBar.max = maxProgress.toInt() + } + + private fun getMaxProgress() = binding.progressBar.max + + fun updateProgress(progress: Long) { + binding.progressBar.progress = progress.toInt() + + val percent = (progress.toFloat() / getMaxProgress()) * 100 + binding.progressText.text = String.format("%.2f %%", percent) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/download_progress.xml b/app/src/main/res/drawable/download_progress.xml deleted file mode 100644 index d3670c3..0000000 --- a/app/src/main/res/drawable/download_progress.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt index 62af5a5..3e2703d 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt @@ -1,6 +1,5 @@ package com.casic.common.detector.gd.view -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -22,7 +21,6 @@ class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" - private val context: Context = this private lateinit var marker: MarkerLocalBean override fun initViewBinding(): ActivityObjectDetailBinding { @@ -86,7 +84,7 @@ binding.showImageView.setOnClickListener { //查数据库 if (marker.imagePath.isNullOrEmpty()) { - "此标识器无图片".show(context) + "此标识器无图片".show(this) } else { val realPaths: ArrayList = ArrayList() //真实图片路径 @@ -97,12 +95,12 @@ if (imagePath.contains(",")) { val list = imagePath.split(",") list.forEach { path -> - val url = path.appendDownloadUrl(FileType.IMAGE) + val url = path.appendDownloadUrl(FileType.Image) realPaths.add(url) } } else { //只有一张图片 - val url = imagePath.appendDownloadUrl(FileType.IMAGE) + val url = imagePath.appendDownloadUrl(FileType.Image) realPaths.add(url) } navigatePageTo(0, realPaths) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt index 94e6c46..9f2d5cd 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt @@ -51,8 +51,8 @@ window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) window.decorView.setBackgroundColor(Color.TRANSPARENT) val params = window.attributes - params.width = (getScreenWidth() * 0.965).roundToInt() - params.height = (getScreenHeight() * 0.775).roundToInt() + params.width = (getScreenWidth() * 0.97).roundToInt() + params.height = (getScreenHeight() * 0.75).roundToInt() window.attributes = params if (ActivityCompat.checkSelfPermission( diff --git a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt index f4aadf8..ddc5a32 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt @@ -1,11 +1,11 @@ package com.casic.common.detector.gd.view -import android.app.ProgressDialog +import android.content.ActivityNotFoundException +import android.content.ClipData import android.content.Intent -import android.net.Uri -import android.os.Build import android.os.Bundle import android.util.Log +import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import androidx.lifecycle.ViewModelProvider import com.casic.common.detector.gd.BuildConfig @@ -13,13 +13,13 @@ import com.casic.common.detector.gd.databinding.ActivityVersionControlBinding import com.casic.common.detector.gd.extensions.appendDownloadUrl import com.casic.common.detector.gd.extensions.initImmersionBar +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType -import com.casic.common.detector.gd.utils.LocaleConstant import com.casic.common.detector.gd.vm.VersionViewModel +import com.casic.common.detector.gd.widgets.ProgressDialog import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.createDownloadFileDir import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.TitleBarView @@ -29,19 +29,11 @@ class VersionControlActivity : KotlinBaseActivity() { private val kTag = "VersionControlActivity" - private val progressDialog by lazy { ProgressDialog(this) } private lateinit var versionViewModel: VersionViewModel override fun initOnCreate(savedInstanceState: Bundle?) { binding.versionView.text = "Version ${BuildConfig.VERSION_NAME}" - //初始化下载对话框 - progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) - progressDialog.setProgressDrawable(resources.getDrawable(R.drawable.download_progress)) - progressDialog.setCanceledOnTouchOutside(false) - progressDialog.setCancelable(false) - progressDialog.max = 0 - versionViewModel = ViewModelProvider(this)[VersionViewModel::class.java] versionViewModel.versionResult.observe(this) { if (it.version.toInt() > BuildConfig.VERSION_CODE) { @@ -101,60 +93,57 @@ } private fun downloadApk(url: String?) { - progressDialog.setMessage("下载新版本中...") - progressDialog.show() - if (url.toString().isBlank()) { - "抱歉,版本下载失败".show(this) + if (url.isNullOrBlank()) { + "下载路径为空,版本下载失败".show(this) return } + val progressDialog = ProgressDialog(this) + progressDialog.show() /** * http://139.198.18.188:8090/ems/apk/EMSCJTX202011052026(V3.14.0).apk * */ - val downloadPath = url!!.appendDownloadUrl(FileType.APK) + val downloadPath = url.appendDownloadUrl(FileType.Apk) Log.d(kTag, "downloadApk => $downloadPath") - //开始下载 FileDownloadManager.Builder() .setDownloadFileSource(downloadPath) .setFileSuffix("apk") .setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + progressDialog.setMaxProgress(total) + } + override fun onDownloadEnd(file: File) { progressDialog.dismiss() - progressDialog.progress = 0 - //安装APK installApk(file) } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() + progressDialog.dismiss() } - override fun onProgressChanged(progress: Int) { - progressDialog.progress = progress + override fun onProgressChanged(progress: Long) { + progressDialog.updateProgress(progress) } - }) - .build() - .start() + }).build().start() } - private fun installApk(apkPackage: File?) { - if (apkPackage == null) { - "安装文件异常,无法安装".show(this) - return + private fun installApk(file: File) { + val apkUri = FileProvider.getUriForFile(this, "${packageName}.provider", file) + val mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension("apk") ?: "application/vnd.android.package-archive" + val intent = Intent(Intent.ACTION_VIEW).apply { + setDataAndType(apkUri, mimeType) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) + // 授予持久化 URI 权限 + clipData = ClipData.newRawUri("", apkUri) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) } - val intent = Intent(Intent.ACTION_VIEW) - val data: Uri - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //判断版本大于等于7.0 - data = FileProvider.getUriForFile(this, LocaleConstant.APP_AUTHORITY, apkPackage) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 给目标应用一个临时授权 - } else { - data = Uri.fromFile(apkPackage) + try { + this.startActivity(intent) + } catch (e: ActivityNotFoundException) { + e.printStackTrace() } - /** - * android 10 - * content://com.casic.app.smartwell.fileprovider/smartWell/Download/1.0.1.apk - * */ - intent.setDataAndType(data, "application/vnd.android.package-archive") - startActivity(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt new file mode 100644 index 0000000..af480b0 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt @@ -0,0 +1,36 @@ +package com.casic.common.detector.gd.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.casic.common.detector.gd.databinding.DialogProgressBinding +import com.pengxh.kt.lite.R +import com.pengxh.kt.lite.extensions.binding +import com.pengxh.kt.lite.extensions.initDialogLayoutParams + +class ProgressDialog(context: Context) : Dialog(context, R.style.UserDefinedDialogStyle) { + + private val binding: DialogProgressBinding by binding() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(0.5f) + setCanceledOnTouchOutside(false) + setCancelable(false) + binding.progressBar.progress = 0 + binding.progressText.text = "0 %" + } + + fun setMaxProgress(maxProgress: Long) { + binding.progressBar.max = maxProgress.toInt() + } + + private fun getMaxProgress() = binding.progressBar.max + + fun updateProgress(progress: Long) { + binding.progressBar.progress = progress.toInt() + + val percent = (progress.toFloat() / getMaxProgress()) * 100 + binding.progressText.text = String.format("%.2f %%", percent) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/download_progress.xml b/app/src/main/res/drawable/download_progress.xml deleted file mode 100644 index d3670c3..0000000 --- a/app/src/main/res/drawable/download_progress.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow.xml b/app/src/main/res/drawable/ic_arrow.xml deleted file mode 100644 index d0b98a0..0000000 --- a/app/src/main/res/drawable/ic_arrow.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt index 62af5a5..3e2703d 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt @@ -1,6 +1,5 @@ package com.casic.common.detector.gd.view -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -22,7 +21,6 @@ class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" - private val context: Context = this private lateinit var marker: MarkerLocalBean override fun initViewBinding(): ActivityObjectDetailBinding { @@ -86,7 +84,7 @@ binding.showImageView.setOnClickListener { //查数据库 if (marker.imagePath.isNullOrEmpty()) { - "此标识器无图片".show(context) + "此标识器无图片".show(this) } else { val realPaths: ArrayList = ArrayList() //真实图片路径 @@ -97,12 +95,12 @@ if (imagePath.contains(",")) { val list = imagePath.split(",") list.forEach { path -> - val url = path.appendDownloadUrl(FileType.IMAGE) + val url = path.appendDownloadUrl(FileType.Image) realPaths.add(url) } } else { //只有一张图片 - val url = imagePath.appendDownloadUrl(FileType.IMAGE) + val url = imagePath.appendDownloadUrl(FileType.Image) realPaths.add(url) } navigatePageTo(0, realPaths) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt index 94e6c46..9f2d5cd 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt @@ -51,8 +51,8 @@ window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) window.decorView.setBackgroundColor(Color.TRANSPARENT) val params = window.attributes - params.width = (getScreenWidth() * 0.965).roundToInt() - params.height = (getScreenHeight() * 0.775).roundToInt() + params.width = (getScreenWidth() * 0.97).roundToInt() + params.height = (getScreenHeight() * 0.75).roundToInt() window.attributes = params if (ActivityCompat.checkSelfPermission( diff --git a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt index f4aadf8..ddc5a32 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt @@ -1,11 +1,11 @@ package com.casic.common.detector.gd.view -import android.app.ProgressDialog +import android.content.ActivityNotFoundException +import android.content.ClipData import android.content.Intent -import android.net.Uri -import android.os.Build import android.os.Bundle import android.util.Log +import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import androidx.lifecycle.ViewModelProvider import com.casic.common.detector.gd.BuildConfig @@ -13,13 +13,13 @@ import com.casic.common.detector.gd.databinding.ActivityVersionControlBinding import com.casic.common.detector.gd.extensions.appendDownloadUrl import com.casic.common.detector.gd.extensions.initImmersionBar +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType -import com.casic.common.detector.gd.utils.LocaleConstant import com.casic.common.detector.gd.vm.VersionViewModel +import com.casic.common.detector.gd.widgets.ProgressDialog import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.createDownloadFileDir import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.TitleBarView @@ -29,19 +29,11 @@ class VersionControlActivity : KotlinBaseActivity() { private val kTag = "VersionControlActivity" - private val progressDialog by lazy { ProgressDialog(this) } private lateinit var versionViewModel: VersionViewModel override fun initOnCreate(savedInstanceState: Bundle?) { binding.versionView.text = "Version ${BuildConfig.VERSION_NAME}" - //初始化下载对话框 - progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) - progressDialog.setProgressDrawable(resources.getDrawable(R.drawable.download_progress)) - progressDialog.setCanceledOnTouchOutside(false) - progressDialog.setCancelable(false) - progressDialog.max = 0 - versionViewModel = ViewModelProvider(this)[VersionViewModel::class.java] versionViewModel.versionResult.observe(this) { if (it.version.toInt() > BuildConfig.VERSION_CODE) { @@ -101,60 +93,57 @@ } private fun downloadApk(url: String?) { - progressDialog.setMessage("下载新版本中...") - progressDialog.show() - if (url.toString().isBlank()) { - "抱歉,版本下载失败".show(this) + if (url.isNullOrBlank()) { + "下载路径为空,版本下载失败".show(this) return } + val progressDialog = ProgressDialog(this) + progressDialog.show() /** * http://139.198.18.188:8090/ems/apk/EMSCJTX202011052026(V3.14.0).apk * */ - val downloadPath = url!!.appendDownloadUrl(FileType.APK) + val downloadPath = url.appendDownloadUrl(FileType.Apk) Log.d(kTag, "downloadApk => $downloadPath") - //开始下载 FileDownloadManager.Builder() .setDownloadFileSource(downloadPath) .setFileSuffix("apk") .setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + progressDialog.setMaxProgress(total) + } + override fun onDownloadEnd(file: File) { progressDialog.dismiss() - progressDialog.progress = 0 - //安装APK installApk(file) } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() + progressDialog.dismiss() } - override fun onProgressChanged(progress: Int) { - progressDialog.progress = progress + override fun onProgressChanged(progress: Long) { + progressDialog.updateProgress(progress) } - }) - .build() - .start() + }).build().start() } - private fun installApk(apkPackage: File?) { - if (apkPackage == null) { - "安装文件异常,无法安装".show(this) - return + private fun installApk(file: File) { + val apkUri = FileProvider.getUriForFile(this, "${packageName}.provider", file) + val mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension("apk") ?: "application/vnd.android.package-archive" + val intent = Intent(Intent.ACTION_VIEW).apply { + setDataAndType(apkUri, mimeType) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) + // 授予持久化 URI 权限 + clipData = ClipData.newRawUri("", apkUri) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) } - val intent = Intent(Intent.ACTION_VIEW) - val data: Uri - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //判断版本大于等于7.0 - data = FileProvider.getUriForFile(this, LocaleConstant.APP_AUTHORITY, apkPackage) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 给目标应用一个临时授权 - } else { - data = Uri.fromFile(apkPackage) + try { + this.startActivity(intent) + } catch (e: ActivityNotFoundException) { + e.printStackTrace() } - /** - * android 10 - * content://com.casic.app.smartwell.fileprovider/smartWell/Download/1.0.1.apk - * */ - intent.setDataAndType(data, "application/vnd.android.package-archive") - startActivity(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt new file mode 100644 index 0000000..af480b0 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt @@ -0,0 +1,36 @@ +package com.casic.common.detector.gd.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.casic.common.detector.gd.databinding.DialogProgressBinding +import com.pengxh.kt.lite.R +import com.pengxh.kt.lite.extensions.binding +import com.pengxh.kt.lite.extensions.initDialogLayoutParams + +class ProgressDialog(context: Context) : Dialog(context, R.style.UserDefinedDialogStyle) { + + private val binding: DialogProgressBinding by binding() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(0.5f) + setCanceledOnTouchOutside(false) + setCancelable(false) + binding.progressBar.progress = 0 + binding.progressText.text = "0 %" + } + + fun setMaxProgress(maxProgress: Long) { + binding.progressBar.max = maxProgress.toInt() + } + + private fun getMaxProgress() = binding.progressBar.max + + fun updateProgress(progress: Long) { + binding.progressBar.progress = progress.toInt() + + val percent = (progress.toFloat() / getMaxProgress()) * 100 + binding.progressText.text = String.format("%.2f %%", percent) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/download_progress.xml b/app/src/main/res/drawable/download_progress.xml deleted file mode 100644 index d3670c3..0000000 --- a/app/src/main/res/drawable/download_progress.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow.xml b/app/src/main/res/drawable/ic_arrow.xml deleted file mode 100644 index d0b98a0..0000000 --- a/app/src/main/res/drawable/ic_arrow.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9..0000000 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt index 62af5a5..3e2703d 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt @@ -1,6 +1,5 @@ package com.casic.common.detector.gd.view -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -22,7 +21,6 @@ class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" - private val context: Context = this private lateinit var marker: MarkerLocalBean override fun initViewBinding(): ActivityObjectDetailBinding { @@ -86,7 +84,7 @@ binding.showImageView.setOnClickListener { //查数据库 if (marker.imagePath.isNullOrEmpty()) { - "此标识器无图片".show(context) + "此标识器无图片".show(this) } else { val realPaths: ArrayList = ArrayList() //真实图片路径 @@ -97,12 +95,12 @@ if (imagePath.contains(",")) { val list = imagePath.split(",") list.forEach { path -> - val url = path.appendDownloadUrl(FileType.IMAGE) + val url = path.appendDownloadUrl(FileType.Image) realPaths.add(url) } } else { //只有一张图片 - val url = imagePath.appendDownloadUrl(FileType.IMAGE) + val url = imagePath.appendDownloadUrl(FileType.Image) realPaths.add(url) } navigatePageTo(0, realPaths) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt index 94e6c46..9f2d5cd 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt @@ -51,8 +51,8 @@ window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) window.decorView.setBackgroundColor(Color.TRANSPARENT) val params = window.attributes - params.width = (getScreenWidth() * 0.965).roundToInt() - params.height = (getScreenHeight() * 0.775).roundToInt() + params.width = (getScreenWidth() * 0.97).roundToInt() + params.height = (getScreenHeight() * 0.75).roundToInt() window.attributes = params if (ActivityCompat.checkSelfPermission( diff --git a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt index f4aadf8..ddc5a32 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt @@ -1,11 +1,11 @@ package com.casic.common.detector.gd.view -import android.app.ProgressDialog +import android.content.ActivityNotFoundException +import android.content.ClipData import android.content.Intent -import android.net.Uri -import android.os.Build import android.os.Bundle import android.util.Log +import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import androidx.lifecycle.ViewModelProvider import com.casic.common.detector.gd.BuildConfig @@ -13,13 +13,13 @@ import com.casic.common.detector.gd.databinding.ActivityVersionControlBinding import com.casic.common.detector.gd.extensions.appendDownloadUrl import com.casic.common.detector.gd.extensions.initImmersionBar +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType -import com.casic.common.detector.gd.utils.LocaleConstant import com.casic.common.detector.gd.vm.VersionViewModel +import com.casic.common.detector.gd.widgets.ProgressDialog import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.createDownloadFileDir import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.TitleBarView @@ -29,19 +29,11 @@ class VersionControlActivity : KotlinBaseActivity() { private val kTag = "VersionControlActivity" - private val progressDialog by lazy { ProgressDialog(this) } private lateinit var versionViewModel: VersionViewModel override fun initOnCreate(savedInstanceState: Bundle?) { binding.versionView.text = "Version ${BuildConfig.VERSION_NAME}" - //初始化下载对话框 - progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) - progressDialog.setProgressDrawable(resources.getDrawable(R.drawable.download_progress)) - progressDialog.setCanceledOnTouchOutside(false) - progressDialog.setCancelable(false) - progressDialog.max = 0 - versionViewModel = ViewModelProvider(this)[VersionViewModel::class.java] versionViewModel.versionResult.observe(this) { if (it.version.toInt() > BuildConfig.VERSION_CODE) { @@ -101,60 +93,57 @@ } private fun downloadApk(url: String?) { - progressDialog.setMessage("下载新版本中...") - progressDialog.show() - if (url.toString().isBlank()) { - "抱歉,版本下载失败".show(this) + if (url.isNullOrBlank()) { + "下载路径为空,版本下载失败".show(this) return } + val progressDialog = ProgressDialog(this) + progressDialog.show() /** * http://139.198.18.188:8090/ems/apk/EMSCJTX202011052026(V3.14.0).apk * */ - val downloadPath = url!!.appendDownloadUrl(FileType.APK) + val downloadPath = url.appendDownloadUrl(FileType.Apk) Log.d(kTag, "downloadApk => $downloadPath") - //开始下载 FileDownloadManager.Builder() .setDownloadFileSource(downloadPath) .setFileSuffix("apk") .setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + progressDialog.setMaxProgress(total) + } + override fun onDownloadEnd(file: File) { progressDialog.dismiss() - progressDialog.progress = 0 - //安装APK installApk(file) } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() + progressDialog.dismiss() } - override fun onProgressChanged(progress: Int) { - progressDialog.progress = progress + override fun onProgressChanged(progress: Long) { + progressDialog.updateProgress(progress) } - }) - .build() - .start() + }).build().start() } - private fun installApk(apkPackage: File?) { - if (apkPackage == null) { - "安装文件异常,无法安装".show(this) - return + private fun installApk(file: File) { + val apkUri = FileProvider.getUriForFile(this, "${packageName}.provider", file) + val mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension("apk") ?: "application/vnd.android.package-archive" + val intent = Intent(Intent.ACTION_VIEW).apply { + setDataAndType(apkUri, mimeType) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) + // 授予持久化 URI 权限 + clipData = ClipData.newRawUri("", apkUri) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) } - val intent = Intent(Intent.ACTION_VIEW) - val data: Uri - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //判断版本大于等于7.0 - data = FileProvider.getUriForFile(this, LocaleConstant.APP_AUTHORITY, apkPackage) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 给目标应用一个临时授权 - } else { - data = Uri.fromFile(apkPackage) + try { + this.startActivity(intent) + } catch (e: ActivityNotFoundException) { + e.printStackTrace() } - /** - * android 10 - * content://com.casic.app.smartwell.fileprovider/smartWell/Download/1.0.1.apk - * */ - intent.setDataAndType(data, "application/vnd.android.package-archive") - startActivity(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt new file mode 100644 index 0000000..af480b0 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt @@ -0,0 +1,36 @@ +package com.casic.common.detector.gd.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.casic.common.detector.gd.databinding.DialogProgressBinding +import com.pengxh.kt.lite.R +import com.pengxh.kt.lite.extensions.binding +import com.pengxh.kt.lite.extensions.initDialogLayoutParams + +class ProgressDialog(context: Context) : Dialog(context, R.style.UserDefinedDialogStyle) { + + private val binding: DialogProgressBinding by binding() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(0.5f) + setCanceledOnTouchOutside(false) + setCancelable(false) + binding.progressBar.progress = 0 + binding.progressText.text = "0 %" + } + + fun setMaxProgress(maxProgress: Long) { + binding.progressBar.max = maxProgress.toInt() + } + + private fun getMaxProgress() = binding.progressBar.max + + fun updateProgress(progress: Long) { + binding.progressBar.progress = progress.toInt() + + val percent = (progress.toFloat() / getMaxProgress()) * 100 + binding.progressText.text = String.format("%.2f %%", percent) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/download_progress.xml b/app/src/main/res/drawable/download_progress.xml deleted file mode 100644 index d3670c3..0000000 --- a/app/src/main/res/drawable/download_progress.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow.xml b/app/src/main/res/drawable/ic_arrow.xml deleted file mode 100644 index d0b98a0..0000000 --- a/app/src/main/res/drawable/ic_arrow.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9..0000000 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_right_black.xml b/app/src/main/res/drawable/ic_right_black.xml deleted file mode 100644 index a25faa7..0000000 --- a/app/src/main/res/drawable/ic_right_black.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt index 62af5a5..3e2703d 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt @@ -1,6 +1,5 @@ package com.casic.common.detector.gd.view -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -22,7 +21,6 @@ class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" - private val context: Context = this private lateinit var marker: MarkerLocalBean override fun initViewBinding(): ActivityObjectDetailBinding { @@ -86,7 +84,7 @@ binding.showImageView.setOnClickListener { //查数据库 if (marker.imagePath.isNullOrEmpty()) { - "此标识器无图片".show(context) + "此标识器无图片".show(this) } else { val realPaths: ArrayList = ArrayList() //真实图片路径 @@ -97,12 +95,12 @@ if (imagePath.contains(",")) { val list = imagePath.split(",") list.forEach { path -> - val url = path.appendDownloadUrl(FileType.IMAGE) + val url = path.appendDownloadUrl(FileType.Image) realPaths.add(url) } } else { //只有一张图片 - val url = imagePath.appendDownloadUrl(FileType.IMAGE) + val url = imagePath.appendDownloadUrl(FileType.Image) realPaths.add(url) } navigatePageTo(0, realPaths) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt index 94e6c46..9f2d5cd 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt @@ -51,8 +51,8 @@ window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) window.decorView.setBackgroundColor(Color.TRANSPARENT) val params = window.attributes - params.width = (getScreenWidth() * 0.965).roundToInt() - params.height = (getScreenHeight() * 0.775).roundToInt() + params.width = (getScreenWidth() * 0.97).roundToInt() + params.height = (getScreenHeight() * 0.75).roundToInt() window.attributes = params if (ActivityCompat.checkSelfPermission( diff --git a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt index f4aadf8..ddc5a32 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt @@ -1,11 +1,11 @@ package com.casic.common.detector.gd.view -import android.app.ProgressDialog +import android.content.ActivityNotFoundException +import android.content.ClipData import android.content.Intent -import android.net.Uri -import android.os.Build import android.os.Bundle import android.util.Log +import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import androidx.lifecycle.ViewModelProvider import com.casic.common.detector.gd.BuildConfig @@ -13,13 +13,13 @@ import com.casic.common.detector.gd.databinding.ActivityVersionControlBinding import com.casic.common.detector.gd.extensions.appendDownloadUrl import com.casic.common.detector.gd.extensions.initImmersionBar +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType -import com.casic.common.detector.gd.utils.LocaleConstant import com.casic.common.detector.gd.vm.VersionViewModel +import com.casic.common.detector.gd.widgets.ProgressDialog import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.createDownloadFileDir import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.TitleBarView @@ -29,19 +29,11 @@ class VersionControlActivity : KotlinBaseActivity() { private val kTag = "VersionControlActivity" - private val progressDialog by lazy { ProgressDialog(this) } private lateinit var versionViewModel: VersionViewModel override fun initOnCreate(savedInstanceState: Bundle?) { binding.versionView.text = "Version ${BuildConfig.VERSION_NAME}" - //初始化下载对话框 - progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) - progressDialog.setProgressDrawable(resources.getDrawable(R.drawable.download_progress)) - progressDialog.setCanceledOnTouchOutside(false) - progressDialog.setCancelable(false) - progressDialog.max = 0 - versionViewModel = ViewModelProvider(this)[VersionViewModel::class.java] versionViewModel.versionResult.observe(this) { if (it.version.toInt() > BuildConfig.VERSION_CODE) { @@ -101,60 +93,57 @@ } private fun downloadApk(url: String?) { - progressDialog.setMessage("下载新版本中...") - progressDialog.show() - if (url.toString().isBlank()) { - "抱歉,版本下载失败".show(this) + if (url.isNullOrBlank()) { + "下载路径为空,版本下载失败".show(this) return } + val progressDialog = ProgressDialog(this) + progressDialog.show() /** * http://139.198.18.188:8090/ems/apk/EMSCJTX202011052026(V3.14.0).apk * */ - val downloadPath = url!!.appendDownloadUrl(FileType.APK) + val downloadPath = url.appendDownloadUrl(FileType.Apk) Log.d(kTag, "downloadApk => $downloadPath") - //开始下载 FileDownloadManager.Builder() .setDownloadFileSource(downloadPath) .setFileSuffix("apk") .setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + progressDialog.setMaxProgress(total) + } + override fun onDownloadEnd(file: File) { progressDialog.dismiss() - progressDialog.progress = 0 - //安装APK installApk(file) } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() + progressDialog.dismiss() } - override fun onProgressChanged(progress: Int) { - progressDialog.progress = progress + override fun onProgressChanged(progress: Long) { + progressDialog.updateProgress(progress) } - }) - .build() - .start() + }).build().start() } - private fun installApk(apkPackage: File?) { - if (apkPackage == null) { - "安装文件异常,无法安装".show(this) - return + private fun installApk(file: File) { + val apkUri = FileProvider.getUriForFile(this, "${packageName}.provider", file) + val mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension("apk") ?: "application/vnd.android.package-archive" + val intent = Intent(Intent.ACTION_VIEW).apply { + setDataAndType(apkUri, mimeType) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) + // 授予持久化 URI 权限 + clipData = ClipData.newRawUri("", apkUri) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) } - val intent = Intent(Intent.ACTION_VIEW) - val data: Uri - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //判断版本大于等于7.0 - data = FileProvider.getUriForFile(this, LocaleConstant.APP_AUTHORITY, apkPackage) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 给目标应用一个临时授权 - } else { - data = Uri.fromFile(apkPackage) + try { + this.startActivity(intent) + } catch (e: ActivityNotFoundException) { + e.printStackTrace() } - /** - * android 10 - * content://com.casic.app.smartwell.fileprovider/smartWell/Download/1.0.1.apk - * */ - intent.setDataAndType(data, "application/vnd.android.package-archive") - startActivity(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt new file mode 100644 index 0000000..af480b0 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt @@ -0,0 +1,36 @@ +package com.casic.common.detector.gd.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.casic.common.detector.gd.databinding.DialogProgressBinding +import com.pengxh.kt.lite.R +import com.pengxh.kt.lite.extensions.binding +import com.pengxh.kt.lite.extensions.initDialogLayoutParams + +class ProgressDialog(context: Context) : Dialog(context, R.style.UserDefinedDialogStyle) { + + private val binding: DialogProgressBinding by binding() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(0.5f) + setCanceledOnTouchOutside(false) + setCancelable(false) + binding.progressBar.progress = 0 + binding.progressText.text = "0 %" + } + + fun setMaxProgress(maxProgress: Long) { + binding.progressBar.max = maxProgress.toInt() + } + + private fun getMaxProgress() = binding.progressBar.max + + fun updateProgress(progress: Long) { + binding.progressBar.progress = progress.toInt() + + val percent = (progress.toFloat() / getMaxProgress()) * 100 + binding.progressText.text = String.format("%.2f %%", percent) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/download_progress.xml b/app/src/main/res/drawable/download_progress.xml deleted file mode 100644 index d3670c3..0000000 --- a/app/src/main/res/drawable/download_progress.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow.xml b/app/src/main/res/drawable/ic_arrow.xml deleted file mode 100644 index d0b98a0..0000000 --- a/app/src/main/res/drawable/ic_arrow.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9..0000000 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_right_black.xml b/app/src/main/res/drawable/ic_right_black.xml deleted file mode 100644 index a25faa7..0000000 --- a/app/src/main/res/drawable/ic_right_black.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/activity_satellite_status.xml b/app/src/main/res/layout/activity_satellite_status.xml index 276f5b2..6b98b2e 100644 --- a/app/src/main/res/layout/activity_satellite_status.xml +++ b/app/src/main/res/layout/activity_satellite_status.xml @@ -1,141 +1,147 @@ - - - - - + app:cardCornerRadius="@dimen/dp_5"> + android:layout_height="match_parent" + android:background="@color/lib_text_color" + android:orientation="vertical"> - - - - + app:tbv_right_image="@drawable/ic_close_white" + app:tbv_show_left_image="false" + app:tbv_show_right_image="true" + app:tbv_smaller_title="true" + app:tbv_text="卫星定位信号" + app:tbv_text_color="@color/white" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> - + - + - - - - - - - - + - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt index 62af5a5..3e2703d 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt @@ -1,6 +1,5 @@ package com.casic.common.detector.gd.view -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -22,7 +21,6 @@ class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" - private val context: Context = this private lateinit var marker: MarkerLocalBean override fun initViewBinding(): ActivityObjectDetailBinding { @@ -86,7 +84,7 @@ binding.showImageView.setOnClickListener { //查数据库 if (marker.imagePath.isNullOrEmpty()) { - "此标识器无图片".show(context) + "此标识器无图片".show(this) } else { val realPaths: ArrayList = ArrayList() //真实图片路径 @@ -97,12 +95,12 @@ if (imagePath.contains(",")) { val list = imagePath.split(",") list.forEach { path -> - val url = path.appendDownloadUrl(FileType.IMAGE) + val url = path.appendDownloadUrl(FileType.Image) realPaths.add(url) } } else { //只有一张图片 - val url = imagePath.appendDownloadUrl(FileType.IMAGE) + val url = imagePath.appendDownloadUrl(FileType.Image) realPaths.add(url) } navigatePageTo(0, realPaths) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt index 94e6c46..9f2d5cd 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt @@ -51,8 +51,8 @@ window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) window.decorView.setBackgroundColor(Color.TRANSPARENT) val params = window.attributes - params.width = (getScreenWidth() * 0.965).roundToInt() - params.height = (getScreenHeight() * 0.775).roundToInt() + params.width = (getScreenWidth() * 0.97).roundToInt() + params.height = (getScreenHeight() * 0.75).roundToInt() window.attributes = params if (ActivityCompat.checkSelfPermission( diff --git a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt index f4aadf8..ddc5a32 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt @@ -1,11 +1,11 @@ package com.casic.common.detector.gd.view -import android.app.ProgressDialog +import android.content.ActivityNotFoundException +import android.content.ClipData import android.content.Intent -import android.net.Uri -import android.os.Build import android.os.Bundle import android.util.Log +import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import androidx.lifecycle.ViewModelProvider import com.casic.common.detector.gd.BuildConfig @@ -13,13 +13,13 @@ import com.casic.common.detector.gd.databinding.ActivityVersionControlBinding import com.casic.common.detector.gd.extensions.appendDownloadUrl import com.casic.common.detector.gd.extensions.initImmersionBar +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType -import com.casic.common.detector.gd.utils.LocaleConstant import com.casic.common.detector.gd.vm.VersionViewModel +import com.casic.common.detector.gd.widgets.ProgressDialog import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.createDownloadFileDir import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.TitleBarView @@ -29,19 +29,11 @@ class VersionControlActivity : KotlinBaseActivity() { private val kTag = "VersionControlActivity" - private val progressDialog by lazy { ProgressDialog(this) } private lateinit var versionViewModel: VersionViewModel override fun initOnCreate(savedInstanceState: Bundle?) { binding.versionView.text = "Version ${BuildConfig.VERSION_NAME}" - //初始化下载对话框 - progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) - progressDialog.setProgressDrawable(resources.getDrawable(R.drawable.download_progress)) - progressDialog.setCanceledOnTouchOutside(false) - progressDialog.setCancelable(false) - progressDialog.max = 0 - versionViewModel = ViewModelProvider(this)[VersionViewModel::class.java] versionViewModel.versionResult.observe(this) { if (it.version.toInt() > BuildConfig.VERSION_CODE) { @@ -101,60 +93,57 @@ } private fun downloadApk(url: String?) { - progressDialog.setMessage("下载新版本中...") - progressDialog.show() - if (url.toString().isBlank()) { - "抱歉,版本下载失败".show(this) + if (url.isNullOrBlank()) { + "下载路径为空,版本下载失败".show(this) return } + val progressDialog = ProgressDialog(this) + progressDialog.show() /** * http://139.198.18.188:8090/ems/apk/EMSCJTX202011052026(V3.14.0).apk * */ - val downloadPath = url!!.appendDownloadUrl(FileType.APK) + val downloadPath = url.appendDownloadUrl(FileType.Apk) Log.d(kTag, "downloadApk => $downloadPath") - //开始下载 FileDownloadManager.Builder() .setDownloadFileSource(downloadPath) .setFileSuffix("apk") .setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + progressDialog.setMaxProgress(total) + } + override fun onDownloadEnd(file: File) { progressDialog.dismiss() - progressDialog.progress = 0 - //安装APK installApk(file) } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() + progressDialog.dismiss() } - override fun onProgressChanged(progress: Int) { - progressDialog.progress = progress + override fun onProgressChanged(progress: Long) { + progressDialog.updateProgress(progress) } - }) - .build() - .start() + }).build().start() } - private fun installApk(apkPackage: File?) { - if (apkPackage == null) { - "安装文件异常,无法安装".show(this) - return + private fun installApk(file: File) { + val apkUri = FileProvider.getUriForFile(this, "${packageName}.provider", file) + val mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension("apk") ?: "application/vnd.android.package-archive" + val intent = Intent(Intent.ACTION_VIEW).apply { + setDataAndType(apkUri, mimeType) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) + // 授予持久化 URI 权限 + clipData = ClipData.newRawUri("", apkUri) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) } - val intent = Intent(Intent.ACTION_VIEW) - val data: Uri - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //判断版本大于等于7.0 - data = FileProvider.getUriForFile(this, LocaleConstant.APP_AUTHORITY, apkPackage) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 给目标应用一个临时授权 - } else { - data = Uri.fromFile(apkPackage) + try { + this.startActivity(intent) + } catch (e: ActivityNotFoundException) { + e.printStackTrace() } - /** - * android 10 - * content://com.casic.app.smartwell.fileprovider/smartWell/Download/1.0.1.apk - * */ - intent.setDataAndType(data, "application/vnd.android.package-archive") - startActivity(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt new file mode 100644 index 0000000..af480b0 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt @@ -0,0 +1,36 @@ +package com.casic.common.detector.gd.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.casic.common.detector.gd.databinding.DialogProgressBinding +import com.pengxh.kt.lite.R +import com.pengxh.kt.lite.extensions.binding +import com.pengxh.kt.lite.extensions.initDialogLayoutParams + +class ProgressDialog(context: Context) : Dialog(context, R.style.UserDefinedDialogStyle) { + + private val binding: DialogProgressBinding by binding() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(0.5f) + setCanceledOnTouchOutside(false) + setCancelable(false) + binding.progressBar.progress = 0 + binding.progressText.text = "0 %" + } + + fun setMaxProgress(maxProgress: Long) { + binding.progressBar.max = maxProgress.toInt() + } + + private fun getMaxProgress() = binding.progressBar.max + + fun updateProgress(progress: Long) { + binding.progressBar.progress = progress.toInt() + + val percent = (progress.toFloat() / getMaxProgress()) * 100 + binding.progressText.text = String.format("%.2f %%", percent) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/download_progress.xml b/app/src/main/res/drawable/download_progress.xml deleted file mode 100644 index d3670c3..0000000 --- a/app/src/main/res/drawable/download_progress.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow.xml b/app/src/main/res/drawable/ic_arrow.xml deleted file mode 100644 index d0b98a0..0000000 --- a/app/src/main/res/drawable/ic_arrow.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9..0000000 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_right_black.xml b/app/src/main/res/drawable/ic_right_black.xml deleted file mode 100644 index a25faa7..0000000 --- a/app/src/main/res/drawable/ic_right_black.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/activity_satellite_status.xml b/app/src/main/res/layout/activity_satellite_status.xml index 276f5b2..6b98b2e 100644 --- a/app/src/main/res/layout/activity_satellite_status.xml +++ b/app/src/main/res/layout/activity_satellite_status.xml @@ -1,141 +1,147 @@ - - - - - + app:cardCornerRadius="@dimen/dp_5"> + android:layout_height="match_parent" + android:background="@color/lib_text_color" + android:orientation="vertical"> - - - - + app:tbv_right_image="@drawable/ic_close_white" + app:tbv_show_left_image="false" + app:tbv_show_right_image="true" + app:tbv_smaller_title="true" + app:tbv_text="卫星定位信号" + app:tbv_text_color="@color/white" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> - + - + - - - - - - - - + - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_progress.xml b/app/src/main/res/layout/dialog_progress.xml new file mode 100644 index 0000000..c21b6d0 --- /dev/null +++ b/app/src/main/res/layout/dialog_progress.xml @@ -0,0 +1,32 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt index 62af5a5..3e2703d 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt @@ -1,6 +1,5 @@ package com.casic.common.detector.gd.view -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -22,7 +21,6 @@ class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" - private val context: Context = this private lateinit var marker: MarkerLocalBean override fun initViewBinding(): ActivityObjectDetailBinding { @@ -86,7 +84,7 @@ binding.showImageView.setOnClickListener { //查数据库 if (marker.imagePath.isNullOrEmpty()) { - "此标识器无图片".show(context) + "此标识器无图片".show(this) } else { val realPaths: ArrayList = ArrayList() //真实图片路径 @@ -97,12 +95,12 @@ if (imagePath.contains(",")) { val list = imagePath.split(",") list.forEach { path -> - val url = path.appendDownloadUrl(FileType.IMAGE) + val url = path.appendDownloadUrl(FileType.Image) realPaths.add(url) } } else { //只有一张图片 - val url = imagePath.appendDownloadUrl(FileType.IMAGE) + val url = imagePath.appendDownloadUrl(FileType.Image) realPaths.add(url) } navigatePageTo(0, realPaths) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt index 94e6c46..9f2d5cd 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt @@ -51,8 +51,8 @@ window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) window.decorView.setBackgroundColor(Color.TRANSPARENT) val params = window.attributes - params.width = (getScreenWidth() * 0.965).roundToInt() - params.height = (getScreenHeight() * 0.775).roundToInt() + params.width = (getScreenWidth() * 0.97).roundToInt() + params.height = (getScreenHeight() * 0.75).roundToInt() window.attributes = params if (ActivityCompat.checkSelfPermission( diff --git a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt index f4aadf8..ddc5a32 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt @@ -1,11 +1,11 @@ package com.casic.common.detector.gd.view -import android.app.ProgressDialog +import android.content.ActivityNotFoundException +import android.content.ClipData import android.content.Intent -import android.net.Uri -import android.os.Build import android.os.Bundle import android.util.Log +import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import androidx.lifecycle.ViewModelProvider import com.casic.common.detector.gd.BuildConfig @@ -13,13 +13,13 @@ import com.casic.common.detector.gd.databinding.ActivityVersionControlBinding import com.casic.common.detector.gd.extensions.appendDownloadUrl import com.casic.common.detector.gd.extensions.initImmersionBar +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType -import com.casic.common.detector.gd.utils.LocaleConstant import com.casic.common.detector.gd.vm.VersionViewModel +import com.casic.common.detector.gd.widgets.ProgressDialog import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.createDownloadFileDir import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.TitleBarView @@ -29,19 +29,11 @@ class VersionControlActivity : KotlinBaseActivity() { private val kTag = "VersionControlActivity" - private val progressDialog by lazy { ProgressDialog(this) } private lateinit var versionViewModel: VersionViewModel override fun initOnCreate(savedInstanceState: Bundle?) { binding.versionView.text = "Version ${BuildConfig.VERSION_NAME}" - //初始化下载对话框 - progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) - progressDialog.setProgressDrawable(resources.getDrawable(R.drawable.download_progress)) - progressDialog.setCanceledOnTouchOutside(false) - progressDialog.setCancelable(false) - progressDialog.max = 0 - versionViewModel = ViewModelProvider(this)[VersionViewModel::class.java] versionViewModel.versionResult.observe(this) { if (it.version.toInt() > BuildConfig.VERSION_CODE) { @@ -101,60 +93,57 @@ } private fun downloadApk(url: String?) { - progressDialog.setMessage("下载新版本中...") - progressDialog.show() - if (url.toString().isBlank()) { - "抱歉,版本下载失败".show(this) + if (url.isNullOrBlank()) { + "下载路径为空,版本下载失败".show(this) return } + val progressDialog = ProgressDialog(this) + progressDialog.show() /** * http://139.198.18.188:8090/ems/apk/EMSCJTX202011052026(V3.14.0).apk * */ - val downloadPath = url!!.appendDownloadUrl(FileType.APK) + val downloadPath = url.appendDownloadUrl(FileType.Apk) Log.d(kTag, "downloadApk => $downloadPath") - //开始下载 FileDownloadManager.Builder() .setDownloadFileSource(downloadPath) .setFileSuffix("apk") .setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + progressDialog.setMaxProgress(total) + } + override fun onDownloadEnd(file: File) { progressDialog.dismiss() - progressDialog.progress = 0 - //安装APK installApk(file) } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() + progressDialog.dismiss() } - override fun onProgressChanged(progress: Int) { - progressDialog.progress = progress + override fun onProgressChanged(progress: Long) { + progressDialog.updateProgress(progress) } - }) - .build() - .start() + }).build().start() } - private fun installApk(apkPackage: File?) { - if (apkPackage == null) { - "安装文件异常,无法安装".show(this) - return + private fun installApk(file: File) { + val apkUri = FileProvider.getUriForFile(this, "${packageName}.provider", file) + val mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension("apk") ?: "application/vnd.android.package-archive" + val intent = Intent(Intent.ACTION_VIEW).apply { + setDataAndType(apkUri, mimeType) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) + // 授予持久化 URI 权限 + clipData = ClipData.newRawUri("", apkUri) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) } - val intent = Intent(Intent.ACTION_VIEW) - val data: Uri - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //判断版本大于等于7.0 - data = FileProvider.getUriForFile(this, LocaleConstant.APP_AUTHORITY, apkPackage) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 给目标应用一个临时授权 - } else { - data = Uri.fromFile(apkPackage) + try { + this.startActivity(intent) + } catch (e: ActivityNotFoundException) { + e.printStackTrace() } - /** - * android 10 - * content://com.casic.app.smartwell.fileprovider/smartWell/Download/1.0.1.apk - * */ - intent.setDataAndType(data, "application/vnd.android.package-archive") - startActivity(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt new file mode 100644 index 0000000..af480b0 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt @@ -0,0 +1,36 @@ +package com.casic.common.detector.gd.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.casic.common.detector.gd.databinding.DialogProgressBinding +import com.pengxh.kt.lite.R +import com.pengxh.kt.lite.extensions.binding +import com.pengxh.kt.lite.extensions.initDialogLayoutParams + +class ProgressDialog(context: Context) : Dialog(context, R.style.UserDefinedDialogStyle) { + + private val binding: DialogProgressBinding by binding() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(0.5f) + setCanceledOnTouchOutside(false) + setCancelable(false) + binding.progressBar.progress = 0 + binding.progressText.text = "0 %" + } + + fun setMaxProgress(maxProgress: Long) { + binding.progressBar.max = maxProgress.toInt() + } + + private fun getMaxProgress() = binding.progressBar.max + + fun updateProgress(progress: Long) { + binding.progressBar.progress = progress.toInt() + + val percent = (progress.toFloat() / getMaxProgress()) * 100 + binding.progressText.text = String.format("%.2f %%", percent) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/download_progress.xml b/app/src/main/res/drawable/download_progress.xml deleted file mode 100644 index d3670c3..0000000 --- a/app/src/main/res/drawable/download_progress.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow.xml b/app/src/main/res/drawable/ic_arrow.xml deleted file mode 100644 index d0b98a0..0000000 --- a/app/src/main/res/drawable/ic_arrow.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9..0000000 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_right_black.xml b/app/src/main/res/drawable/ic_right_black.xml deleted file mode 100644 index a25faa7..0000000 --- a/app/src/main/res/drawable/ic_right_black.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/activity_satellite_status.xml b/app/src/main/res/layout/activity_satellite_status.xml index 276f5b2..6b98b2e 100644 --- a/app/src/main/res/layout/activity_satellite_status.xml +++ b/app/src/main/res/layout/activity_satellite_status.xml @@ -1,141 +1,147 @@ - - - - - + app:cardCornerRadius="@dimen/dp_5"> + android:layout_height="match_parent" + android:background="@color/lib_text_color" + android:orientation="vertical"> - - - - + app:tbv_right_image="@drawable/ic_close_white" + app:tbv_show_left_image="false" + app:tbv_show_right_image="true" + app:tbv_smaller_title="true" + app:tbv_text="卫星定位信号" + app:tbv_text_color="@color/white" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> - + - + - - - - - - - - + - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_progress.xml b/app/src/main/res/layout/dialog_progress.xml new file mode 100644 index 0000000..c21b6d0 --- /dev/null +++ b/app/src/main/res/layout/dialog_progress.xml @@ -0,0 +1,32 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-xhdpi/bg_needle.png b/app/src/main/res/mipmap-xhdpi/bg_needle.png deleted file mode 100644 index ece3665..0000000 --- a/app/src/main/res/mipmap-xhdpi/bg_needle.png +++ /dev/null Binary files differ diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt index 62af5a5..3e2703d 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt @@ -1,6 +1,5 @@ package com.casic.common.detector.gd.view -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -22,7 +21,6 @@ class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" - private val context: Context = this private lateinit var marker: MarkerLocalBean override fun initViewBinding(): ActivityObjectDetailBinding { @@ -86,7 +84,7 @@ binding.showImageView.setOnClickListener { //查数据库 if (marker.imagePath.isNullOrEmpty()) { - "此标识器无图片".show(context) + "此标识器无图片".show(this) } else { val realPaths: ArrayList = ArrayList() //真实图片路径 @@ -97,12 +95,12 @@ if (imagePath.contains(",")) { val list = imagePath.split(",") list.forEach { path -> - val url = path.appendDownloadUrl(FileType.IMAGE) + val url = path.appendDownloadUrl(FileType.Image) realPaths.add(url) } } else { //只有一张图片 - val url = imagePath.appendDownloadUrl(FileType.IMAGE) + val url = imagePath.appendDownloadUrl(FileType.Image) realPaths.add(url) } navigatePageTo(0, realPaths) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt index 94e6c46..9f2d5cd 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt @@ -51,8 +51,8 @@ window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) window.decorView.setBackgroundColor(Color.TRANSPARENT) val params = window.attributes - params.width = (getScreenWidth() * 0.965).roundToInt() - params.height = (getScreenHeight() * 0.775).roundToInt() + params.width = (getScreenWidth() * 0.97).roundToInt() + params.height = (getScreenHeight() * 0.75).roundToInt() window.attributes = params if (ActivityCompat.checkSelfPermission( diff --git a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt index f4aadf8..ddc5a32 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt @@ -1,11 +1,11 @@ package com.casic.common.detector.gd.view -import android.app.ProgressDialog +import android.content.ActivityNotFoundException +import android.content.ClipData import android.content.Intent -import android.net.Uri -import android.os.Build import android.os.Bundle import android.util.Log +import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import androidx.lifecycle.ViewModelProvider import com.casic.common.detector.gd.BuildConfig @@ -13,13 +13,13 @@ import com.casic.common.detector.gd.databinding.ActivityVersionControlBinding import com.casic.common.detector.gd.extensions.appendDownloadUrl import com.casic.common.detector.gd.extensions.initImmersionBar +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType -import com.casic.common.detector.gd.utils.LocaleConstant import com.casic.common.detector.gd.vm.VersionViewModel +import com.casic.common.detector.gd.widgets.ProgressDialog import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.createDownloadFileDir import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.TitleBarView @@ -29,19 +29,11 @@ class VersionControlActivity : KotlinBaseActivity() { private val kTag = "VersionControlActivity" - private val progressDialog by lazy { ProgressDialog(this) } private lateinit var versionViewModel: VersionViewModel override fun initOnCreate(savedInstanceState: Bundle?) { binding.versionView.text = "Version ${BuildConfig.VERSION_NAME}" - //初始化下载对话框 - progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) - progressDialog.setProgressDrawable(resources.getDrawable(R.drawable.download_progress)) - progressDialog.setCanceledOnTouchOutside(false) - progressDialog.setCancelable(false) - progressDialog.max = 0 - versionViewModel = ViewModelProvider(this)[VersionViewModel::class.java] versionViewModel.versionResult.observe(this) { if (it.version.toInt() > BuildConfig.VERSION_CODE) { @@ -101,60 +93,57 @@ } private fun downloadApk(url: String?) { - progressDialog.setMessage("下载新版本中...") - progressDialog.show() - if (url.toString().isBlank()) { - "抱歉,版本下载失败".show(this) + if (url.isNullOrBlank()) { + "下载路径为空,版本下载失败".show(this) return } + val progressDialog = ProgressDialog(this) + progressDialog.show() /** * http://139.198.18.188:8090/ems/apk/EMSCJTX202011052026(V3.14.0).apk * */ - val downloadPath = url!!.appendDownloadUrl(FileType.APK) + val downloadPath = url.appendDownloadUrl(FileType.Apk) Log.d(kTag, "downloadApk => $downloadPath") - //开始下载 FileDownloadManager.Builder() .setDownloadFileSource(downloadPath) .setFileSuffix("apk") .setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + progressDialog.setMaxProgress(total) + } + override fun onDownloadEnd(file: File) { progressDialog.dismiss() - progressDialog.progress = 0 - //安装APK installApk(file) } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() + progressDialog.dismiss() } - override fun onProgressChanged(progress: Int) { - progressDialog.progress = progress + override fun onProgressChanged(progress: Long) { + progressDialog.updateProgress(progress) } - }) - .build() - .start() + }).build().start() } - private fun installApk(apkPackage: File?) { - if (apkPackage == null) { - "安装文件异常,无法安装".show(this) - return + private fun installApk(file: File) { + val apkUri = FileProvider.getUriForFile(this, "${packageName}.provider", file) + val mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension("apk") ?: "application/vnd.android.package-archive" + val intent = Intent(Intent.ACTION_VIEW).apply { + setDataAndType(apkUri, mimeType) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) + // 授予持久化 URI 权限 + clipData = ClipData.newRawUri("", apkUri) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) } - val intent = Intent(Intent.ACTION_VIEW) - val data: Uri - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //判断版本大于等于7.0 - data = FileProvider.getUriForFile(this, LocaleConstant.APP_AUTHORITY, apkPackage) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 给目标应用一个临时授权 - } else { - data = Uri.fromFile(apkPackage) + try { + this.startActivity(intent) + } catch (e: ActivityNotFoundException) { + e.printStackTrace() } - /** - * android 10 - * content://com.casic.app.smartwell.fileprovider/smartWell/Download/1.0.1.apk - * */ - intent.setDataAndType(data, "application/vnd.android.package-archive") - startActivity(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt new file mode 100644 index 0000000..af480b0 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt @@ -0,0 +1,36 @@ +package com.casic.common.detector.gd.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.casic.common.detector.gd.databinding.DialogProgressBinding +import com.pengxh.kt.lite.R +import com.pengxh.kt.lite.extensions.binding +import com.pengxh.kt.lite.extensions.initDialogLayoutParams + +class ProgressDialog(context: Context) : Dialog(context, R.style.UserDefinedDialogStyle) { + + private val binding: DialogProgressBinding by binding() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(0.5f) + setCanceledOnTouchOutside(false) + setCancelable(false) + binding.progressBar.progress = 0 + binding.progressText.text = "0 %" + } + + fun setMaxProgress(maxProgress: Long) { + binding.progressBar.max = maxProgress.toInt() + } + + private fun getMaxProgress() = binding.progressBar.max + + fun updateProgress(progress: Long) { + binding.progressBar.progress = progress.toInt() + + val percent = (progress.toFloat() / getMaxProgress()) * 100 + binding.progressText.text = String.format("%.2f %%", percent) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/download_progress.xml b/app/src/main/res/drawable/download_progress.xml deleted file mode 100644 index d3670c3..0000000 --- a/app/src/main/res/drawable/download_progress.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow.xml b/app/src/main/res/drawable/ic_arrow.xml deleted file mode 100644 index d0b98a0..0000000 --- a/app/src/main/res/drawable/ic_arrow.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9..0000000 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_right_black.xml b/app/src/main/res/drawable/ic_right_black.xml deleted file mode 100644 index a25faa7..0000000 --- a/app/src/main/res/drawable/ic_right_black.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/activity_satellite_status.xml b/app/src/main/res/layout/activity_satellite_status.xml index 276f5b2..6b98b2e 100644 --- a/app/src/main/res/layout/activity_satellite_status.xml +++ b/app/src/main/res/layout/activity_satellite_status.xml @@ -1,141 +1,147 @@ - - - - - + app:cardCornerRadius="@dimen/dp_5"> + android:layout_height="match_parent" + android:background="@color/lib_text_color" + android:orientation="vertical"> - - - - + app:tbv_right_image="@drawable/ic_close_white" + app:tbv_show_left_image="false" + app:tbv_show_right_image="true" + app:tbv_smaller_title="true" + app:tbv_text="卫星定位信号" + app:tbv_text_color="@color/white" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> - + - + - - - - - - - - + - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_progress.xml b/app/src/main/res/layout/dialog_progress.xml new file mode 100644 index 0000000..c21b6d0 --- /dev/null +++ b/app/src/main/res/layout/dialog_progress.xml @@ -0,0 +1,32 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-xhdpi/bg_needle.png b/app/src/main/res/mipmap-xhdpi/bg_needle.png deleted file mode 100644 index ece3665..0000000 --- a/app/src/main/res/mipmap-xhdpi/bg_needle.png +++ /dev/null Binary files differ diff --git a/app/src/main/res/mipmap-xhdpi/center_screen.png b/app/src/main/res/mipmap-xhdpi/center_screen.png deleted file mode 100644 index 1c1b201..0000000 --- a/app/src/main/res/mipmap-xhdpi/center_screen.png +++ /dev/null Binary files differ diff --git a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt b/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt deleted file mode 100644 index 3f5a070..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/callback/OnSerialPortListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.common.detector.gd.callback - -interface OnSerialPortListener { - fun onDataReceived(buffer: ByteArray) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt deleted file mode 100644 index d3bd42a..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ArrayList.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.casic.common.detector.gd.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/common/detector/gd/extensions/Int.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt deleted file mode 100644 index 3aefa3d..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/Int.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.casic.common.detector.gd.extensions - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.RectF - -fun Int.drawCircle(color: Int): Bitmap? { - val bitmap = Bitmap.createBitmap(this * 2, this * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - val paint = Paint() - val rectF = RectF(0f, 0f, (this * 2).toFloat(), (this * 2).toFloat()) - paint.color = color - canvas.drawArc(rectF, 0f, 360f, true, paint) - return bitmap -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index 47853a4..28eb42a 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -33,15 +33,6 @@ return jsonObject.get("message").asString } -fun String.getResponseCode(): Int { - if (this.isBlank()) { - return 404 - } - val element = JsonParser.parseString(this) - val jsonObject = element.asJsonObject - return jsonObject.get("code").asInt -} - /** * 下载路径为 http://xx.com/static/ 拼接downloadUrl * */ @@ -51,9 +42,9 @@ val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String val httpConfig = "http://${serverIp}:${serverPort}" return when (type) { - FileType.APK -> "$httpConfig/ems/${this}" - FileType.EXCEL -> "$httpConfig/ems/xls/marker${this}.xls" - FileType.IMAGE -> "$httpConfig/ems${this}" + FileType.Apk -> "$httpConfig/ems/${this}" + FileType.Excel -> "$httpConfig/ems/xls/marker${this}.xls" + FileType.Image -> "$httpConfig/ems${this}" } } diff --git a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt index 39caffd..5f6c701 100644 --- a/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/common/detector/gd/retrofit/RetrofitServiceManager.kt @@ -1,8 +1,6 @@ package com.casic.common.detector.gd.retrofit -import com.casic.common.detector.gd.extensions.reformat import com.casic.common.detector.gd.utils.LocaleConstant -import com.google.gson.Gson import com.google.gson.JsonObject import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues @@ -15,8 +13,6 @@ object RetrofitServiceManager { - private val gson by lazy { Gson() } - private fun createApi(): RetrofitService { val serverIp = SaveKeyValues.getValue(LocaleConstant.SERVER_IP, "") as String val serverPort = SaveKeyValues.getValue(LocaleConstant.SERVER_PORT, "") as String @@ -223,7 +219,7 @@ suspend fun uploadTaskMarker(taskId: String, ids: ArrayList): String { val param = JsonObject() param.addProperty("taskId", taskId) - param.addProperty("ids", ids.reformat()) + param.addProperty("ids", ids.joinToString(separator = ",")) val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) diff --git a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt index 1b551b3..de9ac80 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/NtripConnectService.kt @@ -50,9 +50,7 @@ override fun handleMessage(msg: Message): Boolean { if (msg.what == 2024082201) { - lifecycleScope.launch(Dispatchers.IO) { - connectQianXunServer() - } + connectQianXunServer() } return true } @@ -169,6 +167,8 @@ return } - socketClient.start(remoteHost, remotePort.toInt()) + lifecycleScope.launch(Dispatchers.IO) { + socketClient.start(remoteHost, remotePort.toInt()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt new file mode 100644 index 0000000..c9151a8 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileDownloadManager.kt @@ -0,0 +1,150 @@ +package com.casic.common.detector.gd.utils + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.File +import java.io.IOException +import java.util.concurrent.atomic.AtomicBoolean + +class FileDownloadManager(builder: Builder) { + + private val httpClient by lazy { OkHttpClient() } + + class Builder { + lateinit var url: String + lateinit var suffix: String + lateinit var directory: File + lateinit var downloadListener: OnFileDownloadListener + + /** + * 文件下载地址 + * */ + fun setDownloadFileSource(url: String): Builder { + this.url = url + return this + } + + /** + * 文件后缀 + * 如:apk等 + * */ + fun setFileSuffix(suffix: String): Builder { + this.suffix = if (suffix.contains(".")) { + //去掉前缀的点 + suffix.drop(1) + } else { + suffix + } + return this + } + + /** + * 文件保存的地址 + * */ + fun setFileSaveDirectory(directory: File): Builder { + this.directory = directory + return this + } + + /** + * 设置文件下载回调监听 + * */ + fun setOnFileDownloadListener(downloadListener: OnFileDownloadListener): Builder { + this.downloadListener = downloadListener + return this + } + + fun build(): FileDownloadManager { + if (!::url.isInitialized || !::suffix.isInitialized || !::directory.isInitialized || !::downloadListener.isInitialized) { + throw IllegalStateException("All properties must be initialized before building.") + } + return FileDownloadManager(this) + } + } + + private val url = builder.url + private val suffix = builder.suffix + private val directory = builder.directory + private val listener = builder.downloadListener + + /** + * 开始下载 + * */ + fun start() { + val job = SupervisorJob() + val scope = CoroutineScope(Dispatchers.Main + job) + + val request = Request.Builder().get().url(url).build() + val newCall = httpClient.newCall(request) + val isExecuting = AtomicBoolean(false) + + /** + * 如果已被加入下载队列,则取消之前的,重新下载 + */ + if (isExecuting.getAndSet(true)) { + newCall.cancel() + } + + //异步下载文件 + newCall.enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + scope.launch(Dispatchers.Main) { + listener.onFailed(e) + } + } + + override fun onResponse(call: Call, response: Response) { + scope.launch(Dispatchers.IO) { + val body = response.body + if (body == null) { + listener.onFailed(IOException("Response body is null")) + throw IOException("Response body is null") + } else { + val inputStream = body.byteStream() + val fileSize = body.contentLength() + + if (fileSize <= 0) { + throw IllegalArgumentException("Invalid file size") + } + listener.onDownloadStart(fileSize) + + val file = File(directory, "${System.currentTimeMillis()}.${suffix}") + file.outputStream().use { fos -> + val buffer = ByteArray(2048) + var sum = 0L + var read: Int + while (inputStream.read(buffer).also { read = it } != -1) { + fos.write(buffer, 0, read) + sum += read.toLong() + withContext(Dispatchers.Main) { + listener.onProgressChanged(sum) + } + } + } + + withContext(Dispatchers.Main) { + listener.onDownloadEnd(file) + } + + job.cancel() + } + } + } + }) + } + + interface OnFileDownloadListener { + fun onDownloadStart(total: Long) + fun onProgressChanged(progress: Long) + fun onDownloadEnd(file: File) + fun onFailed(t: Throwable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt index 8ebea92..97db48e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/FileType.kt @@ -1,9 +1,9 @@ package com.casic.common.detector.gd.utils sealed class FileType { - object APK : FileType() + object Apk : FileType() - object EXCEL : FileType() + object Excel : FileType() - object IMAGE : FileType() + object Image : FileType() } diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt index 05c4e5b..63089b3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/NtripAuthorizationCreator.kt @@ -11,15 +11,10 @@ } override fun toString(): String { - val builder = StringBuilder() - for (i in 0 until this.size) { - val s = this[i] - if (i == this.size - 1) { - builder.append(s).append("\r\n\r\n") - } else { - builder.append(s).append("\r\n") - } + if (this.isEmpty()) { + return "" } - return builder.toString() + + return this.joinToString(separator = "\r\n", postfix = "\r\n\r\n") } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt index 1a131eb..16a5db8 100644 --- a/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt +++ b/app/src/main/java/com/casic/common/detector/gd/utils/RTK.kt @@ -46,17 +46,10 @@ locationManager, object : GnssStatusCompat.Callback() { override fun onSatelliteStatusChanged(status: GnssStatusCompat) { super.onSatelliteStatusChanged(status) - // 可以搜索到的卫星总数 - val satelliteCount = status.satelliteCount var effectiveCount = 0 - for (index in 0 until satelliteCount) { - /** - * 每个卫星的载波噪声密度,噪声密度越大,信号越强。 - *
- * 参考:https://juejin.cn/post/7144313606329335815 - * */ - val cn0DbHz = status.getCn0DbHz(index) - if (cn0DbHz > 20) { + for (i in 0 until status.satelliteCount) { + // 判断卫星是否已锁定,数据可用 + if (status.usedInFix(i)) { effectiveCount++ } } diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 16f71d9..8a798b6 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -51,6 +51,7 @@ import com.casic.common.detector.gd.utils.CurrentSegment import com.casic.common.detector.gd.utils.DataBaseManager import com.casic.common.detector.gd.utils.ExcelKit +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.GpioManager import com.casic.common.detector.gd.utils.LocaleConstant @@ -68,7 +69,6 @@ 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.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.utils.SaveKeyValues @@ -196,22 +196,26 @@ DataBaseManager.get.clearMarkers() //下载最新的数据 val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") - val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL) + val downloadUrl = companyId.toString().appendDownloadUrl(FileType.Excel) Log.d(kTag, "downloadUrl => $downloadUrl") FileDownloadManager.Builder().setDownloadFileSource(downloadUrl) .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + + } + override fun onDownloadEnd(file: File) { lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } LoadingDialog.dismiss() showMarkersOnMap() } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() } - override fun onProgressChanged(progress: Int) { + override fun onProgressChanged(progress: Long) { } }).build().start() @@ -281,9 +285,7 @@ }).build().show() } else { lifecycleScope.launch(Dispatchers.Main) { - val markers = withContext(Dispatchers.IO) { - DataBaseManager.get.queryMarkerByState("0") - } + val markers = DataBaseManager.get.queryMarkerByState("0") //如果有需要补全的标识器,Popup右侧会有小圆点提示 if (markers.isNotEmpty()) { samplePopupWindow.setShowPosition(4) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt index 62af5a5..3e2703d 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/ObjectDetailActivity.kt @@ -1,6 +1,5 @@ package com.casic.common.detector.gd.view -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -22,7 +21,6 @@ class ObjectDetailActivity : KotlinBaseActivity() { private val kTag = "ObjectDetailActivity" - private val context: Context = this private lateinit var marker: MarkerLocalBean override fun initViewBinding(): ActivityObjectDetailBinding { @@ -86,7 +84,7 @@ binding.showImageView.setOnClickListener { //查数据库 if (marker.imagePath.isNullOrEmpty()) { - "此标识器无图片".show(context) + "此标识器无图片".show(this) } else { val realPaths: ArrayList = ArrayList() //真实图片路径 @@ -97,12 +95,12 @@ if (imagePath.contains(",")) { val list = imagePath.split(",") list.forEach { path -> - val url = path.appendDownloadUrl(FileType.IMAGE) + val url = path.appendDownloadUrl(FileType.Image) realPaths.add(url) } } else { //只有一张图片 - val url = imagePath.appendDownloadUrl(FileType.IMAGE) + val url = imagePath.appendDownloadUrl(FileType.Image) realPaths.add(url) } navigatePageTo(0, realPaths) diff --git a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt index 94e6c46..9f2d5cd 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/SatelliteStatusActivity.kt @@ -51,8 +51,8 @@ window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) window.decorView.setBackgroundColor(Color.TRANSPARENT) val params = window.attributes - params.width = (getScreenWidth() * 0.965).roundToInt() - params.height = (getScreenHeight() * 0.775).roundToInt() + params.width = (getScreenWidth() * 0.97).roundToInt() + params.height = (getScreenHeight() * 0.75).roundToInt() window.attributes = params if (ActivityCompat.checkSelfPermission( diff --git a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt index f4aadf8..ddc5a32 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/VersionControlActivity.kt @@ -1,11 +1,11 @@ package com.casic.common.detector.gd.view -import android.app.ProgressDialog +import android.content.ActivityNotFoundException +import android.content.ClipData import android.content.Intent -import android.net.Uri -import android.os.Build import android.os.Bundle import android.util.Log +import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import androidx.lifecycle.ViewModelProvider import com.casic.common.detector.gd.BuildConfig @@ -13,13 +13,13 @@ import com.casic.common.detector.gd.databinding.ActivityVersionControlBinding import com.casic.common.detector.gd.extensions.appendDownloadUrl import com.casic.common.detector.gd.extensions.initImmersionBar +import com.casic.common.detector.gd.utils.FileDownloadManager import com.casic.common.detector.gd.utils.FileType -import com.casic.common.detector.gd.utils.LocaleConstant import com.casic.common.detector.gd.vm.VersionViewModel +import com.casic.common.detector.gd.widgets.ProgressDialog import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.createDownloadFileDir import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.FileDownloadManager import com.pengxh.kt.lite.utils.LoadState import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.TitleBarView @@ -29,19 +29,11 @@ class VersionControlActivity : KotlinBaseActivity() { private val kTag = "VersionControlActivity" - private val progressDialog by lazy { ProgressDialog(this) } private lateinit var versionViewModel: VersionViewModel override fun initOnCreate(savedInstanceState: Bundle?) { binding.versionView.text = "Version ${BuildConfig.VERSION_NAME}" - //初始化下载对话框 - progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) - progressDialog.setProgressDrawable(resources.getDrawable(R.drawable.download_progress)) - progressDialog.setCanceledOnTouchOutside(false) - progressDialog.setCancelable(false) - progressDialog.max = 0 - versionViewModel = ViewModelProvider(this)[VersionViewModel::class.java] versionViewModel.versionResult.observe(this) { if (it.version.toInt() > BuildConfig.VERSION_CODE) { @@ -101,60 +93,57 @@ } private fun downloadApk(url: String?) { - progressDialog.setMessage("下载新版本中...") - progressDialog.show() - if (url.toString().isBlank()) { - "抱歉,版本下载失败".show(this) + if (url.isNullOrBlank()) { + "下载路径为空,版本下载失败".show(this) return } + val progressDialog = ProgressDialog(this) + progressDialog.show() /** * http://139.198.18.188:8090/ems/apk/EMSCJTX202011052026(V3.14.0).apk * */ - val downloadPath = url!!.appendDownloadUrl(FileType.APK) + val downloadPath = url.appendDownloadUrl(FileType.Apk) Log.d(kTag, "downloadApk => $downloadPath") - //开始下载 FileDownloadManager.Builder() .setDownloadFileSource(downloadPath) .setFileSuffix("apk") .setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { + override fun onDownloadStart(total: Long) { + progressDialog.setMaxProgress(total) + } + override fun onDownloadEnd(file: File) { progressDialog.dismiss() - progressDialog.progress = 0 - //安装APK installApk(file) } - override fun onFailure(throwable: Throwable) { - + override fun onFailed(t: Throwable) { + t.printStackTrace() + progressDialog.dismiss() } - override fun onProgressChanged(progress: Int) { - progressDialog.progress = progress + override fun onProgressChanged(progress: Long) { + progressDialog.updateProgress(progress) } - }) - .build() - .start() + }).build().start() } - private fun installApk(apkPackage: File?) { - if (apkPackage == null) { - "安装文件异常,无法安装".show(this) - return + private fun installApk(file: File) { + val apkUri = FileProvider.getUriForFile(this, "${packageName}.provider", file) + val mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension("apk") ?: "application/vnd.android.package-archive" + val intent = Intent(Intent.ACTION_VIEW).apply { + setDataAndType(apkUri, mimeType) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) + // 授予持久化 URI 权限 + clipData = ClipData.newRawUri("", apkUri) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) } - val intent = Intent(Intent.ACTION_VIEW) - val data: Uri - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //判断版本大于等于7.0 - data = FileProvider.getUriForFile(this, LocaleConstant.APP_AUTHORITY, apkPackage) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 给目标应用一个临时授权 - } else { - data = Uri.fromFile(apkPackage) + try { + this.startActivity(intent) + } catch (e: ActivityNotFoundException) { + e.printStackTrace() } - /** - * android 10 - * content://com.casic.app.smartwell.fileprovider/smartWell/Download/1.0.1.apk - * */ - intent.setDataAndType(data, "application/vnd.android.package-archive") - startActivity(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt new file mode 100644 index 0000000..af480b0 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/widgets/ProgressDialog.kt @@ -0,0 +1,36 @@ +package com.casic.common.detector.gd.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.casic.common.detector.gd.databinding.DialogProgressBinding +import com.pengxh.kt.lite.R +import com.pengxh.kt.lite.extensions.binding +import com.pengxh.kt.lite.extensions.initDialogLayoutParams + +class ProgressDialog(context: Context) : Dialog(context, R.style.UserDefinedDialogStyle) { + + private val binding: DialogProgressBinding by binding() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(0.5f) + setCanceledOnTouchOutside(false) + setCancelable(false) + binding.progressBar.progress = 0 + binding.progressText.text = "0 %" + } + + fun setMaxProgress(maxProgress: Long) { + binding.progressBar.max = maxProgress.toInt() + } + + private fun getMaxProgress() = binding.progressBar.max + + fun updateProgress(progress: Long) { + binding.progressBar.progress = progress.toInt() + + val percent = (progress.toFloat() / getMaxProgress()) * 100 + binding.progressText.text = String.format("%.2f %%", percent) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/download_progress.xml b/app/src/main/res/drawable/download_progress.xml deleted file mode 100644 index d3670c3..0000000 --- a/app/src/main/res/drawable/download_progress.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow.xml b/app/src/main/res/drawable/ic_arrow.xml deleted file mode 100644 index d0b98a0..0000000 --- a/app/src/main/res/drawable/ic_arrow.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9..0000000 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_right_black.xml b/app/src/main/res/drawable/ic_right_black.xml deleted file mode 100644 index a25faa7..0000000 --- a/app/src/main/res/drawable/ic_right_black.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/activity_satellite_status.xml b/app/src/main/res/layout/activity_satellite_status.xml index 276f5b2..6b98b2e 100644 --- a/app/src/main/res/layout/activity_satellite_status.xml +++ b/app/src/main/res/layout/activity_satellite_status.xml @@ -1,141 +1,147 @@ - - - - - + app:cardCornerRadius="@dimen/dp_5"> + android:layout_height="match_parent" + android:background="@color/lib_text_color" + android:orientation="vertical"> - - - - + app:tbv_right_image="@drawable/ic_close_white" + app:tbv_show_left_image="false" + app:tbv_show_right_image="true" + app:tbv_smaller_title="true" + app:tbv_text="卫星定位信号" + app:tbv_text_color="@color/white" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> - + - + - - - - - - - - + - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_progress.xml b/app/src/main/res/layout/dialog_progress.xml new file mode 100644 index 0000000..c21b6d0 --- /dev/null +++ b/app/src/main/res/layout/dialog_progress.xml @@ -0,0 +1,32 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-xhdpi/bg_needle.png b/app/src/main/res/mipmap-xhdpi/bg_needle.png deleted file mode 100644 index ece3665..0000000 --- a/app/src/main/res/mipmap-xhdpi/bg_needle.png +++ /dev/null Binary files differ diff --git a/app/src/main/res/mipmap-xhdpi/center_screen.png b/app/src/main/res/mipmap-xhdpi/center_screen.png deleted file mode 100644 index 1c1b201..0000000 --- a/app/src/main/res/mipmap-xhdpi/center_screen.png +++ /dev/null Binary files differ diff --git a/app/src/main/res/mipmap-xhdpi/dashboard.png b/app/src/main/res/mipmap-xhdpi/dashboard.png deleted file mode 100644 index b3c541c..0000000 --- a/app/src/main/res/mipmap-xhdpi/dashboard.png +++ /dev/null Binary files differ