1.修复轨迹和宠物有时不在一条线上的bug
2.增加pet页切换刷新运动数据 3.修复绑定设备激活重启,此时点击太快进入wifi 搜索不到bug 4.蓝牙透传通路由Raw TCP改为Https
This commit is contained in:
@@ -28,9 +28,9 @@ android {
|
|||||||
applicationId "com.abbidot.tracker"
|
applicationId "com.abbidot.tracker"
|
||||||
minSdkVersion 24
|
minSdkVersion 24
|
||||||
targetSdkVersion 35
|
targetSdkVersion 35
|
||||||
versionCode 2216
|
versionCode 2300
|
||||||
// versionName "2.2.16"
|
// versionName "2.3.0"
|
||||||
versionName "2.2.16-Beta1"
|
versionName "2.3.0-Beta1"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.abbidot.baselibrary.constant.MMKVKey
|
|||||||
import com.abbidot.baselibrary.util.MMKVUtil
|
import com.abbidot.baselibrary.util.MMKVUtil
|
||||||
import com.abbidot.baselibrary.util.Utils
|
import com.abbidot.baselibrary.util.Utils
|
||||||
import com.abbidot.tracker.base.BaseDiffBean
|
import com.abbidot.tracker.base.BaseDiffBean
|
||||||
|
import com.abbidot.tracker.retrofit2.INetworkService
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,12 +39,13 @@ data class PetBean(
|
|||||||
var availableOrder: Int,//判断套餐是否可用或过期,1是可用 0不可用
|
var availableOrder: Int,//判断套餐是否可用或过期,1是可用 0不可用
|
||||||
var latitude: Double,
|
var latitude: Double,
|
||||||
var longitude: Double,
|
var longitude: Double,
|
||||||
|
var serverDomain: String,
|
||||||
var deviceId: String
|
var deviceId: String
|
||||||
) : Parcelable, BaseDiffBean() {
|
) : Parcelable, BaseDiffBean() {
|
||||||
constructor() : this(
|
constructor() : this(
|
||||||
"", "", "", "", 0, 1, MMKVUtil.getString(MMKVKey.UserId), "", 0, Utils.formatTime(
|
"", "", "", "", 0, 1, MMKVUtil.getString(MMKVKey.UserId), "", 0, Utils.formatTime(
|
||||||
System.currentTimeMillis(), Utils.DATE_FORMAT_PATTERN_CN
|
System.currentTimeMillis(), Utils.DATE_FORMAT_PATTERN_CN
|
||||||
), "", 0f, 0f, "", "", "", 1, 1, "", false, false, 1, 0.0, 0.0, ""
|
), "", 0f, 0f, "", "", "", 1, 1, "", false, false, 1, 0.0, 0.0, INetworkService.BASE_URL_BLE, ""
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun isSameObject(other: Any): Boolean {
|
override fun isSameObject(other: Any): Boolean {
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ import com.abbidot.tracker.bean.UserInfoBean
|
|||||||
import com.abbidot.tracker.bean.WXPayOrderBean
|
import com.abbidot.tracker.bean.WXPayOrderBean
|
||||||
import com.abbidot.tracker.bean.WiFiZoneListBean
|
import com.abbidot.tracker.bean.WiFiZoneListBean
|
||||||
import okhttp3.MultipartBody
|
import okhttp3.MultipartBody
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import retrofit2.Response
|
||||||
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.Field
|
import retrofit2.http.Field
|
||||||
import retrofit2.http.FormUrlEncoded
|
import retrofit2.http.FormUrlEncoded
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
@@ -44,6 +48,7 @@ import retrofit2.http.Multipart
|
|||||||
import retrofit2.http.POST
|
import retrofit2.http.POST
|
||||||
import retrofit2.http.Part
|
import retrofit2.http.Part
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
import retrofit2.http.Url
|
||||||
|
|
||||||
interface INetworkService {
|
interface INetworkService {
|
||||||
|
|
||||||
@@ -57,6 +62,9 @@ interface INetworkService {
|
|||||||
//亚马逊服务器(国外ip)
|
//亚马逊服务器(国外ip)
|
||||||
const val BASE_URL_ABROAD = "https://aws.abbidot.com/abbidot/"
|
const val BASE_URL_ABROAD = "https://aws.abbidot.com/abbidot/"
|
||||||
|
|
||||||
|
//设备透传
|
||||||
|
const val BASE_URL_BLE = "https://ab-server.abbidot.cn/"
|
||||||
|
|
||||||
//测试服务器
|
//测试服务器
|
||||||
const val BASE_URL_TEST = "https://aws.abbidot.com:8443/abbidot/"
|
const val BASE_URL_TEST = "https://aws.abbidot.com:8443/abbidot/"
|
||||||
// const val BASE_URL_TEST = "http://aws.abbidot.com:8089/abbidot/"
|
// const val BASE_URL_TEST = "http://aws.abbidot.com:8089/abbidot/"
|
||||||
@@ -80,6 +88,13 @@ interface INetworkService {
|
|||||||
// const val BASE_URL_CN1 = "$SERVER_IP_CN/abbidotServer/"
|
// const val BASE_URL_CN1 = "$SERVER_IP_CN/abbidotServer/"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 蓝牙透传机制从TCP迁移到https
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
// @Url 一定要传入以“/”结尾注解会替换 baseUrl,每次调用可传入完整 URL
|
||||||
|
suspend fun blePassThrough(@Url url: String, @Body body: RequestBody): Response<ResponseBody>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取国家代码号
|
* 获取国家代码号
|
||||||
*/
|
*/
|
||||||
@@ -1362,6 +1377,7 @@ interface INetworkService {
|
|||||||
@POST("map/setupRefreshLocation")
|
@POST("map/setupRefreshLocation")
|
||||||
suspend fun setupRefreshLocation(@Field("deviceId") deviceId: String): BaseResponse<String>
|
suspend fun setupRefreshLocation(@Field("deviceId") deviceId: String): BaseResponse<String>
|
||||||
|
|
||||||
|
|
||||||
/*******************************************以下是国内版本接口***********************************/
|
/*******************************************以下是国内版本接口***********************************/
|
||||||
/**
|
/**
|
||||||
* 获取微信登录的OpedId
|
* 获取微信登录的OpedId
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import com.abbidot.tracker.bean.SetMealBean
|
|||||||
import com.abbidot.tracker.bean.SubscriptionsOrderBean
|
import com.abbidot.tracker.bean.SubscriptionsOrderBean
|
||||||
import com.abbidot.tracker.constant.ConstantInt
|
import com.abbidot.tracker.constant.ConstantInt
|
||||||
import okhttp3.MultipartBody
|
import okhttp3.MultipartBody
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -803,6 +804,12 @@ object NetworkApi : BaseNetworkApi<INetworkService>(INetworkService.BASE_URL) {
|
|||||||
service.getRechargeHistory(deviceId)
|
service.getRechargeHistory(deviceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 蓝牙透传机制从TCP迁移到https
|
||||||
|
*/
|
||||||
|
suspend fun blePassThrough(url: String, body: RequestBody) =
|
||||||
|
service.blePassThrough(url, body)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消自动续费/自动订阅
|
* 取消自动续费/自动订阅
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
|
|||||||
// 当网络可用时调用
|
// 当网络可用时调用
|
||||||
super.onAvailable(network)
|
super.onAvailable(network)
|
||||||
LogUtil.e("当网络可用时,onAvailable")
|
LogUtil.e("当网络可用时,onAvailable")
|
||||||
if (mNetworkRequestsFailRetryCount == mNetworkRequestsFailMaxCount && mPetList.size == 0) {
|
if (mNetworkRequestsFailRetryCount == mNetworkRequestsFailMaxCount && mPetList.isEmpty()) {
|
||||||
mNetworkRequestsFailRetryCount = 0
|
mNetworkRequestsFailRetryCount = 0
|
||||||
isFirst = false
|
isFirst = false
|
||||||
mDataViewModel.getHomeBindPetList(this@HomeV2Activity)
|
mDataViewModel.getHomeBindPetList(this@HomeV2Activity)
|
||||||
@@ -239,7 +239,9 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun liveDataObserve() {/*
|
override fun liveDataObserve() {
|
||||||
|
|
||||||
|
/*
|
||||||
Dispatchers.IO 在Android中主要用于执行输入输出操作,如文件读写和网络请求
|
Dispatchers.IO 在Android中主要用于执行输入输出操作,如文件读写和网络请求
|
||||||
Dispatchers.Main:适用于处理与UI相关的操作,如更新UI界面、响应用户输入等。
|
Dispatchers.Main:适用于处理与UI相关的操作,如更新UI界面、响应用户输入等。
|
||||||
Dispatchers.Default:适用于执行CPU密集型任务,如算法计算、数据处理等
|
Dispatchers.Default:适用于执行CPU密集型任务,如算法计算、数据处理等
|
||||||
@@ -358,6 +360,21 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//蓝牙透传
|
||||||
|
XEventBus.observe(this, EventName.BlePassThrough) { receiveData: ReceiveDeviceData ->
|
||||||
|
getPet(false)?.apply {
|
||||||
|
receiveData.data?.let { d ->
|
||||||
|
val sendData = d.sliceArray(8..d.size - 2)
|
||||||
|
if (macID == receiveData.mac) {
|
||||||
|
mDataViewModel.blePassThrough(this, sendData)
|
||||||
|
} else {
|
||||||
|
getMacPet(receiveData.mac)?.let { p ->
|
||||||
|
mDataViewModel.blePassThrough(p, sendData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//蓝牙上报的设备日志
|
//蓝牙上报的设备日志
|
||||||
mLogBleReportViewModel.apply {
|
mLogBleReportViewModel.apply {
|
||||||
@@ -392,7 +409,7 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
|
|||||||
override fun onResult(any: Any) {
|
override fun onResult(any: Any) {
|
||||||
LogUtil.e("HomeV2Activity------>>获取所有绑定宠物数据")
|
LogUtil.e("HomeV2Activity------>>获取所有绑定宠物数据")
|
||||||
isRequestPetData = true
|
isRequestPetData = true
|
||||||
if (mPetList.size > 0) {
|
if (mPetList.isNotEmpty()) {
|
||||||
it.getOrNull()?.apply {
|
it.getOrNull()?.apply {
|
||||||
for (oPet in mPetList) {
|
for (oPet in mPetList) {
|
||||||
for (nPet in this) {
|
for (nPet in this) {
|
||||||
@@ -597,7 +614,7 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
|
|||||||
*/
|
*/
|
||||||
fun selectPetDialog(checkPackageExpire: Boolean = true) {
|
fun selectPetDialog(checkPackageExpire: Boolean = true) {
|
||||||
isCheckPackageExpire = checkPackageExpire
|
isCheckPackageExpire = checkPackageExpire
|
||||||
if (mPetList.size == 0) {
|
if (mPetList.isEmpty()) {
|
||||||
showToast(R.string.no_bind_pet)
|
showToast(R.string.no_bind_pet)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -608,13 +625,29 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getPet(showNoPetTip: Boolean = true): PetBean? {
|
fun getPet(showNoPetTip: Boolean = true): PetBean? {
|
||||||
return if (mPetList.size > 0) mPetList[mSelectPetPosition]
|
return if (mPetList.isNotEmpty()) mPetList[mSelectPetPosition]
|
||||||
else {
|
else {
|
||||||
if (isRequestPetData && showNoPetTip) showToast(R.string.no_bind_pet)
|
if (isRequestPetData && showNoPetTip) showToast(R.string.no_bind_pet)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定mac宠物
|
||||||
|
*/
|
||||||
|
fun getMacPet(mac: String): PetBean? {
|
||||||
|
return if (mPetList.isNotEmpty()) {
|
||||||
|
for (p in mPetList) {
|
||||||
|
if (p.macID == mac) {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跳转debug调试页面
|
* 跳转debug调试页面
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import com.abbidot.tracker.constant.ConstantString
|
|||||||
import com.abbidot.tracker.constant.GetResultCallback
|
import com.abbidot.tracker.constant.GetResultCallback
|
||||||
import com.abbidot.tracker.databinding.ActivityAddPairedSuccessBinding
|
import com.abbidot.tracker.databinding.ActivityAddPairedSuccessBinding
|
||||||
import com.abbidot.tracker.deprecated.ui.activity.vm.AddTrackerDeviceViewModel
|
import com.abbidot.tracker.deprecated.ui.activity.vm.AddTrackerDeviceViewModel
|
||||||
import com.abbidot.tracker.ui.activity.device.wifi.AddWifiPowerZone1Activity
|
|
||||||
import com.abbidot.tracker.ui.activity.subscribe.SubscriptionPlanActivity
|
import com.abbidot.tracker.ui.activity.subscribe.SubscriptionPlanActivity
|
||||||
import com.abbidot.tracker.util.Util
|
import com.abbidot.tracker.util.Util
|
||||||
import com.abbidot.tracker.util.ViewUtil
|
import com.abbidot.tracker.util.ViewUtil
|
||||||
@@ -238,9 +237,10 @@ class AddPairedSuccessActivity :
|
|||||||
if (isFirstBind) {
|
if (isFirstBind) {
|
||||||
mPetBean?.apply {
|
mPetBean?.apply {
|
||||||
val intent =
|
val intent =
|
||||||
Intent(mContext, AddWifiPowerZone1Activity::class.java)
|
Intent(mContext, InitializingDeviceActivity::class.java)
|
||||||
intent.putExtra(ConstantString.Pet, this)
|
intent.putExtra(ConstantString.Pet, this)
|
||||||
intent.putExtra(ConstantString.isFirstBind, isFirstBind)
|
intent.putExtra(ConstantString.isFirstBind, isFirstBind)
|
||||||
|
intent.putExtra(ConstantString.Type, mType)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.abbidot.tracker.ui.activity.device
|
package com.abbidot.tracker.ui.activity.device
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import androidx.activity.viewModels
|
||||||
import com.abbidot.tracker.R
|
import com.abbidot.tracker.R
|
||||||
import com.abbidot.tracker.base.BaseActivity
|
import com.abbidot.tracker.base.BaseActivity
|
||||||
import com.abbidot.tracker.bean.PetBean
|
import com.abbidot.tracker.bean.PetBean
|
||||||
@@ -9,10 +10,12 @@ import com.abbidot.tracker.constant.ConstantString
|
|||||||
import com.abbidot.tracker.databinding.ActivityInitializingDeviceBinding
|
import com.abbidot.tracker.databinding.ActivityInitializingDeviceBinding
|
||||||
import com.abbidot.tracker.ui.activity.device.wifi.AddWifiPowerZone1Activity
|
import com.abbidot.tracker.ui.activity.device.wifi.AddWifiPowerZone1Activity
|
||||||
import com.abbidot.tracker.util.Util
|
import com.abbidot.tracker.util.Util
|
||||||
|
import com.abbidot.tracker.vm.CountDownTimerViewModel
|
||||||
|
|
||||||
class InitializingDeviceActivity :
|
class InitializingDeviceActivity :
|
||||||
BaseActivity<ActivityInitializingDeviceBinding>(ActivityInitializingDeviceBinding::inflate) {
|
BaseActivity<ActivityInitializingDeviceBinding>(ActivityInitializingDeviceBinding::inflate) {
|
||||||
|
|
||||||
|
private val mCountDownTimerViewModel: CountDownTimerViewModel by viewModels()
|
||||||
private var mPetBean: PetBean? = null
|
private var mPetBean: PetBean? = null
|
||||||
private var isFirstBind = false
|
private var isFirstBind = false
|
||||||
private var mDeviceType = ConstantInt.Type1
|
private var mDeviceType = ConstantInt.Type1
|
||||||
@@ -43,6 +46,22 @@ class InitializingDeviceActivity :
|
|||||||
startActivityFinish(intent)
|
startActivityFinish(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mCountDownTimerViewModel.startCountDown(6)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun liveDataObserve() {
|
||||||
|
mCountDownTimerViewModel.apply {
|
||||||
|
mCountDowningLiveData.observe(this@InitializingDeviceActivity) {
|
||||||
|
val string = getString(R.string.txt_continue) + " (${it}s)"
|
||||||
|
mViewBinding.btnPaySuccessInitDeviceNext.text = string
|
||||||
|
}
|
||||||
|
mCountDownEndLiveData.observe(this@InitializingDeviceActivity) {
|
||||||
|
mViewBinding.btnPaySuccessInitDeviceNext.let { v ->
|
||||||
|
v.setText(R.string.txt_continue)
|
||||||
|
setButtonEnabled(v, ConstantInt.Type1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun leftBackOnClick() {
|
override fun leftBackOnClick() {
|
||||||
|
|||||||
@@ -469,10 +469,10 @@ class SureSubscriptionPlanActivity :
|
|||||||
planTimeMonthsCount = cPlan.planTimeMonthsCount
|
planTimeMonthsCount = cPlan.planTimeMonthsCount
|
||||||
mealUnit = cPlan.mealUnit
|
mealUnit = cPlan.mealUnit
|
||||||
planCategory = cPlan.planCategory
|
planCategory = cPlan.planCategory
|
||||||
autoRenewPrice =
|
// autoRenewPrice =
|
||||||
Utils.formatDecimal(cPlan.autoRenewPrice + cPlan.autoRenewPrice * mTaxRate, 2)
|
// Utils.formatDecimal(cPlan.autoRenewPrice + cPlan.autoRenewPrice * mTaxRate, 2)
|
||||||
.toDouble()
|
// .toDouble()
|
||||||
// autoRenewPrice = cPlan.autoRenewPrice
|
autoRenewPrice = cPlan.autoRenewPrice
|
||||||
mealDesc =
|
mealDesc =
|
||||||
mViewBinding.ilSubscribePlanDetail.tvSureSubscribePlanMoney.text.toString() + mViewBinding.ilSubscribePlanDetail.tvSureSubscribePlanPer.text.toString()
|
mViewBinding.ilSubscribePlanDetail.tvSureSubscribePlanMoney.text.toString() + mViewBinding.ilSubscribePlanDetail.tvSureSubscribePlanPer.text.toString()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ class ActivityV2Fragment :
|
|||||||
*/
|
*/
|
||||||
fun showPetNameAndHead(position: Int) {
|
fun showPetNameAndHead(position: Int) {
|
||||||
getHomeV2Activity()?.let {
|
getHomeV2Activity()?.let {
|
||||||
if (it.mPetList.size == 0) {
|
if (it.mPetList.isEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mCurrentShowPetPos = position
|
mCurrentShowPetPos = position
|
||||||
|
|||||||
@@ -38,6 +38,11 @@ import com.abbidot.tracker.widget.NoClickSlideSeekBar
|
|||||||
import com.abbidot.tracker.widget.TypefaceTextView
|
import com.abbidot.tracker.widget.TypefaceTextView
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.atan2
|
||||||
|
import kotlin.math.cos
|
||||||
|
import kotlin.math.pow
|
||||||
|
import kotlin.math.sin
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -482,7 +487,7 @@ class RouteV3Fragment : BaseFragment<FragmentRouteV3Binding>(FragmentRouteV3Bind
|
|||||||
*/
|
*/
|
||||||
fun showPetNameAndHead(position: Int) {
|
fun showPetNameAndHead(position: Int) {
|
||||||
getHomeV2Activity()?.apply {
|
getHomeV2Activity()?.apply {
|
||||||
if (mPetList.size == 0) {
|
if (mPetList.isEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mCurrentShowPetPos = position
|
mCurrentShowPetPos = position
|
||||||
@@ -503,7 +508,19 @@ class RouteV3Fragment : BaseFragment<FragmentRouteV3Binding>(FragmentRouteV3Bind
|
|||||||
|
|
||||||
private fun setLatLngData(data: MutableList<HistoryDataBean>) {
|
private fun setLatLngData(data: MutableList<HistoryDataBean>) {
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
mHistoryDataList = data
|
|
||||||
|
/*慢速步行:epsilon=0.5,插值 2 个
|
||||||
|
日常骑行:epsilon=1.0,插值 2 个
|
||||||
|
机动车行驶:epsilon=1.5~2.0,插值 3 个
|
||||||
|
**/
|
||||||
|
// 1. 降噪
|
||||||
|
val filterPoints = filterNoisePoint(data)
|
||||||
|
// 2. RDP平滑抽稀
|
||||||
|
val smoothPoints = rdpSmooth(filterPoints, epsilon = 0.5)
|
||||||
|
// 3. 插值加密线条
|
||||||
|
val finalPoints = latLngInterpolate(smoothPoints, step = 2)
|
||||||
|
|
||||||
|
mHistoryDataList = finalPoints.toMutableList()
|
||||||
getHomeV2Activity()?.getPet(false)?.let {
|
getHomeV2Activity()?.getPet(false)?.let {
|
||||||
mHistoryDataMapCommon.setPetBean(it)
|
mHistoryDataMapCommon.setPetBean(it)
|
||||||
}
|
}
|
||||||
@@ -517,17 +534,17 @@ class RouteV3Fragment : BaseFragment<FragmentRouteV3Binding>(FragmentRouteV3Bind
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data.size == 0) {
|
if (finalPoints.isEmpty()) {
|
||||||
setSeekBarShowHide(false)
|
setSeekBarShowHide(false)
|
||||||
mHistoryDataMapCommon.setPetUserLatLng()
|
mHistoryDataMapCommon.setPetUserLatLng()
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
setSeekBarShowHide(true)
|
setSeekBarShowHide(true)
|
||||||
val max = data.size - 1
|
val max = finalPoints.size - 1
|
||||||
setSeekBarMax(max)
|
setSeekBarMax(max)
|
||||||
|
|
||||||
mHistoryDataMapCommon.setLatLngData(data)
|
mHistoryDataMapCommon.setLatLngData(finalPoints.toMutableList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,4 +716,134 @@ class RouteV3Fragment : BaseFragment<FragmentRouteV3Binding>(FragmentRouteV3Bind
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 两点间距离 单位米
|
||||||
|
*/
|
||||||
|
private fun distanceBetween(p1: HistoryDataBean, p2: HistoryDataBean): Double {
|
||||||
|
val r = 6371000.0
|
||||||
|
val lat1 = p1.latitude * Math.PI / 180
|
||||||
|
val lng1 = p1.longitude * Math.PI / 180
|
||||||
|
val lat2 = p2.latitude * Math.PI / 180
|
||||||
|
val lng2 = p2.longitude * Math.PI / 180
|
||||||
|
|
||||||
|
val dLat = lat2 - lat1
|
||||||
|
val dLng = lng2 - lng1
|
||||||
|
val a = sin(dLat / 2).pow(2) + cos(lat1) * cos(lat2) * sin(dLng / 2).pow(2)
|
||||||
|
val c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
||||||
|
return r * c
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ramer-Douglas-Peucker 轨迹抽稀平滑
|
||||||
|
* @param epsilon 阈值 建议0.5~2.0
|
||||||
|
*/
|
||||||
|
private fun rdpSmooth(
|
||||||
|
points: List<HistoryDataBean>, epsilon: Double = 1.0
|
||||||
|
): List<HistoryDataBean> {
|
||||||
|
if (points.size < 3) return points
|
||||||
|
var maxDist = 0.0
|
||||||
|
var index = 0
|
||||||
|
val start = points.first()
|
||||||
|
val end = points.last()
|
||||||
|
|
||||||
|
for (i in 1 until points.lastIndex) {
|
||||||
|
val dist = pointToLineDist(p = points[i], a = start, b = end)
|
||||||
|
if (dist > maxDist) {
|
||||||
|
maxDist = dist
|
||||||
|
index = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (maxDist > epsilon) {
|
||||||
|
val left = rdpSmooth(points.subList(0, index + 1), epsilon)
|
||||||
|
val right = rdpSmooth(points.subList(index, points.size), epsilon)
|
||||||
|
left.dropLast(1) + right
|
||||||
|
} else {
|
||||||
|
listOf(start, end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点到线段距离
|
||||||
|
*/
|
||||||
|
private fun pointToLineDist(
|
||||||
|
p: HistoryDataBean,
|
||||||
|
a: HistoryDataBean,
|
||||||
|
b: HistoryDataBean
|
||||||
|
): Double {
|
||||||
|
val ax = a.longitude
|
||||||
|
val ay = a.latitude
|
||||||
|
val bx = b.longitude
|
||||||
|
val by = b.latitude
|
||||||
|
val px = p.longitude
|
||||||
|
val py = p.latitude
|
||||||
|
|
||||||
|
val cross = (px - ax) * (bx - ax) + (py - ay) * (by - ay)
|
||||||
|
if (cross <= 0.0) return distanceBetween(p1 = p, p2 = a)
|
||||||
|
|
||||||
|
val len2 = (bx - ax).pow(2) + (by - ay).pow(2)
|
||||||
|
if (cross >= len2) return distanceBetween(p1 = p, p2 = b)
|
||||||
|
|
||||||
|
val t = cross / len2
|
||||||
|
val nearX = ax + t * (bx - ax)
|
||||||
|
val nearY = ay + t * (by - ay)
|
||||||
|
return distanceBetween(
|
||||||
|
p1 = p,
|
||||||
|
p2 = HistoryDataBean().apply {
|
||||||
|
latitude = nearY
|
||||||
|
longitude = nearX
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相邻两点插值补点,让线条更顺滑
|
||||||
|
* @param step 插值个数 推荐2~3
|
||||||
|
*/
|
||||||
|
private fun latLngInterpolate(
|
||||||
|
points: List<HistoryDataBean>,
|
||||||
|
step: Int = 2
|
||||||
|
): List<HistoryDataBean> {
|
||||||
|
if (points.size < 2) return points
|
||||||
|
val result = mutableListOf<HistoryDataBean>()
|
||||||
|
for (i in 0 until points.size - 1) {
|
||||||
|
val p0 = points[i]
|
||||||
|
val p1 = points[i + 1]
|
||||||
|
result.add(p0)
|
||||||
|
for (s in 1..step) {
|
||||||
|
val ratio = s.toDouble() / (step + 1)
|
||||||
|
val lat = p0.latitude + (p1.latitude - p0.latitude) * ratio
|
||||||
|
val lng = p0.longitude + (p1.longitude - p0.longitude) * ratio
|
||||||
|
result.add(HistoryDataBean().apply {
|
||||||
|
latitude = lat
|
||||||
|
longitude = lng
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.add(points.last())
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GPS降噪,过滤跳点漂移
|
||||||
|
*/
|
||||||
|
private fun filterNoisePoint(
|
||||||
|
data: List<HistoryDataBean>,
|
||||||
|
minDis: Double = 5.0,
|
||||||
|
maxDis: Double = 60.0
|
||||||
|
): List<HistoryDataBean> {
|
||||||
|
if (data.isEmpty()) return emptyList()
|
||||||
|
val res = mutableListOf<HistoryDataBean>().apply { add(data.first()) }
|
||||||
|
for (i in 1 until data.size) {
|
||||||
|
val last = res.last()
|
||||||
|
val d = data[i]
|
||||||
|
val dis = distanceBetween(p1 = last, p2 = d)
|
||||||
|
if (dis in minDis..maxDis) {
|
||||||
|
res.add(d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -63,12 +63,6 @@ import com.google.android.gms.tasks.CancellationTokenSource
|
|||||||
import com.google.android.gms.tasks.Task
|
import com.google.android.gms.tasks.Task
|
||||||
import com.qmuiteam.qmui.util.QMUIDisplayHelper
|
import com.qmuiteam.qmui.util.QMUIDisplayHelper
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.math.PI
|
|
||||||
import kotlin.math.atan2
|
|
||||||
import kotlin.math.cos
|
|
||||||
import kotlin.math.pow
|
|
||||||
import kotlin.math.sin
|
|
||||||
import kotlin.math.sqrt
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -838,21 +832,10 @@ abstract class BaseGoogleMapFragment :
|
|||||||
latLngList
|
latLngList
|
||||||
}
|
}
|
||||||
|
|
||||||
/*慢速步行:epsilon=0.5,插值 2 个
|
|
||||||
日常骑行:epsilon=1.0,插值 2 个
|
|
||||||
机动车行驶:epsilon=1.5~2.0,插值 3 个
|
|
||||||
**/
|
|
||||||
// 1. 降噪
|
|
||||||
val filterPoints = filterNoisePoint(newLatLngList)
|
|
||||||
// 2. RDP平滑抽稀
|
|
||||||
val smoothPoints = rdpSmooth(filterPoints, epsilon = 0.5)
|
|
||||||
// 3. 插值加密线条
|
|
||||||
val finalPoints = latLngInterpolate(smoothPoints, step = 2)
|
|
||||||
|
|
||||||
//先黄黑线
|
//先黄黑线
|
||||||
getPolylineOptions(8f, R.color.line_stroke_color).let {
|
getPolylineOptions(8f, R.color.line_stroke_color).let {
|
||||||
it.geodesic(true)
|
it.geodesic(true)
|
||||||
it.addAll(finalPoints)
|
it.addAll(newLatLngList)
|
||||||
googleMap.addPolyline(it).apply {
|
googleMap.addPolyline(it).apply {
|
||||||
startCap = RoundCap()
|
startCap = RoundCap()
|
||||||
endCap = RoundCap()
|
endCap = RoundCap()
|
||||||
@@ -868,7 +851,7 @@ abstract class BaseGoogleMapFragment :
|
|||||||
//再画黄线
|
//再画黄线
|
||||||
getPolylineOptions(5f, R.color.rote_line_color).let {
|
getPolylineOptions(5f, R.color.rote_line_color).let {
|
||||||
it.geodesic(true)
|
it.geodesic(true)
|
||||||
it.addAll(finalPoints)
|
it.addAll(newLatLngList)
|
||||||
googleMap.addPolyline(it).apply {
|
googleMap.addPolyline(it).apply {
|
||||||
startCap = RoundCap()
|
startCap = RoundCap()
|
||||||
endCap = RoundCap()
|
endCap = RoundCap()
|
||||||
@@ -1300,112 +1283,112 @@ abstract class BaseGoogleMapFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* 两点间距离 单位米
|
// * 两点间距离 单位米
|
||||||
*/
|
// */
|
||||||
private fun distanceBetween(p1: LatLng, p2: LatLng): Double {
|
// private fun distanceBetween(p1: LatLng, p2: LatLng): Double {
|
||||||
val r = 6371000.0
|
// val r = 6371000.0
|
||||||
val lat1 = p1.latitude * PI / 180
|
// val lat1 = p1.latitude * PI / 180
|
||||||
val lng1 = p1.longitude * PI / 180
|
// val lng1 = p1.longitude * PI / 180
|
||||||
val lat2 = p2.latitude * PI / 180
|
// val lat2 = p2.latitude * PI / 180
|
||||||
val lng2 = p2.longitude * PI / 180
|
// val lng2 = p2.longitude * PI / 180
|
||||||
|
//
|
||||||
val dLat = lat2 - lat1
|
// val dLat = lat2 - lat1
|
||||||
val dLng = lng2 - lng1
|
// val dLng = lng2 - lng1
|
||||||
val a = sin(dLat / 2).pow(2) + cos(lat1) * cos(lat2) * sin(dLng / 2).pow(2)
|
// val a = sin(dLat / 2).pow(2) + cos(lat1) * cos(lat2) * sin(dLng / 2).pow(2)
|
||||||
val c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
// val c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
||||||
return r * c
|
// return r * c
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* Ramer-Douglas-Peucker 轨迹抽稀平滑
|
// * Ramer-Douglas-Peucker 轨迹抽稀平滑
|
||||||
* @param epsilon 阈值 建议0.5~2.0
|
// * @param epsilon 阈值 建议0.5~2.0
|
||||||
*/
|
// */
|
||||||
private fun rdpSmooth(points: List<LatLng>, epsilon: Double = 1.0): List<LatLng> {
|
// private fun rdpSmooth(points: List<LatLng>, epsilon: Double = 1.0): List<LatLng> {
|
||||||
if (points.size < 3) return points
|
// if (points.size < 3) return points
|
||||||
var maxDist = 0.0
|
// var maxDist = 0.0
|
||||||
var index = 0
|
// var index = 0
|
||||||
val start = points.first()
|
// val start = points.first()
|
||||||
val end = points.last()
|
// val end = points.last()
|
||||||
|
//
|
||||||
for (i in 1 until points.lastIndex) {
|
// for (i in 1 until points.lastIndex) {
|
||||||
val dist = pointToLineDist(points[i], start, end)
|
// val dist = pointToLineDist(points[i], start, end)
|
||||||
if (dist > maxDist) {
|
// if (dist > maxDist) {
|
||||||
maxDist = dist
|
// maxDist = dist
|
||||||
index = i
|
// index = i
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return if (maxDist > epsilon) {
|
// return if (maxDist > epsilon) {
|
||||||
val left = rdpSmooth(points.subList(0, index + 1), epsilon)
|
// val left = rdpSmooth(points.subList(0, index + 1), epsilon)
|
||||||
val right = rdpSmooth(points.subList(index, points.size), epsilon)
|
// val right = rdpSmooth(points.subList(index, points.size), epsilon)
|
||||||
left.dropLast(1) + right
|
// left.dropLast(1) + right
|
||||||
} else {
|
// } else {
|
||||||
listOf(start, end)
|
// listOf(start, end)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 点到线段距离
|
// * 点到线段距离
|
||||||
*/
|
// */
|
||||||
private fun pointToLineDist(p: LatLng, a: LatLng, b: LatLng): Double {
|
// private fun pointToLineDist(p: LatLng, a: LatLng, b: LatLng): Double {
|
||||||
val ax = a.longitude
|
// val ax = a.longitude
|
||||||
val ay = a.latitude
|
// val ay = a.latitude
|
||||||
val bx = b.longitude
|
// val bx = b.longitude
|
||||||
val by = b.latitude
|
// val by = b.latitude
|
||||||
val px = p.longitude
|
// val px = p.longitude
|
||||||
val py = p.latitude
|
// val py = p.latitude
|
||||||
|
//
|
||||||
val cross = (px - ax) * (bx - ax) + (py - ay) * (by - ay)
|
// val cross = (px - ax) * (bx - ax) + (py - ay) * (by - ay)
|
||||||
if (cross <= 0.0) return distanceBetween(p, a)
|
// if (cross <= 0.0) return distanceBetween(p, a)
|
||||||
|
//
|
||||||
val len2 = (bx - ax).pow(2) + (by - ay).pow(2)
|
// val len2 = (bx - ax).pow(2) + (by - ay).pow(2)
|
||||||
if (cross >= len2) return distanceBetween(p, b)
|
// if (cross >= len2) return distanceBetween(p, b)
|
||||||
|
//
|
||||||
val t = cross / len2
|
// val t = cross / len2
|
||||||
val nearX = ax + t * (bx - ax)
|
// val nearX = ax + t * (bx - ax)
|
||||||
val nearY = ay + t * (by - ay)
|
// val nearY = ay + t * (by - ay)
|
||||||
return distanceBetween(p, LatLng(nearY, nearX))
|
// return distanceBetween(p, LatLng(nearY, nearX))
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 相邻两点插值补点,让线条更顺滑
|
// * 相邻两点插值补点,让线条更顺滑
|
||||||
* @param step 插值个数 推荐2~3
|
// * @param step 插值个数 推荐2~3
|
||||||
*/
|
// */
|
||||||
private fun latLngInterpolate(points: List<LatLng>, step: Int = 2): List<LatLng> {
|
// private fun latLngInterpolate(points: List<LatLng>, step: Int = 2): List<LatLng> {
|
||||||
if (points.size < 2) return points
|
// if (points.size < 2) return points
|
||||||
val result = mutableListOf<LatLng>()
|
// val result = mutableListOf<LatLng>()
|
||||||
for (i in 0 until points.size - 1) {
|
// for (i in 0 until points.size - 1) {
|
||||||
val p0 = points[i]
|
// val p0 = points[i]
|
||||||
val p1 = points[i + 1]
|
// val p1 = points[i + 1]
|
||||||
result.add(p0)
|
// result.add(p0)
|
||||||
for (s in 1..step) {
|
// for (s in 1..step) {
|
||||||
val ratio = s.toDouble() / (step + 1)
|
// val ratio = s.toDouble() / (step + 1)
|
||||||
val lat = p0.latitude + (p1.latitude - p0.latitude) * ratio
|
// val lat = p0.latitude + (p1.latitude - p0.latitude) * ratio
|
||||||
val lng = p0.longitude + (p1.longitude - p0.longitude) * ratio
|
// val lng = p0.longitude + (p1.longitude - p0.longitude) * ratio
|
||||||
result.add(LatLng(lat, lng))
|
// result.add(LatLng(lat, lng))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
result.add(points.last())
|
// result.add(points.last())
|
||||||
return result
|
// return result
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* GPS降噪,过滤跳点漂移
|
// * GPS降噪,过滤跳点漂移
|
||||||
*/
|
// */
|
||||||
private fun filterNoisePoint(
|
// private fun filterNoisePoint(
|
||||||
points: List<LatLng>, minDis: Double = 5.0, maxDis: Double = 60.0
|
// points: List<LatLng>, minDis: Double = 5.0, maxDis: Double = 60.0
|
||||||
): List<LatLng> {
|
// ): List<LatLng> {
|
||||||
if (points.isEmpty()) return emptyList()
|
// if (points.isEmpty()) return emptyList()
|
||||||
val res = mutableListOf<LatLng>().apply { add(points.first()) }
|
// val res = mutableListOf<LatLng>().apply { add(points.first()) }
|
||||||
for (i in 1 until points.size) {
|
// for (i in 1 until points.size) {
|
||||||
val last = res.last()
|
// val last = res.last()
|
||||||
val dis = distanceBetween(last, points[i])
|
// val dis = distanceBetween(last, points[i])
|
||||||
if (dis in minDis..maxDis) {
|
// if (dis in minDis..maxDis) {
|
||||||
res.add(points[i])
|
// res.add(points[i])
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return res
|
// return res
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -119,12 +119,13 @@ class PetV2Fragment : BaseFragment<FragmentPetV2Binding>(FragmentPetV2Binding::i
|
|||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
mNotificationsViewModel.getMessageUnReadCount()
|
mNotificationsViewModel.getMessageUnReadCount()
|
||||||
(mFragments[1] as HomeTrackFragment).onResume()
|
// (mFragments[1] as HomeTrackFragment).onResume()
|
||||||
getHomeV2Activity()?.apply {
|
getHomeV2Activity()?.apply {
|
||||||
//其他页面是否选择了宠物
|
//其他页面是否选择了宠物
|
||||||
if (mCurrentShowPetPos != mSelectPetPosition) {
|
if (mCurrentShowPetPos != mSelectPetPosition) {
|
||||||
showPetNameAndHead(mSelectPetPosition)
|
showPetNameAndHead(mSelectPetPosition)
|
||||||
} else {
|
} else {
|
||||||
|
(mFragments[0] as HomePetFragment).getPetAllInfoData()
|
||||||
(mFragments[1] as HomeTrackFragment).getPetTrackerInfoData()
|
(mFragments[1] as HomeTrackFragment).getPetTrackerInfoData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -375,6 +375,9 @@ class SRBleCmdUtil private constructor() {
|
|||||||
return getCrc8Cmd(byteArray)
|
return getCrc8Cmd(byteArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 蓝牙透传上报设备信息
|
||||||
|
*/
|
||||||
fun setProxy(result: Int, data: ByteArray?): ByteArray {
|
fun setProxy(result: Int, data: ByteArray?): ByteArray {
|
||||||
if (null == data) {
|
if (null == data) {
|
||||||
return getCrc8Cmd(byteArrayOf(0x24, result.toByte(), 0))
|
return getCrc8Cmd(byteArrayOf(0x24, result.toByte(), 0))
|
||||||
|
|||||||
@@ -242,10 +242,8 @@ class SRBleUtil private constructor() {
|
|||||||
XEventBus.post(EventName.BleGetLocation, bleDevice.mac)
|
XEventBus.post(EventName.BleGetLocation, bleDevice.mac)
|
||||||
} else if (data0 == 0x24) {
|
} else if (data0 == 0x24) {
|
||||||
LogUtil.e("${bleDevice.mac},蓝牙透传消息")
|
LogUtil.e("${bleDevice.mac},蓝牙透传消息")
|
||||||
if (null == mSocketUtilManage) mSocketUtilManage = SocketUtilManageV2()
|
val deviceData = ReceiveDeviceData(bleDevice, data, bleDevice.mac)
|
||||||
mContext?.let {
|
XEventBus.post(EventName.BlePassThrough, deviceData)
|
||||||
mSocketUtilManage?.initEasySocket(it, bleDevice.mac, data)
|
|
||||||
}
|
|
||||||
} else if (data0 == 0x09 && data1 == 0x00) {
|
} else if (data0 == 0x09 && data1 == 0x00) {
|
||||||
val deviceData = ReceiveDeviceData(bleDevice, data, bleDevice.mac)
|
val deviceData = ReceiveDeviceData(bleDevice, data, bleDevice.mac)
|
||||||
if (isNotifyFirmware) {
|
if (isNotifyFirmware) {
|
||||||
|
|||||||
@@ -4,12 +4,22 @@ import androidx.lifecycle.MutableLiveData
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.abbidot.baselibrary.constant.MMKVKey
|
import com.abbidot.baselibrary.constant.MMKVKey
|
||||||
|
import com.abbidot.baselibrary.util.LogUtil
|
||||||
import com.abbidot.baselibrary.util.MMKVUtil
|
import com.abbidot.baselibrary.util.MMKVUtil
|
||||||
import com.abbidot.tracker.base.BaseActivity
|
import com.abbidot.tracker.base.BaseActivity
|
||||||
import com.abbidot.tracker.bean.HomeDataBean
|
import com.abbidot.tracker.bean.HomeDataBean
|
||||||
import com.abbidot.tracker.bean.PetBean
|
import com.abbidot.tracker.bean.PetBean
|
||||||
|
import com.abbidot.tracker.retrofit2.INetworkService
|
||||||
import com.abbidot.tracker.retrofit2.NetworkApi
|
import com.abbidot.tracker.retrofit2.NetworkApi
|
||||||
|
import com.abbidot.tracker.util.bluetooth.SRBleCmdUtil
|
||||||
|
import com.abbidot.tracker.util.bluetooth.SRBleUtil
|
||||||
|
import com.mapbox.core.utils.TextUtils
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*Created by .yzq on 2022/3/11/011.
|
*Created by .yzq on 2022/3/11/011.
|
||||||
@@ -18,6 +28,8 @@ import kotlinx.coroutines.launch
|
|||||||
*/
|
*/
|
||||||
class DataViewModel : ViewModel() {
|
class DataViewModel : ViewModel() {
|
||||||
|
|
||||||
|
private val mMutex = Mutex()
|
||||||
|
|
||||||
val mHomePetLiveData = MutableLiveData<Result<MutableList<PetBean>>>()
|
val mHomePetLiveData = MutableLiveData<Result<MutableList<PetBean>>>()
|
||||||
val mHomeDataLiveData = MutableLiveData<Result<HomeDataBean>>()
|
val mHomeDataLiveData = MutableLiveData<Result<HomeDataBean>>()
|
||||||
|
|
||||||
@@ -50,4 +62,44 @@ class DataViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun blePassThrough(petBean: PetBean, binaryData: ByteArray) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
mMutex.withLock {
|
||||||
|
try {
|
||||||
|
var baseUrl =
|
||||||
|
if (TextUtils.isEmpty(petBean.serverDomain)) INetworkService.BASE_URL_BLE
|
||||||
|
else petBean.serverDomain
|
||||||
|
if (!baseUrl.startsWith("https")) baseUrl = "https://$baseUrl"
|
||||||
|
if (!baseUrl.endsWith("/")) baseUrl = "$baseUrl/"
|
||||||
|
val requestBody =
|
||||||
|
binaryData.toRequestBody("application/octet-stream".toMediaType())
|
||||||
|
val response =
|
||||||
|
NetworkApi.blePassThrough("${baseUrl}BlePassThrough", requestBody)
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
// 读取响应二进制
|
||||||
|
val b = response.body()
|
||||||
|
if (null == b) {
|
||||||
|
SRBleUtil.instance.isConnectBleSendCmdData(
|
||||||
|
petBean.macID, SRBleCmdUtil.instance.setProxy(1, null)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val result = b.bytes()
|
||||||
|
SRBleUtil.instance.isConnectBleSendCmdData(
|
||||||
|
petBean.macID, SRBleCmdUtil.instance.setProxy(0, result)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SRBleUtil.instance.isConnectBleSendCmdData(
|
||||||
|
petBean.macID, SRBleCmdUtil.instance.setProxy(1, null)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
SRBleUtil.instance.isConnectBleSendCmdData(
|
||||||
|
petBean.macID, SRBleCmdUtil.instance.setProxy(1, null)
|
||||||
|
)
|
||||||
|
LogUtil.e("蓝牙透传解析异常:${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -55,6 +55,7 @@
|
|||||||
<com.abbidot.tracker.widget.TypefaceButton
|
<com.abbidot.tracker.widget.TypefaceButton
|
||||||
android:id="@+id/btn_pay_success_init_device_next"
|
android:id="@+id/btn_pay_success_init_device_next"
|
||||||
style="@style/my_match_RoundRect_Button_style"
|
style="@style/my_match_RoundRect_Button_style"
|
||||||
|
android:enabled="false"
|
||||||
android:text="@string/txt_continue"
|
android:text="@string/txt_continue"
|
||||||
app:qmui_radius="@dimen/dp_64"
|
app:qmui_radius="@dimen/dp_64"
|
||||||
app:typeface="@string/roboto_bold_font" />
|
app:typeface="@string/roboto_bold_font" />
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import androidx.annotation.StringDef
|
|||||||
EventName.BleGetLocation,
|
EventName.BleGetLocation,
|
||||||
EventName.BleReportData,
|
EventName.BleReportData,
|
||||||
EventName.LogReport,
|
EventName.LogReport,
|
||||||
|
EventName.BlePassThrough,
|
||||||
EventName.ActionConDeviceState
|
EventName.ActionConDeviceState
|
||||||
)
|
)
|
||||||
@Retention(AnnotationRetention.SOURCE)
|
@Retention(AnnotationRetention.SOURCE)
|
||||||
@@ -112,5 +113,7 @@ annotation class EventName {
|
|||||||
|
|
||||||
//设备固件版本
|
//设备固件版本
|
||||||
const val BleFirmwareVersion = "firmwareVersion"
|
const val BleFirmwareVersion = "firmwareVersion"
|
||||||
|
//蓝牙透传
|
||||||
|
const val BlePassThrough = "blePassThrough"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ abstract class BaseNetworkApi<I>(private val baseUrl: String) : IService<I> {
|
|||||||
getRetrofit().create(getServiceClass())
|
getRetrofit().create(getServiceClass())
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getRetrofit(): Retrofit {
|
protected fun getRetrofit(): Retrofit {
|
||||||
//添加gson解析null拦截器
|
//添加gson解析null拦截器
|
||||||
val gson = GsonBuilder().registerTypeAdapter(String::class.java, StringNullAdapter())
|
val gson = GsonBuilder().registerTypeAdapter(String::class.java, StringNullAdapter())
|
||||||
.registerTypeAdapter(Double::class.java, DoubleDefault0Adapter()).create()
|
.registerTypeAdapter(Double::class.java, DoubleDefault0Adapter()).create()
|
||||||
@@ -37,6 +37,19 @@ abstract class BaseNetworkApi<I>(private val baseUrl: String) : IService<I> {
|
|||||||
.addConverterFactory(GsonConverterFactory.create(gson)).build()
|
.addConverterFactory(GsonConverterFactory.create(gson)).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 二进制上传专用 独立 Retrofit 配置
|
||||||
|
*/
|
||||||
|
// protected val binaryService: I by lazy {
|
||||||
|
// binaryRetrofit().create(getServiceClass())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 无 Gson 解析,只处理原始流/二进制
|
||||||
|
// private fun binaryRetrofit(): Retrofit {
|
||||||
|
// return Retrofit.Builder().baseUrl(baseUrl).client(getOkHttpClient())
|
||||||
|
// .build()
|
||||||
|
// }
|
||||||
|
|
||||||
private fun getServiceClass(): Class<I> {
|
private fun getServiceClass(): Class<I> {
|
||||||
val genType = javaClass.genericSuperclass as ParameterizedType
|
val genType = javaClass.genericSuperclass as ParameterizedType
|
||||||
return genType.actualTypeArguments[0] as Class<I>
|
return genType.actualTypeArguments[0] as Class<I>
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ class AppUtils {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private var isDebug: Boolean? = true
|
// private var isDebug: Boolean? = true
|
||||||
|
private var isDebug: Boolean? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 屏幕密度,系统源码注释不推荐使用
|
* 屏幕密度,系统源码注释不推荐使用
|
||||||
@@ -93,7 +94,7 @@ class AppUtils {
|
|||||||
* 是否是国内
|
* 是否是国内
|
||||||
*/
|
*/
|
||||||
fun isChina(type: String = SWITCH_PAGE_TYPE): Boolean {
|
fun isChina(type: String = SWITCH_PAGE_TYPE): Boolean {
|
||||||
return true
|
return false
|
||||||
if (isDebug()) {
|
if (isDebug()) {
|
||||||
if (type == SWITCH_MAP_TYPE && MMKVUtil.getBoolean(MMKVKey.OnlyGoogleMap, false)) {
|
if (type == SWITCH_MAP_TYPE && MMKVUtil.getBoolean(MMKVKey.OnlyGoogleMap, false)) {
|
||||||
//只启用谷歌地图
|
//只启用谷歌地图
|
||||||
|
|||||||
Reference in New Issue
Block a user