1.围栏和wifi适配百度地图

2.修复首次绑定流程中添加wifi ,定位点未按国内版纠正bug
3.优化百度和谷歌定位全局只使用一个
4.删除未使用字符串,整理多语言
This commit is contained in:
2026-08-27 17:32:35 +08:00
parent 567088bb87
commit c6f9e191b9
53 changed files with 2523 additions and 2216 deletions

View File

@@ -28,9 +28,9 @@ android {
applicationId "com.abbidot.tracker" applicationId "com.abbidot.tracker"
minSdkVersion 24 minSdkVersion 24
targetSdkVersion 35 targetSdkVersion 35
versionCode 2400 versionCode 2500
versionName "2.4.0" // versionName "2.5.0"
// versionName "2.4.0-Beta1" versionName "2.5.0-Beta1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -87,7 +87,9 @@
android:usesPermissionFlags="neverForLocation" android:usesPermissionFlags="neverForLocation"
tools:targetApi="s" /> tools:targetApi="s" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" /> <!-- 指定微信包名 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<!-- 指定微信包名 -->
<queries> <queries>
<package android:name="com.tencent.mm" /> <package android:name="com.tencent.mm" />
</queries> </queries>
@@ -532,6 +534,14 @@
</intent-filter> </intent-filter>
</activity> </activity>
<service
android:name=".service.BaiduLocationService"
android:exported="false"
android:foregroundServiceType="location" />
<service
android:name=".service.GoogleLocationService"
android:exported="false"
android:foregroundServiceType="location" />
<service <service
android:name=".service.DfuService" android:name=".service.DfuService"
android:exported="false" android:exported="false"

View File

@@ -11,7 +11,10 @@ import coil.decode.GifDecoder
import coil.decode.ImageDecoderDecoder import coil.decode.ImageDecoderDecoder
import com.abbidot.baselibrary.util.AppUtils import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.baselibrary.util.MMKVUtil import com.abbidot.baselibrary.util.MMKVUtil
import com.abbidot.tracker.util.BaiduLocationManager
import com.abbidot.tracker.util.CrashHandler import com.abbidot.tracker.util.CrashHandler
import com.abbidot.tracker.util.GoogleLocationManager
import com.easysocket.utils.LogUtil
import com.hjq.toast.Toaster import com.hjq.toast.Toaster
import com.qmuiteam.qmui.arch.QMUISwipeBackActivityManager import com.qmuiteam.qmui.arch.QMUISwipeBackActivityManager
import dagger.hilt.android.HiltAndroidApp import dagger.hilt.android.HiltAndroidApp
@@ -27,7 +30,6 @@ class MyApplication : Application() {
companion object { companion object {
lateinit var instance: Application lateinit var instance: Application
//保存地图宠物头像对象在内存中,提高显示速度 //保存地图宠物头像对象在内存中,提高显示速度
val mapPetHeadHashMap = hashMapOf<String, Any>() val mapPetHeadHashMap = hashMapOf<String, Any>()
} }
@@ -46,6 +48,8 @@ class MyApplication : Application() {
Toaster.init(this) Toaster.init(this)
Toaster.setView(R.layout.toast_my_layout) Toaster.setView(R.layout.toast_my_layout)
initLocationServer()
// JPushInterface.setDebugMode(true) // JPushInterface.setDebugMode(true)
// JPushInterface.init(this) // JPushInterface.init(this)
@@ -79,10 +83,20 @@ class MyApplication : Application() {
}.build() }.build()
//设置全局唯一实例 //设置全局唯一实例
Coil.setImageLoader(imageLoader) Coil.setImageLoader(imageLoader)
}
CrashHandler().init(this) CrashHandler().init(this)
} }
}
private fun initLocationServer() {
LogUtil.e("初始化定位服务")
//初始化定位服务,需要BaseActivity中startLocation()方法调用启动定位服务
if (AppUtils.isChina()) {
BaiduLocationManager.init(this)
} else {
GoogleLocationManager.init(this)
}
}
/** /**
* 主进程初始化 * 主进程初始化

View File

@@ -1,6 +1,5 @@
package com.abbidot.tracker.base package com.abbidot.tracker.base
import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@@ -36,6 +35,8 @@ import com.abbidot.baselibrary.util.MMKVUtil
import com.abbidot.tracker.R import com.abbidot.tracker.R
import com.abbidot.tracker.constant.ConstantInt import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.constant.GetResultCallback import com.abbidot.tracker.constant.GetResultCallback
import com.abbidot.tracker.util.BaiduLocationManager
import com.abbidot.tracker.util.GoogleLocationManager
import com.abbidot.tracker.util.Util import com.abbidot.tracker.util.Util
import com.abbidot.tracker.util.ViewUtil import com.abbidot.tracker.util.ViewUtil
import com.baidu.platform.comapi.util.NetworkUtil import com.baidu.platform.comapi.util.NetworkUtil
@@ -590,7 +591,7 @@ abstract class BaseActivity<T : ViewBinding>(val inflater: (inflater: LayoutInfl
//服务器返回错误信息 //服务器返回错误信息
val exceptionMessage = it.exceptionOrNull()?.message val exceptionMessage = it.exceptionOrNull()?.message
//服务器返回错误code //服务器返回错误code
val exceptionCode= it.exceptionOrNull()?.toString() val exceptionCode = it.exceptionOrNull()?.toString()
LogUtil.d("Throwable异常", "code=${exceptionCode},${exceptionMessage}") LogUtil.d("Throwable异常", "code=${exceptionCode},${exceptionMessage}")
if (null != exceptionCode) { if (null != exceptionCode) {
//处理验证码登录,用户未注册的情况 //处理验证码登录,用户未注册的情况
@@ -932,5 +933,28 @@ abstract class BaseActivity<T : ViewBinding>(val inflater: (inflater: LayoutInfl
hideSoftKeyboardCallback() hideSoftKeyboardCallback()
} }
} }
/*****************************监听软键盘弹出,输入框上移end************************************/ /*****************************监听软键盘弹出,输入框上移end************************************/
/**
* 释放定位服务
*/
private fun releaseLocationService() {
LogUtil.e("释放定位服务")
if (AppUtils.isChina()) {
BaiduLocationManager.releaseServer(this)
} else {
GoogleLocationManager.releaseServer(this)
}
}
override fun onDestroy() {
super.onDestroy()
//判断是否为“完全退出”场景(例如:用户点击返回键退出应用)
//isFinishing:判断 Activity 是否正在被销毁。
//isTaskRoot:判断当前 Activity 是否为任务栈的根 Activity(避免其他 Activity 销毁时误触发)
if (isFinishing && isTaskRoot) {
releaseLocationService()
}
}
} }

View File

@@ -8,7 +8,6 @@ import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.ui.fragment.map.baidumap.BaseBaiduMapFragment import com.abbidot.tracker.ui.fragment.map.baidumap.BaseBaiduMapFragment
import com.abbidot.tracker.ui.fragment.map.googlemap.BaseGoogleMapFragment import com.abbidot.tracker.ui.fragment.map.googlemap.BaseGoogleMapFragment
import com.abbidot.tracker.util.Util import com.abbidot.tracker.util.Util
import com.baidu.mapapi.utils.DistanceUtil
import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.LatLng
/** /**
@@ -39,7 +38,7 @@ open class BaseMapCommon {
fun startRefreshUserLocation( fun startRefreshUserLocation(
baiduMapFragment: BaseBaiduMapFragment?, googleMapFragment: BaseGoogleMapFragment? baiduMapFragment: BaseBaiduMapFragment?, googleMapFragment: BaseGoogleMapFragment?
) { ) {
googleMapFragment?.getLastLocation() // googleMapFragment?.getLastLocation()
//百度地图定位成功后,每隔60秒刷新用户位置,无需重复调用 //百度地图定位成功后,每隔60秒刷新用户位置,无需重复调用
} }
@@ -134,11 +133,20 @@ open class BaseMapCommon {
context, context,
padding, padding,
LatLng(ancillaryLatitude, ancillaryLongitude), LatLng(ancillaryLatitude, ancillaryLongitude),
LatLng(latitudeCenter, longitudeCenter),
LatLng(ancillaryOtherLatitude, ancillaryOtherLongitude) LatLng(ancillaryOtherLatitude, ancillaryOtherLongitude)
) )
} }
baiduMapFragment?.apply { baiduMapFragment?.apply {
setBaiduMapZoom(getDistanceZoom(radius.toDouble()) + 1) // setBaiduMapZoom(getDistanceZoom(radius.toDouble()) + 1)
setLatLngZoom(
context,
com.baidu.mapapi.model.LatLng(ancillaryLatitude, ancillaryLongitude),
com.baidu.mapapi.model.LatLng(latitudeCenter, longitudeCenter),
com.baidu.mapapi.model.LatLng(
ancillaryOtherLatitude, ancillaryOtherLongitude
)
)
} }
} }
@@ -152,13 +160,20 @@ open class BaseMapCommon {
LatLng(latitudeD, longitudeD) LatLng(latitudeD, longitudeD)
) )
baiduMapFragment?.apply { baiduMapFragment?.apply {
setBaiduMapZoom( setLatLngZoom(
getDistanceZoom( context,
maxOf( com.baidu.mapapi.model.LatLng(latitudeA, longitudeA),
shortDistance, longDistance com.baidu.mapapi.model.LatLng(latitudeB, longitudeB),
).toDouble() com.baidu.mapapi.model.LatLng(latitudeC, longitudeC),
) + 1 com.baidu.mapapi.model.LatLng(latitudeD, longitudeD)
) )
// setBaiduMapZoom(
// getDistanceZoom(
// maxOf(
// shortDistance, longDistance
// ).toDouble()
// ) + 1
// )
} }
} }
@@ -174,20 +189,29 @@ open class BaseMapCommon {
LatLng(latitudeF, longitudeF), LatLng(latitudeF, longitudeF),
) )
baiduMapFragment?.apply { baiduMapFragment?.apply {
val minLat = setLatLngZoom(
minOf(latitudeA, latitudeB, latitudeC, latitudeD, latitudeE, latitudeF) context,
val maxLat = com.baidu.mapapi.model.LatLng(latitudeA, longitudeA),
minOf(latitudeA, latitudeB, latitudeC, latitudeD, latitudeE, latitudeF) com.baidu.mapapi.model.LatLng(latitudeB, longitudeB),
val minLon = minOf( com.baidu.mapapi.model.LatLng(latitudeC, longitudeC),
longitudeA, longitudeB, longitudeC, longitudeD, longitudeE, longitudeF com.baidu.mapapi.model.LatLng(latitudeD, longitudeD),
com.baidu.mapapi.model.LatLng(latitudeE, longitudeE),
com.baidu.mapapi.model.LatLng(latitudeF, longitudeF),
) )
val maxLon = minOf( // val minLat =
longitudeA, longitudeB, longitudeC, longitudeD, longitudeE, longitudeF // minOf(latitudeA, latitudeB, latitudeC, latitudeD, latitudeE, latitudeF)
) // val maxLat =
val distance = DistanceUtil.getDistance( // minOf(latitudeA, latitudeB, latitudeC, latitudeD, latitudeE, latitudeF)
getBaiduMapLatLng(minLat, minLon), getBaiduMapLatLng(maxLat, maxLon) // val minLon = minOf(
) // longitudeA, longitudeB, longitudeC, longitudeD, longitudeE, longitudeF
setBaiduMapZoom(getDistanceZoom(distance)) // )
// val maxLon = minOf(
// longitudeA, longitudeB, longitudeC, longitudeD, longitudeE, longitudeF
// )
// val distance = DistanceUtil.getDistance(
// getBaiduMapLatLng(minLat, minLon), getBaiduMapLatLng(maxLat, maxLon)
// )
// setBaiduMapZoom(getDistanceZoom(distance))
} }
} }
} }

View File

@@ -16,8 +16,6 @@ import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.deprecated.ui.activity.profile.FencesAddActivity import com.abbidot.tracker.deprecated.ui.activity.profile.FencesAddActivity
import com.abbidot.tracker.ui.common.map.FencesMapCommon import com.abbidot.tracker.ui.common.map.FencesMapCommon
import com.abbidot.tracker.ui.fragment.map.baidumap.BaseBaiduMapFragment import com.abbidot.tracker.ui.fragment.map.baidumap.BaseBaiduMapFragment
import com.abbidot.tracker.util.LonAndLatUtil.Companion.getMaxLatOrLon
import com.abbidot.tracker.util.LonAndLatUtil.Companion.getMinLatOrLon
import com.abbidot.tracker.util.Util import com.abbidot.tracker.util.Util
import com.abbidot.tracker.util.ViewUtil import com.abbidot.tracker.util.ViewUtil
import com.abbidot.tracker.widget.FencesPolygonView import com.abbidot.tracker.widget.FencesPolygonView
@@ -88,8 +86,6 @@ class FencesAddBaiduMapFragment : BaseBaiduMapFragment() {
if (fencesAddActivity.isEdit) { if (fencesAddActivity.isEdit) {
locationSuccess(null) locationSuccess(null)
} else {
startLocation()
} }
//测试矩形围栏使用的代码 //测试矩形围栏使用的代码
@@ -276,27 +272,28 @@ class FencesAddBaiduMapFragment : BaseBaiduMapFragment() {
fun setRectMapZoom( fun setRectMapZoom(
rectALatLng: LatLng, rectBLatLng: LatLng, rectCLatLng: LatLng, rectDLatLng: LatLng rectALatLng: LatLng, rectBLatLng: LatLng, rectCLatLng: LatLng, rectDLatLng: LatLng
) { ) {
val maxLat = getMaxLatOrLon( // val maxLat = getMaxLatOrLon(
rectALatLng.latitude, rectBLatLng.latitude, rectCLatLng.latitude, rectDLatLng.latitude // rectALatLng.latitude, rectBLatLng.latitude, rectCLatLng.latitude, rectDLatLng.latitude
) // )
val maxLon = getMaxLatOrLon( // val maxLon = getMaxLatOrLon(
rectALatLng.longitude, // rectALatLng.longitude,
rectBLatLng.longitude, // rectBLatLng.longitude,
rectCLatLng.longitude, // rectCLatLng.longitude,
rectDLatLng.longitude // rectDLatLng.longitude
) // )
val minLat = getMinLatOrLon( // val minLat = getMinLatOrLon(
rectALatLng.latitude, rectBLatLng.latitude, rectCLatLng.latitude, rectDLatLng.latitude // rectALatLng.latitude, rectBLatLng.latitude, rectCLatLng.latitude, rectDLatLng.latitude
) // )
val minLon = getMinLatOrLon( // val minLon = getMinLatOrLon(
rectALatLng.longitude, // rectALatLng.longitude,
rectBLatLng.longitude, // rectBLatLng.longitude,
rectCLatLng.longitude, // rectCLatLng.longitude,
rectDLatLng.longitude // rectDLatLng.longitude
) // )
val zoom = getDistanceZoom(LatLng(minLat, minLon), LatLng(maxLat, maxLon)) // val zoom = getDistanceZoom(LatLng(minLat, minLon), LatLng(maxLat, maxLon))
LogUtil.e("百度地图zoom==$zoom") // LogUtil.e("百度地图zoom==$zoom")
setBaiduMapZoom(zoom) // setBaiduMapZoom(zoom)
setLatLngZoom(mContext!!, rectALatLng, rectBLatLng, rectCLatLng, rectDLatLng)
} }
/** /**

View File

@@ -77,8 +77,6 @@ class NavigationBaiduMapFragment: BaseBaiduMapFragment() {
isAnimMoveCamera = false, isAnimMoveCamera = false,
headBgResId = R.drawable.pic_map_location headBgResId = R.drawable.pic_map_location
) )
startLocation()
} }
} }

View File

@@ -72,8 +72,6 @@ class FencesAddGoogleMapFragment : BaseGoogleMapFragment() {
if (fencesAddActivity.isEdit) { if (fencesAddActivity.isEdit) {
locationSuccess(null) locationSuccess(null)
} else {
getLastLocation()
} }
} }

View File

@@ -137,7 +137,6 @@ class NavigationGoogleMapFragment: BaseGoogleMapFragment() {
refreshPetCurrentLocation(mPetLatLng!!, isAnimMoveCamera = false, refreshPetCurrentLocation(mPetLatLng!!, isAnimMoveCamera = false,
headBgResId = R.drawable.pic_map_location) headBgResId = R.drawable.pic_map_location)
getLastLocation()
} }
} }

View File

@@ -0,0 +1,84 @@
package com.abbidot.tracker.service
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import com.abbidot.baselibrary.constant.EventName
import com.abbidot.baselibrary.constant.MMKVKey
import com.abbidot.baselibrary.eventbus.XEventBus
import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.baselibrary.util.MMKVUtil
import com.abbidot.tracker.util.LonAndLatUtil
import com.baidu.location.BDAbstractLocationListener
import com.baidu.location.BDLocation
import com.baidu.location.LocationClient
import com.baidu.location.LocationClientOption
/**
* 百度定位服务
*/
class BaiduLocationService : Service() {
private val mBinder = LocalBinder()
private var mLocationClient: LocationClient? = null
private var mLocationListener: BDAbstractLocationListener? = null
//坐标类型,定位SDK默认输出GCJ02坐标,地图SDK默认输出BD09ll坐标。火星GCJ02坐标https://lbsyun.baidu.com/faq/api?title=androidsdk/guide/create-map/location
private val mCordType = "GCJ02" // Keep consistent with original coordinate type
inner class LocalBinder : Binder() {
fun getService(): BaiduLocationService = this@BaiduLocationService
}
fun startLocation(locationPeriod: Int = 1, needStopLocation: Boolean = false) {
if (mLocationClient != null) return
mLocationClient = LocationClient(applicationContext).apply {
locOption = LocationClientOption().apply {
openGps = true
setCoorType(mCordType)
setScanSpan(locationPeriod * 1000)
}
mLocationListener = object : BDAbstractLocationListener() {
override fun onReceiveLocation(location: BDLocation?) {
location?.let {
LogUtil.e("百度定位成功: ${it.latitude}, ${it.longitude}")
if (needStopLocation) stopLocation()
//转换为gps经纬度
LonAndLatUtil.convertFromGCJ02ToWGS84(it.latitude, it.longitude)
.let { (lat, lon) ->
MMKVUtil.putDouble(MMKVKey.UserGpsLat, lat)
MMKVUtil.putDouble(MMKVKey.UserGpsLon, lon)
//Android 百度定位 SDK 中,location.getSpeed() 返回的单位是 公里/小时(km/h)。
//注意:
//只有 GNSS/卫星定位结果通常才有速度信息。
//非 GNSS 定位时可能没有有效速度,默认值是 0.0f。
//可先用 location.hasSpeed() 判断是否包含速度信息。
//保存速度单位是米/秒(m/s)`
MMKVUtil.putFloat(MMKVKey.UserGpsSpeed, (it.speed / 3.6f))
}
XEventBus.post(EventName.LocationData, it)
}
}
}
registerLocationListener(mLocationListener)
start()
}
}
fun stopLocation() {
mLocationClient?.apply {
stop()
unRegisterLocationListener(mLocationListener)
}
mLocationClient = null
}
override fun onBind(intent: Intent): IBinder = mBinder
override fun onDestroy() {
super.onDestroy()
stopLocation()
}
}

View File

@@ -0,0 +1,116 @@
package com.abbidot.tracker.service
import android.annotation.SuppressLint
import android.app.Service
import android.content.Intent
import android.location.Location
import android.os.Binder
import android.os.IBinder
import com.abbidot.baselibrary.constant.EventName
import com.abbidot.baselibrary.constant.MMKVKey
import com.abbidot.baselibrary.eventbus.XEventBus
import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.baselibrary.util.MMKVUtil
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationAvailability
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.Priority
import com.hjq.toast.Toaster
/**
* 谷歌定位服务
*/
class GoogleLocationService : Service() {
private val mBinder = LocalBinder()
// The Fused Location Provider provides access to location APIs.
private var mFusedLocationClient: FusedLocationProviderClient? = null
inner class LocalBinder : Binder() {
fun getService(): GoogleLocationService = this@GoogleLocationService
}
private var mLocationCallback: LocationCallback? = null
@SuppressLint("MissingPermission")
fun startLocation() {
if (null == mFusedLocationClient) {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
}
if (null == mLocationCallback) {
mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
locationResult.lastLocation?.let {
Toaster.show("谷歌定位成功")
LogUtil.e("谷歌定位成功: ${it.latitude}, ${it.longitude}")
setLocationData(it)
XEventBus.post(EventName.LocationData, it)
}
// for (location in locationResult.locations) {
// // 处理位置信息
// val lat = location.latitude
// val lng = location.longitude
// // 更新 UI 或业务逻辑
// }
}
override fun onLocationAvailability(availability: LocationAvailability) {
// 当位置可用性发生变化时调用(例如 GPS 信号丢失)
}
}
}
mFusedLocationClient?.apply {
// // 设置期望的更新间隔为 20 秒
val locationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 20000L)
//‌请求持续时间‌。请求在此时间后自动过期并移除。默认为 Long.MAX_VALUE(无限期)。
// .setDurationMillis(Long.MAX_VALUE)
// 位置变化超过10米才更新
.setMinUpdateDistanceMeters(10f)
// 设置最大延迟为 30 秒(用于批量处理以省电)
.setMaxUpdateDelayMillis(30000L)
// ‌最小更新间隔‌。应用能处理位置更新的最快频率。如果其他应用请求更高频率,你的应用不会收到比这更快的更新,有助于节省电量
// .setMinUpdateIntervalMillis(5000L)
.build()
mLocationCallback?.let { callback ->
try {
requestLocationUpdates(locationRequest, callback, mainLooper)
} catch (e: SecurityException) {
// 无定位权限
LogUtil.e("GoogleLocationService异常:${e.message}")
}
}
}
}
private fun setLocationData(location: Location) {
location.apply {
MMKVUtil.putDouble(MMKVKey.UserGpsLat, latitude)
MMKVUtil.putDouble(MMKVKey.UserGpsLon, longitude)
//单位是米/秒(m/s)
MMKVUtil.putFloat(MMKVKey.UserGpsSpeed, speed)
}
}
fun stopLocation() {
mFusedLocationClient?.let { client ->
mLocationCallback?.let { callback ->
client.removeLocationUpdates(callback)
}
}
// 回调置空,释放引用防内存泄漏
mLocationCallback = null
}
override fun onBind(intent: Intent): IBinder = mBinder
override fun onDestroy() {
super.onDestroy()
stopLocation()
}
}

View File

@@ -50,6 +50,8 @@ import com.abbidot.tracker.ui.fragment.data.ActivityV2Fragment
import com.abbidot.tracker.ui.fragment.data.RouteV3Fragment import com.abbidot.tracker.ui.fragment.data.RouteV3Fragment
import com.abbidot.tracker.ui.fragment.map.MapV3Fragment import com.abbidot.tracker.ui.fragment.map.MapV3Fragment
import com.abbidot.tracker.ui.fragment.pet.PetV2Fragment import com.abbidot.tracker.ui.fragment.pet.PetV2Fragment
import com.abbidot.tracker.util.BaiduLocationManager
import com.abbidot.tracker.util.GoogleLocationManager
import com.abbidot.tracker.util.Util import com.abbidot.tracker.util.Util
import com.abbidot.tracker.util.ViewUtil import com.abbidot.tracker.util.ViewUtil
import com.abbidot.tracker.util.bluetooth.SRBleUtil import com.abbidot.tracker.util.bluetooth.SRBleUtil
@@ -134,6 +136,7 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
setStatusBarLight() setStatusBarLight()
mSelectPetPosition = MMKVUtil.getInt(MMKVKey.PetSelectPosition) mSelectPetPosition = MMKVUtil.getInt(MMKVKey.PetSelectPosition)
startUpLocation()
mViewBinding.homeV2ViewPager2.let { mViewBinding.homeV2ViewPager2.let {
it.adapter = ViewPagerAdapter(mFragments, this).apply { it.adapter = ViewPagerAdapter(mFragments, this).apply {
@@ -799,6 +802,32 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
} }
} }
/**
* 开始定位
*/
private fun startUpLocation() {
LogUtil.e("开始定位")
if (AppUtils.isChina()) {
//30秒定位一次,定位精度为高精度
BaiduLocationManager.startLocation(30)
} else {
GoogleLocationManager.startLocation()
}
}
/**
* 停止定位
*/
private fun stopUpLocation() {
LogUtil.e("停止定位")
if (AppUtils.isChina()) {
BaiduLocationManager.stopLocation()
} else {
GoogleLocationManager.stopLocation()
}
}
// override fun onTrimMemory(level: Int) { // override fun onTrimMemory(level: Int) {
// super.onTrimMemory(level) // super.onTrimMemory(level)
// LogUtil.e("系统级别:$level"+printLevel(level)) // LogUtil.e("系统级别:$level"+printLevel(level))
@@ -839,8 +868,8 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
LogUtil.e("HomeV2Activity---------------onDestroy") LogUtil.e("HomeV2Activity---------------onDestroy")
stopUpLocation()
stopCountDownConBle() stopCountDownConBle()
// mSocketUtilManage?.destroy()
mBleListenerReceiver?.let { mBleListenerReceiver?.let {
unregisterReceiver(it) unregisterReceiver(it)
} }

View File

@@ -244,7 +244,7 @@ class AddPairedSuccessActivity :
startActivity(intent) startActivity(intent)
} }
} }
}, 1500) }, 1000)
} }
// override fun onRequestError(exceptionCode: String?) { // override fun onRequestError(exceptionCode: String?) {

View File

@@ -77,8 +77,7 @@ open class AddAndEditFencesZoneBaseActivity :
private var isBlockedClick = false private var isBlockedClick = false
private var mShowCenterLocationType = ConstantInt.OtherLocationType private var mShowCenterLocationType = ConstantInt.OtherLocationType
private val mDefaultFencesName = private val mDefaultFencesName = mutableListOf<String>()
arrayOf("Home", "Office", "Garden", "Park", "Play", "Unsafe", "Vegetable Garden", "Water")
//是否是卫星地图 //是否是卫星地图
private var isSatelliteMap = false private var isSatelliteMap = false
@@ -146,12 +145,12 @@ open class AddAndEditFencesZoneBaseActivity :
addListData() addListData()
mFencesZoneShapeAdapter = mFencesZoneShapeAdapter =
VirtualFencesZoneShadeAdapter(mContext, mFencesZoneShapeList).apply { VirtualFencesZoneShadeAdapter(mContext, mFencesZoneShapeList).let {
setOnItemClickListener(object : BaseRecyclerAdapter.OnItemClickListener { it.setOnItemClickListener(object : BaseRecyclerAdapter.OnItemClickListener {
override fun onItemClick(itemView: View?, pos: Int) { override fun onItemClick(itemView: View?, pos: Int) {
if (mFencesZoneShapeList[pos].selected) return if (mFencesZoneShapeList[pos].selected) return
ViewUtil.instance.updateDataBeanOnlySelectedItem( ViewUtil.instance.updateDataBeanOnlySelectedItem(
this@apply, mFencesZoneShapeList, pos it, mFencesZoneShapeList, pos
) )
setFenceShape(pos + 1) setFenceShape(pos + 1)
mFencesMapCommon.calculateDistanceAndGetPointLatLng( mFencesMapCommon.calculateDistanceAndGetPointLatLng(
@@ -159,23 +158,25 @@ open class AddAndEditFencesZoneBaseActivity :
) )
} }
}) })
it
} }
ViewUtil.instance.setRecyclerViewFlexboxLayout( ViewUtil.instance.setRecyclerViewFlexboxLayout(
mContext, rvFencesZoneShapeList, mFencesZoneShapeAdapter mContext, rvFencesZoneShapeList, mFencesZoneShapeAdapter
) )
mSelectTypeShadeAdapter = mSelectTypeShadeAdapter =
SelectFencesTypeCardShadeAdapter(mContext, mFencesZoneTypeList).apply { SelectFencesTypeCardShadeAdapter(mContext, mFencesZoneTypeList).let {
setOnItemClickListener(object : BaseRecyclerAdapter.OnItemClickListener { it.setOnItemClickListener(object : BaseRecyclerAdapter.OnItemClickListener {
override fun onItemClick(itemView: View?, pos: Int) { override fun onItemClick(itemView: View?, pos: Int) {
ViewUtil.instance.updateDataBeanOnlySelectedItem( ViewUtil.instance.updateDataBeanOnlySelectedItem(
this@apply, mFencesZoneTypeList, pos it, mFencesZoneTypeList, pos
) )
if (mFencesBean.fenceType == 2) mFencesBean.fenceNameType = pos + 6 if (mFencesBean.fenceType == 2) mFencesBean.fenceNameType = pos + 6
else mFencesBean.fenceNameType = pos + 1 else mFencesBean.fenceNameType = pos + 1
setFenceName() setFenceName()
} }
}) })
it
} }
ViewUtil.instance.setRecyclerViewGridLayout( ViewUtil.instance.setRecyclerViewGridLayout(
mContext, rvFencesZoneImageTypeList, mSelectTypeShadeAdapter, 5 mContext, rvFencesZoneImageTypeList, mSelectTypeShadeAdapter, 5
@@ -335,6 +336,8 @@ open class AddAndEditFencesZoneBaseActivity :
* 地图上画已添加的围栏 * 地图上画已添加的围栏
*/ */
fun drawFences() { fun drawFences() {
//延时执行,等待地图渲染完成
mViewBinding.root.postDelayed({
mFencesList?.apply { mFencesList?.apply {
nogoFenceList?.let { nogoFenceList?.let {
mHaveFencesList.addAll(it.toList()) mHaveFencesList.addAll(it.toList())
@@ -343,10 +346,12 @@ open class AddAndEditFencesZoneBaseActivity :
mHaveFencesList.addAll(it.toList()) mHaveFencesList.addAll(it.toList())
} }
if (mHaveFencesList.size > 0) mFencesMapViewModel.setImageFencesData( if (mHaveFencesList.isNotEmpty()) mFencesMapViewModel.setImageFencesData(
mContext, mHaveFencesList, mFragment, isSatelliteMap = isSatelliteMap mContext, mHaveFencesList, mFragment, isSatelliteMap = isSatelliteMap
) )
} }
}, 200)
} }
/** /**
@@ -525,6 +530,15 @@ open class AddAndEditFencesZoneBaseActivity :
} }
private fun addListData() { private fun addListData() {
mDefaultFencesName.add(getString(R.string.txt_home))
mDefaultFencesName.add(getString(R.string.txt_office))
mDefaultFencesName.add(getString(R.string.txt_garden))
mDefaultFencesName.add(getString(R.string.txt_park))
mDefaultFencesName.add(getString(R.string.txt_play))
mDefaultFencesName.add(getString(R.string.txt_unsafe))
mDefaultFencesName.add(getString(R.string.txt_vegetable_garden))
mDefaultFencesName.add(getString(R.string.txt_water))
mFencesZoneShapeList = mutableListOf() mFencesZoneShapeList = mutableListOf()
with(DataBean()) { with(DataBean()) {
imageId = R.drawable.icon_fence_circle_shape_svg imageId = R.drawable.icon_fence_circle_shape_svg

View File

@@ -1,6 +1,5 @@
package com.abbidot.tracker.ui.activity.device.wifi package com.abbidot.tracker.ui.activity.device.wifi
import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.wifi.WifiManager import android.net.wifi.WifiManager
import android.provider.Settings import android.provider.Settings
@@ -48,7 +47,7 @@ class AddWifiPowerZone2Activity :
else setLeftBackImage(R.drawable.icon_white_back_svg) else setLeftBackImage(R.drawable.icon_white_back_svg)
mWifiZone2MapCommon = WifiZone2MapCommon() mWifiZone2MapCommon = WifiZone2MapCommon()
mFragment = mWifiZone2MapCommon.getMapFragment(mContext) mFragment = mWifiZone2MapCommon.getMapFragment(mContext, isFirstBind)
mViewBinding.apply { mViewBinding.apply {
tvWifiZone2LaterBtn.visibility = if (isFirstBind) View.VISIBLE tvWifiZone2LaterBtn.visibility = if (isFirstBind) View.VISIBLE
@@ -80,7 +79,7 @@ class AddWifiPowerZone2Activity :
mPetBean?.let { mPetBean?.let {
if (it.deviceType == ConstantInt.Type2) { if (it.deviceType == ConstantInt.Type2) {
val wifiManager = val wifiManager =
applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager applicationContext.getSystemService(WIFI_SERVICE) as WifiManager
if (!wifiManager.isWifiEnabled) { if (!wifiManager.isWifiEnabled) {
val intent = Intent(Settings.ACTION_WIFI_SETTINGS) val intent = Intent(Settings.ACTION_WIFI_SETTINGS)
startActivity(intent) startActivity(intent)
@@ -105,7 +104,9 @@ class AddWifiPowerZone2Activity :
override fun onClick(v: View?) { override fun onClick(v: View?) {
mViewBinding.apply { mViewBinding.apply {
when (v!!) { when (v!!) {
btnAddWifiZone2Next -> Util.checkBluetoothPermissionsEnabled(this@AddWifiPowerZone2Activity, { btnAddWifiZone2Next -> Util.checkBluetoothPermissionsEnabled(
this@AddWifiPowerZone2Activity,
{
goNext() goNext()
}) })

View File

@@ -229,7 +229,7 @@ class PaymentSuccessActivity :
} }
startActivity(intent) startActivity(intent)
} }
}, 1500) }, 1000)
} }
}) })
} }

View File

@@ -4,7 +4,6 @@ import android.content.Intent
import android.graphics.Paint import android.graphics.Paint
import android.view.Gravity import android.view.Gravity
import android.view.View import android.view.View
import android.widget.RadioGroup
import androidx.activity.viewModels import androidx.activity.viewModels
import com.abbidot.baselibrary.constant.EventName import com.abbidot.baselibrary.constant.EventName
import com.abbidot.baselibrary.constant.MMKVKey import com.abbidot.baselibrary.constant.MMKVKey
@@ -28,7 +27,6 @@ import com.abbidot.tracker.util.ViewUtil
import com.abbidot.tracker.vm.GeoCoderViewModel import com.abbidot.tracker.vm.GeoCoderViewModel
import com.abbidot.tracker.vm.GoogleLocationViewModel import com.abbidot.tracker.vm.GoogleLocationViewModel
import com.abbidot.tracker.vm.SubscriptionManageViewModel import com.abbidot.tracker.vm.SubscriptionManageViewModel
import com.abbidot.tracker.widget.TypefaceRoundButton
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import kotlin.math.abs import kotlin.math.abs
@@ -493,28 +491,28 @@ class SureSubscriptionPlanActivity :
mViewBinding.apply { mViewBinding.apply {
when (v!!) { when (v!!) {
btnSureSubscribePlan1Continue -> { btnSureSubscribePlan1Continue -> {
if (AppUtils.isChina()) { // if (AppUtils.isChina()) {
if (null == mRechargePayOptionsCn) { // if (null == mRechargePayOptionsCn) {
mRechargePayOptionsCn = ViewUtil.instance.showBottomSheet( // mRechargePayOptionsCn = ViewUtil.instance.showBottomSheet(
mContext, // mContext,
R.layout.layout_recharge_pay_options_cn // R.layout.layout_recharge_pay_options_cn
).apply { // ).apply {
setOnClickListenerViews(findViewById<TypefaceRoundButton>(R.id.btn_pay_cn_chose_sure)) // setOnClickListenerViews(findViewById<TypefaceRoundButton>(R.id.btn_pay_cn_chose_sure))
findViewById<RadioGroup>(R.id.rg_pay_cn_chose)?.let { // findViewById<RadioGroup>(R.id.rg_pay_cn_chose)?.let {
it.setOnCheckedChangeListener { _, checkedId -> // it.setOnCheckedChangeListener { _, checkedId ->
when (checkedId) { // when (checkedId) {
R.id.rb_pay_cn_chose_alipay -> mPayCnOption = // R.id.rb_pay_cn_chose_alipay -> mPayCnOption =
ConstantInt.Type0 // ConstantInt.Type0
//
R.id.rb_pay_cn_chose_wxpay -> mPayCnOption = // R.id.rb_pay_cn_chose_wxpay -> mPayCnOption =
ConstantInt.Type1 // ConstantInt.Type1
} // }
} // }
} // }
} // }
} // }
return // return
} // }
createOrder() createOrder()
} }

View File

@@ -7,7 +7,7 @@ import com.abbidot.tracker.R
import com.abbidot.tracker.base.BaseMapCommon import com.abbidot.tracker.base.BaseMapCommon
import com.abbidot.tracker.bean.WiFiZoneBean import com.abbidot.tracker.bean.WiFiZoneBean
import com.abbidot.tracker.constant.ConstantInt import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.deprecated.ui.fragment.map.baidumap.NavigationBaiduMapFragment import com.abbidot.tracker.ui.fragment.map.baidumap.EditWiFiZoneBaiduFragment
import com.abbidot.tracker.ui.fragment.map.googlemap.EditWiFiZoneGoogleMapFragment import com.abbidot.tracker.ui.fragment.map.googlemap.EditWiFiZoneGoogleMapFragment
/** /**
@@ -18,13 +18,14 @@ import com.abbidot.tracker.ui.fragment.map.googlemap.EditWiFiZoneGoogleMapFragme
class EditWifiZoneMapCommon : BaseMapCommon() { class EditWifiZoneMapCommon : BaseMapCommon() {
private var mEditZoneGoogleMapFragment: EditWiFiZoneGoogleMapFragment? = null private var mEditZoneGoogleMapFragment: EditWiFiZoneGoogleMapFragment? = null
private var mBaiduMapFragment: NavigationBaiduMapFragment? = null private var mBaiduMapFragment: EditWiFiZoneBaiduFragment? = null
fun getMapFragment( fun getMapFragment(
context: Context, wiFiZoneBean: WiFiZoneBean, mapLoadOk: () -> Unit context: Context, wiFiZoneBean: WiFiZoneBean, mapLoadOk: () -> Unit
): Fragment { ): Fragment {
return if (AppUtils.isChina(AppUtils.SWITCH_MAP_TYPE)) { return if (AppUtils.isChina(AppUtils.SWITCH_MAP_TYPE)) {
mBaiduMapFragment = NavigationBaiduMapFragment.newInstance(context) mBaiduMapFragment =
EditWiFiZoneBaiduFragment.newInstance(context, wiFiZoneBean, mapLoadOk)
mBaiduMapFragment!! mBaiduMapFragment!!
} else { } else {
mEditZoneGoogleMapFragment = mEditZoneGoogleMapFragment =
@@ -41,6 +42,14 @@ class EditWifiZoneMapCommon : BaseMapCommon() {
moveCameraLocation(lat, lon) moveCameraLocation(lat, lon)
addImageMarker(lat, lon, R.drawable.icon_location_svg, false, isDraggable) addImageMarker(lat, lon, R.drawable.icon_location_svg, false, isDraggable)
} }
mBaiduMapFragment?.apply {
moveCameraLocation(lat, lon)
addImageMarker(
lat, lon, R.drawable.icon_location_svg,
needConvertGCJ02 = true,
anchorCenter = false
)
}
} }
/** /**

View File

@@ -135,7 +135,7 @@ class FencesAddEditMapCommon : BaseMapCommon() {
if (null != mFencesGoogleMapFragment) { if (null != mFencesGoogleMapFragment) {
mFencesGoogleMapFragment?.mapOkAndDistancePointLatLng(delayMillis) mFencesGoogleMapFragment?.mapOkAndDistancePointLatLng(delayMillis)
} else if (null != mFencesBaiduMapFragment) { } else if (null != mFencesBaiduMapFragment) {
mFencesBaiduMapFragment?.mapOkAndDistancePointLatLng() mFencesBaiduMapFragment?.mapOkAndDistancePointLatLng(delayMillis)
} }
} }

View File

@@ -117,21 +117,18 @@ class HistoryDataMapCommon : BaseMapCommon() {
} }
} }
fun showInfoWindow(historyDataBean: HistoryDataBean) {
if (null != mHistoryDataBaiduMapFragment) {
mHistoryDataBaiduMapFragment!!.showMarkerInfoWindow(historyDataBean)
} else if (null != mHistoryDataGoogleMapFragment) {
mHistoryDataGoogleMapFragment!!.showMarkerInfoWindow(historyDataBean)
}
}
fun resetMarkerInfoViewOffset() { fun resetMarkerInfoViewOffset() {
mHistoryDataGoogleMapFragment?.resetMarkerInfoViewOffset() mHistoryDataGoogleMapFragment?.resetMarkerInfoViewOffset()
} }
fun setPetUserLatLng() { fun setPetUserLatLng() {
if (null != mHistoryDataBaiduMapFragment) { if (null != mHistoryDataBaiduMapFragment) {
// mHistoryDataBaiduMapFragment!!.setPetUserLatLng() mHistoryDataBaiduMapFragment?.apply {
mUserLatLng?.let {
moveCameraLocation(it)
setPetMarkerLatLng(it)
}
}
} else if (null != mHistoryDataGoogleMapFragment) { } else if (null != mHistoryDataGoogleMapFragment) {
mHistoryDataGoogleMapFragment?.apply { mHistoryDataGoogleMapFragment?.apply {
mUserLatLng?.let { mUserLatLng?.let {

View File

@@ -5,7 +5,7 @@ import androidx.fragment.app.Fragment
import com.abbidot.baselibrary.util.AppUtils import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.tracker.base.BaseMapCommon import com.abbidot.tracker.base.BaseMapCommon
import com.abbidot.tracker.bean.HistoryDataBean import com.abbidot.tracker.bean.HistoryDataBean
import com.abbidot.tracker.deprecated.ui.fragment.map.baidumap.NavigationBaiduMapFragment import com.abbidot.tracker.ui.fragment.map.baidumap.WiFiZoneBaiduMapFragment
import com.abbidot.tracker.ui.fragment.map.googlemap.WiFiZone2GoogleMapFragment import com.abbidot.tracker.ui.fragment.map.googlemap.WiFiZone2GoogleMapFragment
/** /**
@@ -16,20 +16,20 @@ import com.abbidot.tracker.ui.fragment.map.googlemap.WiFiZone2GoogleMapFragment
class WifiZone2MapCommon : BaseMapCommon() { class WifiZone2MapCommon : BaseMapCommon() {
private var mWiFiZone2GoogleMapFragment: WiFiZone2GoogleMapFragment? = null private var mWiFiZone2GoogleMapFragment: WiFiZone2GoogleMapFragment? = null
private var mBaiduMapFragment: NavigationBaiduMapFragment? = null private var mBaiduMapFragment: WiFiZoneBaiduMapFragment? = null
fun getMapFragment(context: Context): Fragment { fun getMapFragment(context: Context, firstBind: Boolean): Fragment {
return if (AppUtils.isChina(AppUtils.SWITCH_MAP_TYPE)) { return if (AppUtils.isChina(AppUtils.SWITCH_MAP_TYPE)) {
mBaiduMapFragment = NavigationBaiduMapFragment.newInstance(context) mBaiduMapFragment = WiFiZoneBaiduMapFragment.newInstance(context)
mBaiduMapFragment!! mBaiduMapFragment!!
} else { } else {
mWiFiZone2GoogleMapFragment = WiFiZone2GoogleMapFragment.newInstance(context) mWiFiZone2GoogleMapFragment = WiFiZone2GoogleMapFragment.newInstance(context, firstBind)
mWiFiZone2GoogleMapFragment!! mWiFiZone2GoogleMapFragment!!
} }
} }
fun refreshLocation() { fun refreshLocation() {
mWiFiZone2GoogleMapFragment?.getLastLocation() // mWiFiZone2GoogleMapFragment?.getLastLocation()
} }
/** /**
@@ -43,6 +43,9 @@ class WifiZone2MapCommon : BaseMapCommon() {
if (null != mWiFiZone2GoogleMapFragment) { if (null != mWiFiZone2GoogleMapFragment) {
if (null !== mWiFiZone2GoogleMapFragment!!.mDecWifiAddressData) return mWiFiZone2GoogleMapFragment!!.mDecWifiAddressData if (null !== mWiFiZone2GoogleMapFragment!!.mDecWifiAddressData) return mWiFiZone2GoogleMapFragment!!.mDecWifiAddressData
return null return null
} else if (null != mBaiduMapFragment) {
if (null !== mBaiduMapFragment!!.mDecWifiAddressData) return mBaiduMapFragment!!.mDecWifiAddressData
return null
} }
return null return null
} }

View File

@@ -13,7 +13,9 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.abbidot.baselibrary.constant.EventName
import com.abbidot.baselibrary.constant.MMKVKey import com.abbidot.baselibrary.constant.MMKVKey
import com.abbidot.baselibrary.eventbus.XEventBus
import com.abbidot.baselibrary.util.AppUtils import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.baselibrary.util.LogUtil import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.baselibrary.util.MMKVUtil import com.abbidot.baselibrary.util.MMKVUtil
@@ -32,10 +34,7 @@ import com.abbidot.tracker.util.Util.Companion.safeRecycle
import com.abbidot.tracker.util.ViewUtil import com.abbidot.tracker.util.ViewUtil
import com.abbidot.tracker.widget.MapMarkerInfoView import com.abbidot.tracker.widget.MapMarkerInfoView
import com.abbidot.tracker.widget.TypefaceTextView import com.abbidot.tracker.widget.TypefaceTextView
import com.baidu.location.BDAbstractLocationListener
import com.baidu.location.BDLocation import com.baidu.location.BDLocation
import com.baidu.location.LocationClient
import com.baidu.location.LocationClientOption
import com.baidu.mapapi.map.BaiduMap import com.baidu.mapapi.map.BaiduMap
import com.baidu.mapapi.map.BitmapDescriptor import com.baidu.mapapi.map.BitmapDescriptor
import com.baidu.mapapi.map.BitmapDescriptorFactory import com.baidu.mapapi.map.BitmapDescriptorFactory
@@ -54,6 +53,7 @@ import com.baidu.mapapi.map.PolylineOptions
import com.baidu.mapapi.map.Stroke import com.baidu.mapapi.map.Stroke
import com.baidu.mapapi.map.TextureMapView import com.baidu.mapapi.map.TextureMapView
import com.baidu.mapapi.model.LatLng import com.baidu.mapapi.model.LatLng
import com.baidu.mapapi.model.LatLngBounds
import com.baidu.mapapi.utils.DistanceUtil import com.baidu.mapapi.utils.DistanceUtil
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.math.abs import kotlin.math.abs
@@ -74,25 +74,17 @@ abstract class BaseBaiduMapFragment :
var isMapLoadOk = false var isMapLoadOk = false
//地图放大 //地图放大
private var mBaiduMapZoom = 19f private var mBaiduMapZoom = 18.8f
//自定显示宠物头像地点信息图层 //自定显示宠物头像地点信息图层
protected var mMarker: Overlay? = null protected var mMarker: Overlay? = null
//宠物大头针设置自定义头像
private var mPetHeadIconBitmap: Bitmap? = null
//宠物头像地址 //宠物头像地址
var mPetHeadUrl = "" var mPetHeadUrl = ""
//头像为空,用默认类型的头像 //头像为空,用默认类型的头像
private var mPetType = ConstantInt.DogPetType private var mPetType = ConstantInt.DogPetType
//坐标类型,定位SDK默认输出GCJ02坐标,地图SDK默认输出BD09ll坐标。火星GCJ02坐标https://lbsyun.baidu.com/faq/api?title=androidsdk/guide/create-map/location
private val mCoordType = "GCJ02"
private var mLocationClient: LocationClient? = null
private var mLocationListener: BDAbstractLocationListener? = null
private var mSensorManager: SensorManager? = null private var mSensorManager: SensorManager? = null
private var mSensor: Sensor? = null private var mSensor: Sensor? = null
private var mSensorEventListener: SensorEventListener? = null private var mSensorEventListener: SensorEventListener? = null
@@ -132,15 +124,40 @@ abstract class BaseBaiduMapFragment :
//自定义精度圈边框颜色 //自定义精度圈边框颜色
setMyLocationConfiguration(locationConfiguration) setMyLocationConfiguration(locationConfiguration)
//没有宠物位置,默认北京经纬度
val lat = MMKVUtil.getDouble(MMKVKey.MapShowDefaultLat)
val lon = MMKVUtil.getDouble(MMKVKey.MapShowDefaultLon)
if (lat != 0.0 && lon != 0.0) {
val status = MapStatusUpdateFactory.newLatLng(getBaiduMapLatLng(lat, lon))
setMapStatus(status)
}
uiSettings.let {
//设置是否允许俯视手势 //设置是否允许俯视手势
uiSettings.isOverlookingGesturesEnabled = false it.isOverlookingGesturesEnabled = false
//设置是否允许抛出惯性手势 //设置是否允许抛出惯性手势
uiSettings.setFlingEnable(false) it.setFlingEnable(false)
//指南针为开启状态
it.isCompassEnabled = true
}
setOnMapLoadedCallback { setOnMapLoadedCallback {
LogUtil.e("百度地图加载好了") LogUtil.e("百度地图加载好了")
isMapLoadOk = true isMapLoadOk = true
initMyLocationData()
XEventBus.observe(viewLifecycleOwner, EventName.LocationData) { loc: BDLocation ->
mUserLatLng = LatLng(loc.latitude, loc.longitude)
val locData = MyLocationData.Builder().accuracy(loc.radius)
// 此处设置开发者获取到的方向信息,顺时针0-360
.direction(loc.direction).latitude(loc.latitude).longitude(loc.longitude)
.build()
// LogUtil.e("百度定位成功返回: ${loc.latitude}, ${loc.longitude}")
setMyLocationData(locData)
locationSuccess(loc)
}
onMapLoadOk(this) onMapLoadOk(this)
} }
} }
@@ -184,6 +201,25 @@ abstract class BaseBaiduMapFragment :
} }
} }
/**
* 初始化用户位置数据
*/
private fun initMyLocationData() {
initSensorEvent(mContext!!)
mBaiduMap?.apply {
val userGpsLat = MMKVUtil.getDouble(MMKVKey.UserGpsLat)
val userGpsLon = MMKVUtil.getDouble(MMKVKey.UserGpsLon)
if (userGpsLat != 0.0 || userGpsLon != 0.0) {
getBaiduMapLatLng(userGpsLat, userGpsLon).let {
val locData =
MyLocationData.Builder().latitude(it.latitude).longitude(it.longitude)
.build()
setMyLocationData(locData)
}
}
}
}
/** /**
* 设置地图样式 * 设置地图样式
*/ */
@@ -223,8 +259,6 @@ abstract class BaseBaiduMapFragment :
*/ */
fun setPetHeadIconUrl(petHeadUrl: String) { fun setPetHeadIconUrl(petHeadUrl: String) {
mPetHeadUrl = petHeadUrl mPetHeadUrl = petHeadUrl
mPetHeadIconBitmap.safeRecycle()
mPetHeadIconBitmap = null
} }
/** /**
@@ -249,6 +283,21 @@ abstract class BaseBaiduMapFragment :
mMarker = mBaiduMap!!.addOverlay(option) mMarker = mBaiduMap!!.addOverlay(option)
} }
/**
* 由 points 组成的区域 距离手机屏幕距离screenPaddingPx 像素单位
*/
fun setLatLngZoom(context: Context, vararg points: LatLng) {
// val width = context.resources.displayMetrics.widthPixels
// val height = context.resources.displayMetrics.heightPixels
// val padding = width / 8
val builder = LatLngBounds.Builder()
for (item in points) {
builder.include(toGCJ02LatLon(item))
}
// bounds 设置显示在屏幕中的地图地理范围
mBaiduMap?.setMapStatus(MapStatusUpdateFactory.newLatLngZoom(builder.build(), 10, 0, 10, 0))
}
suspend fun getMarkerBitmapDescriptor( suspend fun getMarkerBitmapDescriptor(
context: Context, context: Context,
headUrl: String, headUrl: String,
@@ -287,22 +336,71 @@ abstract class BaseBaiduMapFragment :
/** /**
* 地图添加图片 * 地图添加图片
*/ */
private fun addImageMarker( fun addImageMarker(
lat: Double, lon: Double, imageTypeResId: Int, needConvertGCJ02: Boolean = true lat: Double,
) { lon: Double,
imageTypeResId: Int,
needConvertGCJ02: Boolean = true,
anchorCenter: Boolean = true,
): Overlay? {
var overlay: Overlay? = null
mBaiduMap?.apply { mBaiduMap?.apply {
val latLng = getBaiduMapLatLng(lat, lon, needConvertGCJ02) //构建MarkerOption,用于在地图上添加Marker ,目前支持掉下和生长两种动画
val option = getMarkerOptions(lat, lon, imageTypeResId, needConvertGCJ02, anchorCenter)
overlay = addOverlay(option)
}
return overlay
}
/**
* 获取地图Marker选项
* @param anchorCenter 锚点是否需要居中显示,默认(0.5f, 1.0f)水平居中,垂直下对齐,底下居中显示
*/
fun getMarkerOptions(
lat: Double,
lon: Double,
imageTypeResId: Int,
needConvertGCJ02: Boolean = true,
anchorCenter: Boolean = false,
): MarkerOptions? {
var markerOptions: MarkerOptions?
//构建MarkerOption,用于在地图上添加Marker ,animateTypes掉下动画
val latLng = getBaiduMapLatLng(lat, lon, needConvertGCJ02)
val bitmap = ImageUtil.getBitmapFromDrawableAndSvg(mContext!!, imageTypeResId) val bitmap = ImageUtil.getBitmapFromDrawableAndSvg(mContext!!, imageTypeResId)
//构建MarkerOption,用于在地图上添加Marker markerOptions =
val option =
MarkerOptions().position(latLng).animateType(MarkerOptions.MarkerAnimateType.grow) MarkerOptions().position(latLng).animateType(MarkerOptions.MarkerAnimateType.grow)
.icon(BitmapDescriptorFactory.fromBitmap(bitmap)).apply { .icon(BitmapDescriptorFactory.fromBitmap(bitmap)).apply {
if (anchorCenter) {
anchor(anchorX, anchorY / 2) anchor(anchorX, anchorY / 2)
} }
addOverlay(option)
bitmap?.recycle()
} }
bitmap?.safeRecycle()
return markerOptions
}
/**
* 获取地图Marker选项
* @param anchorCenter 锚点是否需要居中显示,默认(0.5f, 1.0f)水平居中,垂直下对齐,底下居中显示
*/
fun getMarkerOptions(
latLng: LatLng,
imageTypeResId: Int,
needConvertGCJ02: Boolean = true,
anchorCenter: Boolean = false,
): MarkerOptions? {
var markerOptions: MarkerOptions?
//构建MarkerOption,用于在地图上添加Marker ,animateTypes掉下动画
val latLng = getBaiduMapLatLng(latLng.latitude, latLng.longitude, needConvertGCJ02)
val bitmap = ImageUtil.getBitmapFromDrawableAndSvg(mContext!!, imageTypeResId)
markerOptions =
MarkerOptions().position(latLng).animateType(MarkerOptions.MarkerAnimateType.grow)
.icon(BitmapDescriptorFactory.fromBitmap(bitmap)).apply {
if (anchorCenter) {
anchor(anchorX, anchorY / 2)
}
}
bitmap?.safeRecycle()
return markerOptions
} }
/** /**
@@ -391,7 +489,7 @@ abstract class BaseBaiduMapFragment :
/** /**
* 显示信息窗(弹窗覆盖物InfoWindow) * 显示信息窗(弹窗覆盖物InfoWindow)
*/ */
fun showMarkerInfoWindow(historyDataBean: HistoryDataBean) { fun showMarkerInfoWindow(historyDataBean: HistoryDataBean, offsetY: Int = 0) {
historyDataBean.apply { historyDataBean.apply {
val convertLatLng = getBaiduMapLatLng(latitude, longitude) val convertLatLng = getBaiduMapLatLng(latitude, longitude)
val view = LayoutInflater.from(mContext).inflate(R.layout.marker_info_contents, null) val view = LayoutInflater.from(mContext).inflate(R.layout.marker_info_contents, null)
@@ -400,9 +498,9 @@ abstract class BaseBaiduMapFragment :
view.findViewById<TypefaceTextView>(R.id.map_pet_location_update_time) view.findViewById<TypefaceTextView>(R.id.map_pet_location_update_time)
addressTextView.text = address addressTextView.text = address
timeTextView.text = dayTime timeTextView.text = dayTime
val mInfoWindow = InfoWindow( addressTextView.visibility = if (TextUtils.isEmpty(address)) View.GONE else View.VISIBLE
view, convertLatLng, -(mPetHeadIconBitmap?.width!! + 30) timeTextView.visibility = if (TextUtils.isEmpty(dayTime)) View.GONE else View.VISIBLE
) val mInfoWindow = InfoWindow(view, convertLatLng, offsetY)
mBaiduMap?.showInfoWindow(mInfoWindow) mBaiduMap?.showInfoWindow(mInfoWindow)
} }
} }
@@ -661,9 +759,9 @@ abstract class BaseBaiduMapFragment :
//添加起始点图片 //添加起始点图片
if (startCapImageRes > 0) { if (startCapImageRes > 0) {
//构建MarkerOption,用于在地图上添加Marker //构建MarkerOption,用于在地图上添加Marker
val option = MarkerOptions().position(latLngList[0]) val option = getMarkerOptions(
.animateType(MarkerOptions.MarkerAnimateType.grow) latLngList[0], startCapImageRes, needConvertGCJ02 = false, anchorCenter = true
.icon(BitmapDescriptorFactory.fromResource(startCapImageRes)) )
//在地图上添加Marker,并显示 //在地图上添加Marker,并显示
baiduMap.addOverlay(option) baiduMap.addOverlay(option)
} }
@@ -685,63 +783,11 @@ abstract class BaseBaiduMapFragment :
clearFenceList() clearFenceList()
} }
/**
* 开始定位,请求用户当前的位置
*/
fun startLocation(locationPeriod: Int = 1, needStopLocation: Boolean = true) {
if (null != mLocationClient) return
initSensorEvent(mContext!!)
//定位初始化
mLocationClient = LocationClient(mContext)
//通过LocationClientOption设置LocationClient相关参数
val option = LocationClientOption()
// 打开gps
option.openGps = true
// 设置坐标类型
option.setCoorType(mCoordType)
//设置定位刷新间隔
option.setScanSpan(locationPeriod * 1000)
//设置locationClientOption
mLocationClient!!.locOption = option
//注册LocationListener监听器
mLocationListener = object : BDAbstractLocationListener() {
override fun onReceiveLocation(location: BDLocation?) {
//mapView 销毁后不在处理新接收的位置
if (null == location) {
return
}
val locData = MyLocationData.Builder().accuracy(location.radius)
// 此处设置开发者获取到的方向信息,顺时针0-360
.direction(location.direction).latitude(location.latitude)
.longitude(location.longitude).build()
LogUtil.e("百度定位成功: ${location.latitude}, ${location.longitude}")
mBaiduMap!!.setMyLocationData(locData)
if (needStopLocation) stopLocation()
//转换为gps经纬度
LonAndLatUtil.convertFromGCJ02ToWGS84(location.latitude, location.longitude).let {
MMKVUtil.putDouble(MMKVKey.UserGpsLat, it[0])
MMKVUtil.putDouble(MMKVKey.UserGpsLon, it[1])
//Android 百度定位 SDK 中,location.getSpeed() 返回的单位是 公里/小时(km/h)。
//注意:
//只有 GNSS/卫星定位结果通常才有速度信息。
//非 GNSS 定位时可能没有有效速度,默认值是 0.0f。
//可先用 location.hasSpeed() 判断是否包含速度信息。
//保存速度单位是米/秒(m/s)`
MMKVUtil.putFloat(MMKVKey.UserGpsSpeed, (location.speed / 3.6f))
}
mUserLatLng = LatLng(location.latitude, location.longitude)
locationSuccess(location)
}
}
mLocationClient!!.registerLocationListener(mLocationListener)
//开启定位
mLocationClient!!.start()
}
/** /**
* 设置方向感应器,百度地图使用 * 设置方向感应器,百度地图使用
*/ */
private fun initSensorEvent(context: Context) { private fun initSensorEvent(context: Context) {
if (mSensorManager != null) return
// 获得传感器管理器 // 获得传感器管理器
mSensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager mSensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
if (mSensorManager != null) { if (mSensorManager != null) {
@@ -784,16 +830,6 @@ abstract class BaseBaiduMapFragment :
mBaiduMap!!.setMyLocationData(myLocData) mBaiduMap!!.setMyLocationData(myLocData)
} }
/**
* 停止定位
*/
private fun stopLocation() {
mLocationClient?.apply {
unRegisterLocationListener(mLocationListener)
stop()
}
}
/** /**
* 根据轨迹获取地图缩放比例 * 根据轨迹获取地图缩放比例
*/ */
@@ -959,9 +995,6 @@ abstract class BaseBaiduMapFragment :
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
mSensorManager?.unregisterListener(mSensorEventListener) mSensorManager?.unregisterListener(mSensorEventListener)
mPetHeadIconBitmap.safeRecycle()
mPetHeadIconBitmap = null
stopLocation()
//在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理 //在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
mMapView.onDestroy() mMapView.onDestroy()
} }

View File

@@ -0,0 +1,32 @@
package com.abbidot.tracker.ui.fragment.map.baidumap
import android.content.Context
import androidx.fragment.app.Fragment
import com.abbidot.tracker.bean.WiFiZoneBean
import com.baidu.mapapi.map.BaiduMap
/**
* A simple [Fragment] subclass.
* Use the [EditWiFiZoneBaiduFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class EditWiFiZoneBaiduFragment : BaseBaiduMapFragment() {
private var mMapLoadOk: (() -> Unit)? = null
private var mWiFiZoneBean: WiFiZoneBean? = null
companion object {
@JvmStatic
fun newInstance(context: Context, wiFiZoneBean: WiFiZoneBean, mapLoadOk: () -> Unit) =
EditWiFiZoneBaiduFragment().apply {
mContext = context
mMapLoadOk = mapLoadOk
mWiFiZoneBean = wiFiZoneBean
}
}
override fun onMapLoadOk(baiduMap: BaiduMap) {
mMapLoadOk?.invoke()
}
}

View File

@@ -6,7 +6,6 @@ import android.view.MotionEvent
import android.view.View import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.abbidot.baselibrary.util.LogUtil import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.baselibrary.util.Utils
import com.abbidot.tracker.bean.FencesBean import com.abbidot.tracker.bean.FencesBean
import com.abbidot.tracker.constant.ConstantInt import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.ui.common.map.FencesAddEditMapCommon import com.abbidot.tracker.ui.common.map.FencesAddEditMapCommon
@@ -19,6 +18,7 @@ import com.baidu.location.BDLocation
import com.baidu.mapapi.map.BaiduMap import com.baidu.mapapi.map.BaiduMap
import com.baidu.mapapi.map.MapStatus import com.baidu.mapapi.map.MapStatus
import com.baidu.mapapi.model.LatLng import com.baidu.mapapi.model.LatLng
import kotlin.math.abs
import kotlin.math.pow import kotlin.math.pow
/** /**
@@ -37,6 +37,8 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
private lateinit var mMapLoadOk: () -> Unit private lateinit var mMapLoadOk: () -> Unit
private var isFirst = false
companion object { companion object {
@JvmStatic @JvmStatic
fun newInstance( fun newInstance(
@@ -66,7 +68,6 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
setOnMapLongClickListener { setOnMapLongClickListener {
resetFencesViewCentre(it) resetFencesViewCentre(it)
mapOkAndDistancePointLatLng(10)
} }
setOnMapGestureListener(object : BaiduMap.onMapGestureListener { setOnMapGestureListener(object : BaiduMap.onMapGestureListener {
@@ -85,35 +86,27 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
override fun onMapDoubleTouch(p0: Point?, p1: MapStatus?): Boolean { override fun onMapDoubleTouch(p0: Point?, p1: MapStatus?): Boolean {
//双击放大 //双击放大
LogUtil.e("onMapDoubleTouch") LogUtil.e("onMapDoubleTouch")
isRecoverFencesView = true
return false return false
} }
override fun onMapTwoClick(p0: Point?, p1: Point?, p2: MapStatus?): Boolean { override fun onMapTwoClick(p0: Point?, p1: Point?, p2: MapStatus?): Boolean {
//双指点击缩小 //双指点击缩小
LogUtil.e("onMapTwoClick") LogUtil.e("onMapTwoClick")
isRecoverFencesView = true
return false return false
} }
override fun onMapKneading(p0: Point?, p1: Point?, p2: MapStatus?): Boolean { override fun onMapKneading(p0: Point?, p1: Point?, p2: MapStatus?): Boolean {
LogUtil.e("onMapKneading") LogUtil.e("onMapKneading")
//监听地图放大缩小操作 recoverFencesView()
if (getBaiduMapZoom() != mapStatus.zoom) { isRecoverFencesView = true
setBaiduMapZoom(mapStatus.zoom)
resetFencesViewSize()
mFencesBean.let {
resetFencesViewCentre(
getBaiduMapLatLng(
it.latitudeCenter, it.longitudeCenter
)
)
}
}
return false return false
} }
override fun onMapOverLooking(p0: Point?, p1: Point?, p2: MapStatus?): Boolean { override fun onMapOverLooking(p0: Point?, p1: Point?, p2: MapStatus?): Boolean {
LogUtil.e("onMapOverLooking") LogUtil.e("onMapOverLooking")
isRecoverFencesView = true
return false return false
} }
@@ -127,16 +120,42 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
override fun onMapStatusChangeFinish(p0: MapStatus?) { override fun onMapStatusChangeFinish(p0: MapStatus?) {
LogUtil.e("onMapStatusChangeFinish") LogUtil.e("onMapStatusChangeFinish")
if (isRecoverFencesView) {
isRecoverFencesView = false
recoverFencesView()
}
} }
}) })
} }
startLocation()
//变量是否初始化 //变量是否初始化
if (::mMapLoadOk.isInitialized) mMapLoadOk() if (::mMapLoadOk.isInitialized) mMapLoadOk()
} }
private var isRecoverFencesView = false
/**
* 恢复围栏视图大小
*/
private fun recoverFencesView() {
mBaiduMap?.apply {
//监听地图放大缩小操作
if (getBaiduMapZoom() != mapStatus.zoom) {
setBaiduMapZoom(mapStatus.zoom)
resetFencesViewSize()
setScaleLimitDistance()
mFencesBean.let {
resetFencesViewCentre(
getBaiduMapLatLng(
it.latitudeCenter, it.longitudeCenter
)
)
}
}
}
}
override fun locationSuccess(location: BDLocation?) { override fun locationSuccess(location: BDLocation?) {
if (isEditFences) { if (isEditFences) {
mFencesBean.apply { mFencesBean.apply {
@@ -169,32 +188,48 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
* 地图准备好计算距离 * 地图准备好计算距离
*/ */
fun mapOkAndDistancePointLatLng(delayMillis: Long = 500) { fun mapOkAndDistancePointLatLng(delayMillis: Long = 500) {
if (mFencesBean.startDrag) return
//延时计算距离,防止围栏没画好/地图摄像头移动中
if (delayMillis == 0L) {
val arrayOfDistance = getLatLngAndCalDistance()
mOnActivityCallBack?.calculationDistance(arrayOfDistance)
} else {
//延时计算距离,防止围栏没画好/地图摄像头移动中 //延时计算距离,防止围栏没画好/地图摄像头移动中
mFencesCircleView.postDelayed({ mFencesCircleView.postDelayed({
val arrayOfDistance = getLatLngAndCalDistance() val arrayOfDistance = getLatLngAndCalDistance()
mOnActivityCallBack?.calculationDistance(arrayOfDistance) mOnActivityCallBack?.calculationDistance(arrayOfDistance)
if (!isFirst) {
isFirst = true
setScaleLimitDistance()
}
}, delayMillis) }, delayMillis)
} }
}
/** /**
* 还原围栏 * 还原围栏
*/ */
private fun restoreEditFences() { private fun restoreEditFences() {
var arrayOfDistance = arrayOf("0") var arrayOfDistance = arrayOf("0")
setScaleLimitDistance()
mFencesBean.apply { mFencesBean.apply {
when (mFencesBean.fenceShapeType) { when (mFencesBean.fenceShapeType) {
ConstantInt.CircleShapeType -> { ConstantInt.CircleShapeType -> {
val radiusPx = getCircleRadiusPx(radius.toDouble()) restoreCircleFences()
mFencesCircleView.let { val showDistance = Util.getShowDistance(radius)
it.visibility = View.VISIBLE arrayOfDistance = arrayOf("$radius", "$showDistance")
it.setCircleRadiusPx(radiusPx.toFloat())
arrayOfDistance = arrayOf("$radius")
}
} }
ConstantInt.RectangleShapeType -> { ConstantInt.RectangleShapeType -> {
restoreRectFences() restoreRectFences()
arrayOfDistance = arrayOf("$longDistance", "$shortDistance") val showWidthDistance = Util.getShowDistance(longDistance)
val showHeightDistance = Util.getShowDistance(shortDistance)
arrayOfDistance = arrayOf(
"$longDistance",
"$shortDistance",
"$showWidthDistance",
"$showHeightDistance"
)
} }
ConstantInt.PolygonShapeType -> { ConstantInt.PolygonShapeType -> {
@@ -212,15 +247,11 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
*/ */
fun resetFencesViewCentre(centreLatLng: LatLng) { fun resetFencesViewCentre(centreLatLng: LatLng) {
mBaiduMap?.projection?.toScreenLocation(centreLatLng)?.apply { mBaiduMap?.projection?.toScreenLocation(centreLatLng)?.apply {
if (mFencesCircleView.isVisible) {
mFencesCircleView.setCentreXY(this) mFencesCircleView.setCentreXY(this)
} else if (mFencesRectView.isVisible) {
mFencesRectView.setCentreXY(this) mFencesRectView.setCentreXY(this)
} else if (mFencesPolygonView.isVisible) {
mFencesPolygonView.setCentreXY(this) mFencesPolygonView.setCentreXY(this)
} }
} }
}
/** /**
* 重新设置围栏控件的大小 * 重新设置围栏控件的大小
@@ -228,8 +259,9 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
private fun resetFencesViewSize() { private fun resetFencesViewSize() {
if (mFencesCircleView.isVisible) { if (mFencesCircleView.isVisible) {
if (mFencesBean.radius <= 0.0) return if (mFencesBean.radius <= 0.0) return
val radiusPx = zoomToCircleRadiusPx(mFencesBean.radius.toDouble()) // val radiusPx = zoomToCircleRadiusPx(mFencesBean.radius.toDouble())
mFencesCircleView.setCircleRadiusPx(radiusPx.toFloat()) // mFencesCircleView.setCircleRadiusPx(radiusPx.toFloat())
restoreCircleFences()
} else if (mFencesRectView.isVisible) { } else if (mFencesRectView.isVisible) {
restoreRectFences() restoreRectFences()
} else if (mFencesPolygonView.isVisible) { } else if (mFencesPolygonView.isVisible) {
@@ -237,35 +269,85 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
} }
} }
/**
* 设置围栏最小可拖动距离
*/
private fun setScaleLimitDistance() {
mBaiduMap?.apply {
//假设取个离(100,100)x坐标100的点
var stepX: Int
var stepY: Int
//手机坐标点转换为经纬度
val centreLatLng = Point(100, 100).let {
stepX = it.x + 100
stepY = it.y
projection.fromScreenLocation(it)
}
val stepLatLng = projection.fromScreenLocation(Point(stepX, stepY))
val stepDistance = Util.measureLatLonDistance(
centreLatLng.latitude,
centreLatLng.longitude,
stepLatLng.latitude,
stepLatLng.longitude
)
//限制圆半径50m
val limitRadius = 100 / stepDistance * 50
//限制矩形边长100m
val limitSide = 100 / stepDistance * 100
LogUtil.e("scaleLimitDistance,$stepDistance,$limitRadius,$limitSide,${mapStatus.zoom}")
mFencesCircleView.mLimitRadius = limitRadius.toFloat()
mFencesRectView.mLimitSide = limitSide.toFloat()
mFencesPolygonView.mLimitSide = limitSide.toFloat()
}
}
/**
* 返回2种距离,第一个是设备使用真实距离,第二个是界面显示10的倍数距离
*/
private fun getLatLngAndCalDistance(): Array<String> { private fun getLatLngAndCalDistance(): Array<String> {
// 经纬度转换为手机坐标点 if (null == mBaiduMap) return arrayOf("0", "0")
// val x = mBaiduMap!!.projection.toScreenLocation(it).x
return when (mFencesBean.fenceShapeType) { return when (mFencesBean.fenceShapeType) {
ConstantInt.CircleShapeType -> { ConstantInt.CircleShapeType -> {
//手机坐标点转换为经纬度 //手机坐标点转换为经纬度
val centreLatLng = mFencesCircleView.getCircleCentrePoint() val centreLatLng = mFencesCircleView.getCircleCentrePoint()
.let { mBaiduMap!!.projection.fromScreenLocation(it) } .let { mBaiduMap!!.projection.fromScreenLocation(it) }
val startLatLng = mFencesCircleView.getCircleLineStartPoint()
.let { mBaiduMap!!.projection.fromScreenLocation(it) }
val endLatLng = mFencesCircleView.getCircleLineEndPoint() val endLatLng = mFencesCircleView.getCircleLineEndPoint()
.let { mBaiduMap!!.projection.fromScreenLocation(it) } .let { mBaiduMap!!.projection.fromScreenLocation(it) }
// mEndLatLng = endLatLng
LogUtil.e("mBaiduMap,getLatLngAndCalDistance 监听回调") LogUtil.e("mBaiduMap,getLatLngAndCalDistance 监听回调")
LogUtil.e("startLatLng=$centreLatLng,endLatLng=$endLatLng") // LogUtil.e("startLatLng=$centreLatLng,endLatLng=$endLatLng")
val distance = Util.measureLatLonDistance( val distance = Util.measureLatLonDistance(
centreLatLng.latitude, startLatLng.latitude,
centreLatLng.longitude, startLatLng.longitude,
endLatLng.latitude, endLatLng.latitude,
endLatLng.longitude endLatLng.longitude
) )
val distanceInt = distance.toInt()
val showDistance = Util.getShowDistance(distanceInt)
//把输出的GCJ02坐标转换为gps原生坐标WGS84 //把输出的GCJ02坐标转换为gps原生坐标WGS84
val gpsWGS84 = LonAndLatUtil.convertFromGCJ02ToWGS84(
centreLatLng.latitude, centreLatLng.longitude
)
mFencesBean.apply { mFencesBean.apply {
latitudeCenter = gpsWGS84[0] LonAndLatUtil.convertFromGCJ02ToWGS84(
longitudeCenter = gpsWGS84[1] centreLatLng.latitude, centreLatLng.longitude
).let {
latitudeCenter = it[0]
longitudeCenter = it[1]
}
LonAndLatUtil.convertFromGCJ02ToWGS84(
startLatLng.latitude, startLatLng.longitude
).let {
ancillaryOtherLatitude = it[0]
ancillaryOtherLongitude = it[1]
}
LonAndLatUtil.convertFromGCJ02ToWGS84(
endLatLng.latitude, endLatLng.longitude
).let {
ancillaryLatitude = it[0]
ancillaryLongitude = it[1]
}
} }
arrayOf( arrayOf(
Utils.formatDecimal(distance, 2) distanceInt.toString(), showDistance.toString()
) )
} }
@@ -296,39 +378,50 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
rectCLatLng.latitude, rectCLatLng.latitude,
rectCLatLng.longitude rectCLatLng.longitude
) )
val widthDistance = rectWidthDistance.toInt()
val showWidthDistance = Util.getShowDistance(widthDistance)
val heightDistance = rectHeightDistance.toInt()
val showHeightDistance = Util.getShowDistance(heightDistance)
//把输出的GCJ02坐标转换为gps原生坐标WGS84 //把输出的GCJ02坐标转换为gps原生坐标WGS84
val centreGpsWGS84 = LonAndLatUtil.convertFromGCJ02ToWGS84(
centreLatLng.latitude, centreLatLng.longitude
)
val rectAGpsWGS84 = LonAndLatUtil.convertFromGCJ02ToWGS84(
rectALatLng.latitude, rectALatLng.longitude
)
val rectBGpsWGS84 = LonAndLatUtil.convertFromGCJ02ToWGS84(
rectBLatLng.latitude, rectBLatLng.longitude
)
val rectCGpsWGS84 = LonAndLatUtil.convertFromGCJ02ToWGS84(
rectCLatLng.latitude, rectCLatLng.longitude
)
val rectDGpsWGS84 = LonAndLatUtil.convertFromGCJ02ToWGS84(
rectDLatLng.latitude, rectDLatLng.longitude
)
mFencesBean.apply { mFencesBean.apply {
latitudeCenter = centreGpsWGS84[0] LonAndLatUtil.convertFromGCJ02ToWGS84(
longitudeCenter = centreGpsWGS84[1] centreLatLng.latitude, centreLatLng.longitude
latitudeA = rectAGpsWGS84[0] ).let {
longitudeA = rectAGpsWGS84[1] latitudeCenter = it[0]
latitudeB = rectBGpsWGS84[0] longitudeCenter = it[1]
longitudeB = rectBGpsWGS84[1] }
latitudeC = rectCGpsWGS84[0] LonAndLatUtil.convertFromGCJ02ToWGS84(
longitudeC = rectCGpsWGS84[1] rectALatLng.latitude, rectALatLng.longitude
latitudeD = rectDGpsWGS84[0] ).let {
longitudeD = rectDGpsWGS84[1] latitudeA = it[0]
longitudeA = it[1]
}
LonAndLatUtil.convertFromGCJ02ToWGS84(
rectBLatLng.latitude, rectBLatLng.longitude
).let {
latitudeB = it[0]
longitudeB = it[1]
}
LonAndLatUtil.convertFromGCJ02ToWGS84(
rectCLatLng.latitude, rectCLatLng.longitude
).let {
latitudeC = it[0]
longitudeC = it[1]
}
LonAndLatUtil.convertFromGCJ02ToWGS84(
rectDLatLng.latitude, rectDLatLng.longitude
).let {
latitudeD = it[0]
longitudeD = it[1]
}
} }
//长度和高度 //长度和高度
arrayOf( arrayOf(
Utils.formatDecimal(rectWidthDistance, 2), widthDistance.toString(),
Utils.formatDecimal(rectHeightDistance, 2) heightDistance.toString(),
showWidthDistance.toString(),
showHeightDistance.toString()
) )
} }
@@ -404,10 +497,59 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
} }
} }
/**
* 还原圆形围栏
*/
private fun restoreCircleFences() {
if (null == mBaiduMap) return
mFencesBean.apply {
mFencesCircleView.let {
it.visibility = View.VISIBLE
val pointCentre = mBaiduMap!!.projection.toScreenLocation(
getBaiduMapLatLng(
latitudeCenter, longitudeCenter
)
)
val pointLineEnd = mBaiduMap!!.projection.toScreenLocation(
getBaiduMapLatLng(
ancillaryLatitude, ancillaryLongitude
)
)
val radius = abs(pointLineEnd.x - pointCentre.x).toFloat()
it.setCircleRadiusPx(radius)
//圆形大小变了,其他形状的围栏也要改变大小
val rectA = Point(
(pointLineEnd.x - radius * 2).toInt(), (pointLineEnd.y - radius).toInt()
)
val rectB = Point(pointLineEnd.x, (pointLineEnd.y - radius).toInt())
val rectC = Point(pointLineEnd.x, (pointLineEnd.y + radius).toInt())
val rectD =
Point((pointLineEnd.x - radius * 2).toInt(), (pointLineEnd.y + radius).toInt())
mFencesRectView.setRectABCDXYPoint(pointCentre, rectA, rectB, rectC, rectD)
val polygonA = Point(pointCentre.x, (pointCentre.y - radius).toInt())
val polygonB = Point(pointLineEnd.x, (pointLineEnd.y - radius / 2).toInt())
val polygonC = Point(pointLineEnd.x, (pointLineEnd.y + radius / 2).toInt())
val polygonD = Point(pointCentre.x, (pointCentre.y + radius).toInt())
val polygonE = Point(
(pointLineEnd.x - 2 * radius).toInt(), (pointLineEnd.y + radius / 2).toInt()
)
val polygonF = Point(
(pointLineEnd.x - 2 * radius).toInt(), (pointLineEnd.y - radius / 2).toInt()
)
mFencesPolygonView.setPolygonABCDEFPoint(
pointCentre, polygonA, polygonB, polygonC, polygonD, polygonE, polygonF
)
}
}
}
/** /**
* 还原矩形围栏大小 * 还原矩形围栏大小
*/ */
private fun restoreRectFences() { private fun restoreRectFences() {
if (null == mBaiduMap) return
mFencesBean.apply { mFencesBean.apply {
mFencesRectView.let { mFencesRectView.let {
it.visibility = View.VISIBLE it.visibility = View.VISIBLE
@@ -426,8 +568,25 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
val pointD = toScreenLocation( val pointD = toScreenLocation(
getBaiduMapLatLng(latitudeD, longitudeD) getBaiduMapLatLng(latitudeD, longitudeD)
) )
it.setRectABCDXYPoint( it.setRectABCDXYPoint(pointCentre, pointA, pointB, pointC, pointD)
pointCentre, pointA, pointB, pointC, pointD
//矩形大小变了,其他形状的围栏也要改变大小
val radius = abs(pointA.x - pointCentre.x).toFloat()
mFencesCircleView.setCircleRadiusPx(radius)
val minX = minOf(pointA.x, pointB.x, pointC.x, pointD.x)
val maxX = maxOf(pointA.x, pointB.x, pointC.x, pointD.x)
val minY = minOf(pointA.y, pointB.y, pointC.y, pointD.y)
val maxY = maxOf(pointA.y, pointB.y, pointC.y, pointD.y)
val difX = maxX - minX
val difY = maxY - minY
val polygonA = Point(minX + difX / 2, minY)
val polygonB = Point(maxX, minY + difY / 4)
val polygonC = Point(maxX, maxY - difY / 4)
val polygonD = Point(minX + difX / 2, maxY)
val polygonE = Point(minX, maxY - difY / 4)
val polygonF = Point(minX, minY + difY / 4)
mFencesPolygonView.setPolygonABCDEFPoint(
pointCentre, polygonA, polygonB, polygonC, polygonD, polygonE, polygonF
) )
} }
} }
@@ -438,6 +597,7 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
* 还原多边形围栏大小 * 还原多边形围栏大小
*/ */
private fun restorePolygonFences() { private fun restorePolygonFences() {
if (null == mBaiduMap) return
mFencesBean.apply { mFencesBean.apply {
mFencesPolygonView.let { mFencesPolygonView.let {
it.visibility = View.VISIBLE it.visibility = View.VISIBLE
@@ -465,6 +625,19 @@ class FencesAddEditBaiduMapFragment : BaseBaiduMapFragment() {
it.setPolygonABCDEFPoint( it.setPolygonABCDEFPoint(
pointCentre, pointA, pointB, pointC, pointD, pointE, pointF pointCentre, pointA, pointB, pointC, pointD, pointE, pointF
) )
val maxX = maxOf(pointA.x, pointB.x, pointC.x, pointD.x, pointE.x, pointF.x)
//多边形大小变了,其他形状的围栏也要改变大小
val radius = abs(maxX - pointCentre.x).toFloat()
mFencesCircleView.setCircleRadiusPx(radius)
val minX = minOf(pointA.x, pointB.x, pointC.x, pointD.x, pointE.x, pointF.x)
val minY = minOf(pointA.y, pointB.y, pointC.y, pointD.y, pointE.y, pointF.y)
val maxY = maxOf(pointA.y, pointB.y, pointC.y, pointD.y, pointE.y, pointF.y)
val rectA = Point(minX, minY)
val rectB = Point(maxX, minY)
val rectC = Point(maxX, maxY)
val rectD = Point(minX, maxY)
mFencesRectView.setRectABCDXYPoint(pointCentre, rectA, rectB, rectC, rectD)
} }
} }
} }

View File

@@ -75,7 +75,6 @@ class HistoryDataBaiduMapFragment : BaseBaiduMapFragment() {
} }
override fun onMapLoadOk(baiduMap: BaiduMap) { override fun onMapLoadOk(baiduMap: BaiduMap) {
//点击地图任意地方都不消失自定义头部地点布局
// startLocation(60, false) // startLocation(60, false)
baiduMap.apply { baiduMap.apply {
@@ -176,6 +175,7 @@ class HistoryDataBaiduMapFragment : BaseBaiduMapFragment() {
val zoom = getDistanceZoom(LatLng(minLat, minLon), LatLng(maxLat, maxLon)) val zoom = getDistanceZoom(LatLng(minLat, minLon), LatLng(maxLat, maxLon))
LogUtil.e("百度地图zoom==$zoom") LogUtil.e("百度地图zoom==$zoom")
setBaiduMapZoom(zoom + 1) setBaiduMapZoom(zoom + 1)
// setLatLngZoom(mContext!!, LatLng(minLat, minLon), LatLng(maxLat, maxLon))
val maxIndex = data.size - 1 val maxIndex = data.size - 1
mCurLatLng = mLatLngList[maxIndex] mCurLatLng = mLatLngList[maxIndex]
@@ -321,14 +321,15 @@ class HistoryDataBaiduMapFragment : BaseBaiduMapFragment() {
* 设置宠物Marker经纬度 * 设置宠物Marker经纬度
*/ */
fun setPetMarkerLatLng(latLng: LatLng) { fun setPetMarkerLatLng(latLng: LatLng) {
mBaiduMap?.apply { mBaiduMap?.let { baidu ->
//显示最上面,层级最高,默认值 0f
mMarkerOptions?.let { mMarkerOptions?.let {
it.position(latLng) it.position(latLng)
mMarker?.remove() mMarker?.remove()
mMarker = addOverlay(it) mMarker = baidu.addOverlay(it).apply {
//显示最上面,层级最高,默认值 0f
zIndex = 99
}
} }
// setUserMarker()
} }
} }
} }

View File

@@ -152,7 +152,6 @@ class HomeMapBaiduMapFragment : BaseBaiduMapFragment() {
} }
override fun onMapLoadOk(baiduMap: BaiduMap) { override fun onMapLoadOk(baiduMap: BaiduMap) {
startLocation(60, false)
mBaiduMap?.apply { mBaiduMap?.apply {
setOnMarkerClickListener { marker -> setOnMarkerClickListener { marker ->

View File

@@ -23,7 +23,6 @@ class PreviewFencesBaiduMapFragment : BaseBaiduMapFragment() {
} }
override fun onMapLoadOk(baiduMap: BaiduMap) { override fun onMapLoadOk(baiduMap: BaiduMap) {
startLocation()
//变量是否初始化 //变量是否初始化
if (::mMapLoadOk.isInitialized) mMapLoadOk() if (::mMapLoadOk.isInitialized) mMapLoadOk()
} }

View File

@@ -0,0 +1,182 @@
package com.abbidot.tracker.ui.fragment.map.baidumap
import android.content.Context
import android.graphics.Point
import android.view.MotionEvent
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.tracker.R
import com.abbidot.tracker.bean.HistoryDataBean
import com.abbidot.tracker.util.LonAndLatUtil
import com.abbidot.tracker.vm.GeoCoderViewModel
import com.baidu.location.BDLocation
import com.baidu.mapapi.map.BaiduMap
import com.baidu.mapapi.map.MapStatus
import com.baidu.mapapi.map.MarkerOptions
import com.baidu.mapapi.model.LatLng
/**
* A simple [Fragment] subclass.
* Use the [WiFiZoneBaiduMapFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class WiFiZoneBaiduMapFragment : BaseBaiduMapFragment() {
private val mGeoCoderViewModel: GeoCoderViewModel by viewModels()
//wifi zone当前位置信息 //保存地理信息,方便传参给其他页面
var mDecWifiAddressData: HistoryDataBean? = null
private var mMarkerOptions: MarkerOptions? = null
companion object {
@JvmStatic
fun newInstance(context: Context) = WiFiZoneBaiduMapFragment().apply {
mContext = context
}
}
override fun onMapLoadOk(baiduMap: BaiduMap) {
mDecWifiAddressData = HistoryDataBean()
baiduMap.apply {
//是否双击放大当前地图中心点 默认:false 即按照双击位置放大地图
uiSettings.setEnlargeCenterWithDoubleClickEnable(true)
setOnMapStatusChangeListener(object : BaiduMap.OnMapStatusChangeListener {
override fun onMapStatusChangeStart(p0: MapStatus?) {
LogUtil.e("onMapStatusChangeStart")
mBaiduMap?.hideInfoWindow()
}
override fun onMapStatusChangeStart(p: MapStatus?, p1: Int) {
p?.let {
getCameraCenterLatLng()
}
}
override fun onMapStatusChange(p: MapStatus?) {
LogUtil.e("onMapStatusChange")
p?.let {
getCameraCenterLatLng()
}
}
override fun onMapStatusChangeFinish(p: MapStatus?) {
LogUtil.e("setOnMapStatusChangeListener,onMapStatusChangeFinish")
p?.let {
getCameraCenterLatLng(true)
}
}
})
setOnMapGestureListener(object : BaiduMap.onMapGestureListener {
override fun onMapScroll(p0: Point?, p1: Point?, p: MapStatus?): Boolean {
//平移
p?.let {
getCameraCenterLatLng()
}
return false
}
override fun onMapDoubleTouch(p0: Point?, p: MapStatus?): Boolean {
//双击放大
LogUtil.e("onMapDoubleTouch")
p?.let {
getCameraCenterLatLng()
}
return false
}
override fun onMapTwoClick(p0: Point?, p1: Point?, p: MapStatus?): Boolean {
//双指点击缩小
LogUtil.e("onMapTwoClick")
p?.let {
getCameraCenterLatLng()
}
return false
}
override fun onMapKneading(p0: Point?, p1: Point?, p: MapStatus?): Boolean {
LogUtil.e("onMapKneading")
// p?.let {
// getCameraCenterLatLng()
// }
return false
}
override fun onMapOverLooking(p0: Point?, p1: Point?, p2: MapStatus?): Boolean {
LogUtil.e("onMapOverLooking")
return false
}
override fun onMapFling(
p0: MotionEvent?, p1: Float, p2: Float, p3: MapStatus?
): Boolean {
//惯性抛出手势
LogUtil.e("onMapFling1")
return false
}
override fun onMapStatusChangeFinish(p: MapStatus?) {
LogUtil.e("onMapStatusChangeFinish")
}
})
}
}
override fun liveDataObserve() {
//反地理编码成功返回
mGeoCoderViewModel.mLatLonAddressLiveData.observe(viewLifecycleOwner) {
mDecWifiAddressData?.let { history ->
//更新位置时间
// history.dayTime = timeString
//详细位置
history.address = it
//传递位置信息给InfoWindowAdapter窗口
mMarkerOptions?.let { m ->
showMarkerInfoWindow(history, -m.icon.bitmap.height - AppUtils.dpToPx(2))
}
}
}
}
private fun getCameraCenterLatLng(isNeedGeoCoder: Boolean = false) {
mBaiduMap?.apply {
//地图操作中心点在屏幕中的坐标
val latLng = mapStatus.target
mMarker?.remove()
mMarkerOptions?.let {
it.position(latLng)
mMarker = addOverlay(it)
}
if (isNeedGeoCoder) {
val gpsLatLng =
LonAndLatUtil.convertFromGCJ02ToWGS84(latLng.latitude, latLng.longitude)
geoCoderLatLon(gpsLatLng[0], gpsLatLng[1])
}
}
}
private fun geoCoderLatLon(latitude: Double, longitude: Double) {
mDecWifiAddressData?.apply {
this.latitude = latitude
this.longitude = longitude
}
mGeoCoderViewModel.getLatLonAddress(latitude, longitude, false)
}
override fun locationSuccess(location: BDLocation?) {
location?.apply {
moveCameraLocation(LatLng(latitude, longitude))
val gpsLatLng = LonAndLatUtil.convertFromGCJ02ToWGS84(latitude, longitude)
if (null == mMarker) {
mMarkerOptions = getMarkerOptions(
gpsLatLng[0], gpsLatLng[1], R.drawable.icon_location_svg
)
mMarker = mBaiduMap?.addOverlay(mMarkerOptions)
} else mMarker?.remove()
geoCoderLatLon(gpsLatLng[0], gpsLatLng[1])
}
}
}

View File

@@ -1,10 +1,8 @@
package com.abbidot.tracker.ui.fragment.map.googlemap package com.abbidot.tracker.ui.fragment.map.googlemap
import android.Manifest import android.Manifest
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Point import android.graphics.Point
import android.location.Location import android.location.Location
import android.os.Bundle import android.os.Bundle
@@ -14,7 +12,9 @@ import android.view.ViewGroup
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.abbidot.baselibrary.constant.EventName
import com.abbidot.baselibrary.constant.MMKVKey import com.abbidot.baselibrary.constant.MMKVKey
import com.abbidot.baselibrary.eventbus.XEventBus
import com.abbidot.baselibrary.util.AppUtils import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.baselibrary.util.LogUtil import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.baselibrary.util.MMKVUtil import com.abbidot.baselibrary.util.MMKVUtil
@@ -28,13 +28,9 @@ import com.abbidot.tracker.databinding.FragmentGoogleMapBinding
import com.abbidot.tracker.util.ImageUtil import com.abbidot.tracker.util.ImageUtil
import com.abbidot.tracker.util.LonAndLatUtil import com.abbidot.tracker.util.LonAndLatUtil
import com.abbidot.tracker.util.Util import com.abbidot.tracker.util.Util
import com.abbidot.tracker.util.Util.Companion.safeRecycle
import com.abbidot.tracker.util.ViewUtil import com.abbidot.tracker.util.ViewUtil
import com.abbidot.tracker.widget.MapDeviceNetView import com.abbidot.tracker.widget.MapDeviceNetView
import com.abbidot.tracker.widget.MapMarkerInfoView import com.abbidot.tracker.widget.MapMarkerInfoView
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.Priority
import com.google.android.gms.maps.CameraUpdate import com.google.android.gms.maps.CameraUpdate
import com.google.android.gms.maps.CameraUpdateFactory import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap import com.google.android.gms.maps.GoogleMap
@@ -59,8 +55,6 @@ import com.google.android.gms.maps.model.PolygonOptions
import com.google.android.gms.maps.model.Polyline import com.google.android.gms.maps.model.Polyline
import com.google.android.gms.maps.model.PolylineOptions import com.google.android.gms.maps.model.PolylineOptions
import com.google.android.gms.maps.model.RoundCap import com.google.android.gms.maps.model.RoundCap
import com.google.android.gms.tasks.CancellationTokenSource
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
@@ -97,9 +91,6 @@ abstract class BaseGoogleMapFragment :
//自定显示用户地点信息图层 //自定显示用户地点信息图层
private var mUserMarker: Marker? = null private var mUserMarker: Marker? = null
//宠物大头针设置自定义头像
private var mPetHeadIconBitmap: Bitmap? = null
private var mMarkerInfoWindowAdapter: MarkerInfoWindowAdapter? = null private var mMarkerInfoWindowAdapter: MarkerInfoWindowAdapter? = null
//宠物头像地址 //宠物头像地址
@@ -135,7 +126,7 @@ abstract class BaseGoogleMapFragment :
//指定地图的初始照相机位置(指定 null 以使用 默认摄像机位置) //指定地图的初始照相机位置(指定 null 以使用 默认摄像机位置)
val options = GoogleMapOptions().apply { val options = GoogleMapOptions().apply {
// val options = GoogleMapOptions().liteMode(true) // val options = GoogleMapOptions().liteMode(true)
//默认华盛顿经纬度 //没有宠物位置,默认华盛顿经纬度
val lat = MMKVUtil.getDouble(MMKVKey.MapShowDefaultLat, 38.913611) val lat = MMKVUtil.getDouble(MMKVKey.MapShowDefaultLat, 38.913611)
val lon = MMKVUtil.getDouble(MMKVKey.MapShowDefaultLon, -77.013222) val lon = MMKVUtil.getDouble(MMKVKey.MapShowDefaultLon, -77.013222)
//不使用地图摄像头移动动画,默认级别一样大 //不使用地图摄像头移动动画,默认级别一样大
@@ -184,6 +175,68 @@ abstract class BaseGoogleMapFragment :
mGoogleMapView?.onSaveInstanceState(mapViewBundle) mGoogleMapView?.onSaveInstanceState(mapViewBundle)
} }
override fun onMapReady(googleMap: GoogleMap) {
LogUtil.e("谷歌地图加载好了")
mGoogleMap = googleMap
isMapLoadOk = true
// googleMap.uiSettings.apply {
// //右下角工具栏不显示
// isMapToolbarEnabled = true
// //指南针
// isCompassEnabled = true
// //定位按钮
// isMyLocationButtonEnabled = true
// }
//地图样式
setGoogleMapType()
googleMap.apply {
//显示实时交通信息
// isTrafficEnabled = true
//检测权限,开启用户的当前位置https://developers.google.cn/maps/documentation/android-sdk/location?hl=zh-cn
if (ActivityCompat.checkSelfPermission(
mContext!!, Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
mContext!!, Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
//启用“我的位置”图层。
isMyLocationEnabled = true
}
uiSettings.let {
//禁止显示“我的位置”按钮。
it.isMyLocationButtonEnabled = false
//用于设置是启用还是停用倾斜手势的偏好设置。
// https://developers.google.cn/maps/documentation/android-sdk/reference/com/google/android/libraries/maps/UiSettings?hl=zh-cn
it.isMapToolbarEnabled = false
it.isTiltGesturesEnabled = false
it.isCompassEnabled = true
}
XEventBus.observe(viewLifecycleOwner, EventName.LocationData) { loc: Location ->
setUserLocationData(loc.latitude, loc.longitude)
locationSuccess(loc)
}
val userGpsLat = MMKVUtil.getDouble(MMKVKey.UserGpsLat)
val userGpsLon = MMKVUtil.getDouble(MMKVKey.UserGpsLon)
if (userGpsLat != 0.0 || userGpsLon != 0.0) {
setUserLocationData(userGpsLat, userGpsLon)
}
onMapLoadOk(googleMap)
}
}
private fun setUserLocationData(lat: Double, lon: Double) {
mUserLatLng = LatLng(lat, lon)
setUserMarker()
}
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
mGoogleMapView?.onPause() mGoogleMapView?.onPause()
@@ -307,8 +360,6 @@ abstract class BaseGoogleMapFragment :
fun switchShowLocation(@ConstantInt type: Int) { fun switchShowLocation(@ConstantInt type: Int) {
when (type) { when (type) {
ConstantInt.PetLocationType -> { ConstantInt.PetLocationType -> {
//刷新下用户当前的位置
getLastLocation()
mPetLatLng?.let { mPetLatLng?.let {
mGoogleMapZoom = 17f mGoogleMapZoom = 17f
refreshPetCurrentLocation(it, true) refreshPetCurrentLocation(it, true)
@@ -370,8 +421,6 @@ abstract class BaseGoogleMapFragment :
fun setPetHeadIconUrl(petHeadUrl: String, petType: Int) { fun setPetHeadIconUrl(petHeadUrl: String, petType: Int) {
mPetHeadUrl = petHeadUrl mPetHeadUrl = petHeadUrl
mPetType = petType mPetType = petType
mPetHeadIconBitmap.safeRecycle()
mPetHeadIconBitmap = null
} }
fun latLngToScreenLocation(latLng: LatLng): Point { fun latLngToScreenLocation(latLng: LatLng): Point {
@@ -946,136 +995,6 @@ abstract class BaseGoogleMapFragment :
// LogUtil.e("点的个数:${mBlackPolyline?.points?.size},${mYellowPolyline?.points?.size}") // LogUtil.e("点的个数:${mBlackPolyline?.points?.size},${mYellowPolyline?.points?.size}")
// } // }
override fun onMapReady(googleMap: GoogleMap) {
LogUtil.e("谷歌地图加载好了")
mGoogleMap = googleMap
isMapLoadOk = true
// googleMap.uiSettings.apply {
// //右下角工具栏不显示
// isMapToolbarEnabled = true
// //指南针
// isCompassEnabled = true
// //定位按钮
// isMyLocationButtonEnabled = true
// }
//地图样式
setGoogleMapType()
googleMap.apply {
//显示实时交通信息
// isTrafficEnabled = true
//检测权限,开启用户的当前位置https://developers.google.cn/maps/documentation/android-sdk/location?hl=zh-cn
if (ActivityCompat.checkSelfPermission(
mContext!!, Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
mContext!!, Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
//启用“我的位置”图层。
isMyLocationEnabled = true
}
uiSettings.let {
//禁止显示“我的位置”按钮。
it.isMyLocationButtonEnabled = false
//用于设置是启用还是停用倾斜手势的偏好设置。
// https://developers.google.cn/maps/documentation/android-sdk/reference/com/google/android/libraries/maps/UiSettings?hl=zh-cn
it.isMapToolbarEnabled = false
it.isTiltGesturesEnabled = false
it.isCompassEnabled = true
}
onMapLoadOk(googleMap)
}
}
//*************************定位代码start****************************************
// The Fused Location Provider provides access to location APIs.
private val mFusedLocationClient: FusedLocationProviderClient by lazy {
LocationServices.getFusedLocationProviderClient(mContext!!)
}
private var mCancellationTokenSource: CancellationTokenSource? = null
/**
* 获取最后位置,用户当前的位置
*/
@SuppressLint("MissingPermission")
fun getLastLocation() {
mFusedLocationClient.lastLocation.addOnCompleteListener { taskLocation ->
var location: Location? = null
if (taskLocation.isSuccessful && taskLocation.result != null) {
location = taskLocation.result
LonAndLatUtil.currentUserGPSLat = location.latitude
LonAndLatUtil.currentUserGPSLon = location.longitude
LogUtil.e("getLastLocation:${location.latitude}, ${location.longitude}")
} else {
LogUtil.e("getLastLocation:exception" + taskLocation.exception)
}
if (null != location) {
setUserLatLng(location)
if (isLocationSuccessCallback) {
setUserMarker()
locationSuccess(location)
}
isLocationSuccessCallback = false
} else requestCurrentLocation()
}
}
/**
* 请求用户当前的位置
*/
@SuppressLint("MissingPermission")
fun requestCurrentLocation() {
try {
if (null == mCancellationTokenSource) mCancellationTokenSource =
CancellationTokenSource()
// val currentLocationTask = mFusedLocationClient.getCurrentLocation(
// LocationRequest.PRIORITY_HIGH_ACCURACY, mCancellationTokenSource!!.token
// )
val currentLocationTask = mFusedLocationClient.getCurrentLocation(
Priority.PRIORITY_HIGH_ACCURACY, mCancellationTokenSource!!.token
)
currentLocationTask.addOnCompleteListener { task: Task<Location> ->
var location: Location? = null
val result = if (task.isSuccessful && task.result != null) {
location = task.result
LonAndLatUtil.currentUserGPSLat = location.latitude
LonAndLatUtil.currentUserGPSLon = location.longitude
"(success): ${location.latitude}, ${location.longitude}"
} else {
val exception = task.exception
"(failure): $exception"
}
LogUtil.e("requestCurrentLocation $result")
if (null != location) {
setUserLatLng(location)
if (isLocationSuccessCallback) locationSuccess(location)
isLocationSuccessCallback = false
}
}
} catch (e: Exception) {
LogUtil.e("requestCurrentLocation异常:${e.message}")
}
}
private fun setUserLatLng(location: Location) {
location.apply {
MMKVUtil.putDouble(MMKVKey.UserGpsLat, latitude)
MMKVUtil.putDouble(MMKVKey.UserGpsLon, longitude)
//单位是米/秒(m/s)
MMKVUtil.putFloat(MMKVKey.UserGpsSpeed, speed)
mUserLatLng = LatLng(latitude, longitude)
}
}
//*************************定位代码end****************************************
/** /**
* 由 points 组成的区域 距离手机屏幕距离screenPaddingPx 像素单位 * 由 points 组成的区域 距离手机屏幕距离screenPaddingPx 像素单位
@@ -1267,124 +1186,12 @@ abstract class BaseGoogleMapFragment :
override fun onStop() { override fun onStop() {
super.onStop() super.onStop()
mCancellationTokenSource?.cancel()
mGoogleMapView?.onStop() mGoogleMapView?.onStop()
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
mPetHeadIconBitmap.safeRecycle()
mPetHeadIconBitmap = null
mGoogleMapView?.onDestroy() mGoogleMapView?.onDestroy()
} }
// /**
// * 两点间距离 单位米
// */
// private fun distanceBetween(p1: LatLng, p2: LatLng): Double {
// val r = 6371000.0
// val lat1 = p1.latitude * PI / 180
// val lng1 = p1.longitude * PI / 180
// val lat2 = p2.latitude * PI / 180
// val lng2 = p2.longitude * 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<LatLng>, epsilon: Double = 1.0): List<LatLng> {
// 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(points[i], start, 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: LatLng, a: LatLng, b: LatLng): 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(p, a)
//
// val len2 = (bx - ax).pow(2) + (by - ay).pow(2)
// if (cross >= len2) return distanceBetween(p, b)
//
// val t = cross / len2
// val nearX = ax + t * (bx - ax)
// val nearY = ay + t * (by - ay)
// return distanceBetween(p, LatLng(nearY, nearX))
// }
//
// /**
// * 相邻两点插值补点,让线条更顺滑
// * @param step 插值个数 推荐2~3
// */
// private fun latLngInterpolate(points: List<LatLng>, step: Int = 2): List<LatLng> {
// if (points.size < 2) return points
// val result = mutableListOf<LatLng>()
// 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(LatLng(lat, lng))
// }
// }
// result.add(points.last())
// return result
// }
//
// /**
// * GPS降噪,过滤跳点漂移
// */
// private fun filterNoisePoint(
// points: List<LatLng>, minDis: Double = 5.0, maxDis: Double = 60.0
// ): List<LatLng> {
// if (points.isEmpty()) return emptyList()
// val res = mutableListOf<LatLng>().apply { add(points.first()) }
// for (i in 1 until points.size) {
// val last = res.last()
// val dis = distanceBetween(last, points[i])
// if (dis in minDis..maxDis) {
// res.add(points[i])
// }
// }
// return res
// }
} }

View File

@@ -1,22 +1,17 @@
package com.abbidot.tracker.ui.fragment.map.googlemap package com.abbidot.tracker.ui.fragment.map.googlemap
import android.content.Context import android.content.Context
import androidx.fragment.app.viewModels
import com.abbidot.tracker.bean.WiFiZoneBean import com.abbidot.tracker.bean.WiFiZoneBean
import com.abbidot.tracker.vm.GeoCoderViewModel
import com.google.android.gms.maps.GoogleMap import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.Marker
/** /**
*Created by .yzq on 2024/6/4/004. *Created by .yzq on 2024/6/4/004.
* @link * @link
* @description: * @description: 编辑WiFi区域地图
*/ * */
class EditWiFiZoneGoogleMapFragment( class EditWiFiZoneGoogleMapFragment() : BaseGoogleMapFragment() {
) : BaseGoogleMapFragment() { // private val mGeoCoderViewModel: GeoCoderViewModel by viewModels()
private val mGeoCoderViewModel: GeoCoderViewModel by viewModels()
private lateinit var mMapLoadOk: () -> Unit private lateinit var mMapLoadOk: () -> Unit
private lateinit var mWiFiZoneBean: WiFiZoneBean private lateinit var mWiFiZoneBean: WiFiZoneBean
@@ -33,34 +28,33 @@ class EditWiFiZoneGoogleMapFragment(
override fun onMapLoadOk(googleMap: GoogleMap) { override fun onMapLoadOk(googleMap: GoogleMap) {
googleMap.setOnMarkerDragListener(object : GoogleMap.OnMarkerDragListener { // googleMap.setOnMarkerDragListener(object : GoogleMap.OnMarkerDragListener {
override fun onMarkerDrag(marker: Marker) { // override fun onMarkerDrag(marker: Marker) {
//
// }
//
// override fun onMarkerDragEnd(marker: Marker) {
// marker.position.let {
// mGeoCoderViewModel.getLatLonAddress(it.latitude, it.longitude, false)
// mWiFiZoneBean.latitude = it.latitude
// mWiFiZoneBean.longitude = it.longitude
// }
// }
//
// override fun onMarkerDragStart(marker: Marker) {
//
// }
// })
}
override fun onMarkerDragEnd(marker: Marker) {
marker.position.let {
mGeoCoderViewModel.getLatLonAddress(it.latitude, it.longitude, false)
mWiFiZoneBean.latitude = it.latitude
mWiFiZoneBean.longitude = it.longitude
}
}
override fun onMarkerDragStart(marker: Marker) {
}
})
getLastLocation()
//变量是否初始化 //变量是否初始化
if (::mMapLoadOk.isInitialized) mMapLoadOk() if (::mMapLoadOk.isInitialized) mMapLoadOk()
} }
override fun liveDataObserve() { // override fun liveDataObserve() {
mGeoCoderViewModel.mLatLonAddressLiveData.observe(viewLifecycleOwner) { // mGeoCoderViewModel.mLatLonAddressLiveData.observe(viewLifecycleOwner) {
mWiFiZoneBean.address = it // mWiFiZoneBean.address = it
} // }
} // }
} }

View File

@@ -100,7 +100,6 @@ class FencesAddEditGoogleMapFragment : BaseGoogleMapFragment() {
} }
} }
getLastLocation()
//变量是否初始化 //变量是否初始化
if (::mMapLoadOk.isInitialized) mMapLoadOk() if (::mMapLoadOk.isInitialized) mMapLoadOk()
@@ -197,13 +196,16 @@ class FencesAddEditGoogleMapFragment : BaseGoogleMapFragment() {
val limitRadius = 100 / stepDistance * 50 val limitRadius = 100 / stepDistance * 50
//限制矩形边长100m //限制矩形边长100m
val limitSide = 100 / stepDistance * 100 val limitSide = 100 / stepDistance * 100
LogUtil.e("setScaleLimitDistance,$stepDistance,$limitRadius,$limitSide,${cameraPosition.zoom}") LogUtil.e("ScaleLimitDistance,$stepDistance,$limitRadius,$limitSide,${cameraPosition.zoom}")
mFencesCircleView.mLimitRadius = limitRadius.toFloat() mFencesCircleView.mLimitRadius = limitRadius.toFloat()
mFencesRectView.mLimitSide = limitSide.toFloat() mFencesRectView.mLimitSide = limitSide.toFloat()
mFencesPolygonView.mLimitSide = limitSide.toFloat() mFencesPolygonView.mLimitSide = limitSide.toFloat()
} }
} }
/**
* 返回2种距离,第一个是设备使用真实距离,第二个是界面显示10的倍数距离
*/
private fun getLatLngAndCalDistance(): Array<String> { private fun getLatLngAndCalDistance(): Array<String> {
if (null == mGoogleMap) return arrayOf("0", "0") if (null == mGoogleMap) return arrayOf("0", "0")
@@ -227,7 +229,7 @@ class FencesAddEditGoogleMapFragment : BaseGoogleMapFragment() {
endLatLng.longitude endLatLng.longitude
) )
val distanceInt = distance.toInt() val distanceInt = distance.toInt()
val showDistance = getShowDistance(distanceInt) val showDistance = Util.getShowDistance(distanceInt)
LogUtil.e("getLatLngAndCalDistance,$distanceInt,$showDistance") LogUtil.e("getLatLngAndCalDistance,$distanceInt,$showDistance")
mFencesBean.apply { mFencesBean.apply {
toGpsLatLon(centreLatLng).let { toGpsLatLon(centreLatLng).let {
@@ -276,9 +278,9 @@ class FencesAddEditGoogleMapFragment : BaseGoogleMapFragment() {
rectCLatLng.longitude rectCLatLng.longitude
) )
val widthDistance = rectWidthDistance.toInt() val widthDistance = rectWidthDistance.toInt()
val showWidthDistance = getShowDistance(widthDistance) val showWidthDistance = Util.getShowDistance(widthDistance)
val heightDistance = rectHeightDistance.toInt() val heightDistance = rectHeightDistance.toInt()
val showHeightDistance = getShowDistance(heightDistance) val showHeightDistance = Util.getShowDistance(heightDistance)
mFencesBean.apply { mFencesBean.apply {
toGpsLatLon(centreLatLng).let { toGpsLatLon(centreLatLng).let {
latitudeCenter = it.latitude latitudeCenter = it.latitude
@@ -374,16 +376,6 @@ class FencesAddEditGoogleMapFragment : BaseGoogleMapFragment() {
} }
} }
/**
* 获取ui显示的距离,经过算法处理的
*/
private fun getShowDistance(distance: Int): Int {
val singleDigit = distance % 10
val integerDigit = distance / 10 * 10
return if (singleDigit > 4) integerDigit + 10
else integerDigit
}
/** /**
* 还原围栏 * 还原围栏
*/ */
@@ -394,14 +386,14 @@ class FencesAddEditGoogleMapFragment : BaseGoogleMapFragment() {
when (mFencesBean.fenceShapeType) { when (mFencesBean.fenceShapeType) {
ConstantInt.CircleShapeType -> { ConstantInt.CircleShapeType -> {
restoreCircleFences() restoreCircleFences()
val showDistance = getShowDistance(radius) val showDistance = Util.getShowDistance(radius)
arrayOfDistance = arrayOf("$radius", "$showDistance") arrayOfDistance = arrayOf("$radius", "$showDistance")
} }
ConstantInt.RectangleShapeType -> { ConstantInt.RectangleShapeType -> {
restoreRectFences() restoreRectFences()
val showWidthDistance = getShowDistance(longDistance) val showWidthDistance = Util.getShowDistance(longDistance)
val showHeightDistance = getShowDistance(shortDistance) val showHeightDistance = Util.getShowDistance(shortDistance)
arrayOfDistance = arrayOf( arrayOfDistance = arrayOf(
"$longDistance", "$longDistance",
"$shortDistance", "$shortDistance",

View File

@@ -114,8 +114,6 @@ class HistoryDataGoogleMapFragment : BaseGoogleMapFragment() {
} }
} }
getLastLocation()
//变量是否初始化 //变量是否初始化
if (::mMapLoadOk.isInitialized) mMapLoadOk() if (::mMapLoadOk.isInitialized) mMapLoadOk()
} }

View File

@@ -181,7 +181,6 @@ class HomeMapGoogleMapFragmentV3 : BaseGoogleMapFragment() {
return false return false
} }
}) })
getLastLocation()
} }
//变量是否初始化 //变量是否初始化

View File

@@ -60,12 +60,15 @@ class MarkerInfoWindowAdapter(context: Context) : GoogleMap.InfoWindowAdapter {
LogUtil.d("$tag-----------") LogUtil.d("$tag-----------")
if (null == tag) return if (null == tag) return
if (TextUtils.isEmpty(tag.dayTime)) { locationUpdateTextView.visibility = if (TextUtils.isEmpty(tag.dayTime)) View.GONE
locationUpdateTextView.visibility = View.GONE else {
} else {
locationUpdateTextView.visibility = View.VISIBLE
locationUpdateTextView.text = tag.dayTime locationUpdateTextView.text = tag.dayTime
View.VISIBLE
} }
locationTextView.visibility = if (TextUtils.isEmpty(tag.address)) View.GONE
else {
locationTextView.text = tag.address locationTextView.text = tag.address
View.VISIBLE
}
} }
} }

View File

@@ -23,7 +23,6 @@ class PreviewFencesGoogleMapFragment : BaseGoogleMapFragment() {
} }
override fun onMapLoadOk(googleMap: GoogleMap) { override fun onMapLoadOk(googleMap: GoogleMap) {
getLastLocation()
//变量是否初始化 //变量是否初始化
if (::mMapLoadOk.isInitialized) mMapLoadOk() if (::mMapLoadOk.isInitialized) mMapLoadOk()
} }

View File

@@ -3,8 +3,11 @@ package com.abbidot.tracker.ui.fragment.map.googlemap
import android.content.Context import android.content.Context
import android.location.Location import android.location.Location
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import com.abbidot.baselibrary.constant.MMKVKey
import com.abbidot.baselibrary.util.MMKVUtil
import com.abbidot.tracker.R import com.abbidot.tracker.R
import com.abbidot.tracker.bean.HistoryDataBean import com.abbidot.tracker.bean.HistoryDataBean
import com.abbidot.tracker.util.LonAndLatUtil
import com.abbidot.tracker.vm.GeoCoderViewModel import com.abbidot.tracker.vm.GeoCoderViewModel
import com.google.android.gms.maps.GoogleMap import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.LatLng
@@ -20,11 +23,13 @@ class WiFiZone2GoogleMapFragment : BaseGoogleMapFragment() {
//wifi zone当前位置信息 //保存地理信息,方便传参给其他页面 //wifi zone当前位置信息 //保存地理信息,方便传参给其他页面
var mDecWifiAddressData: HistoryDataBean? = null var mDecWifiAddressData: HistoryDataBean? = null
private var isFirstBind = false
companion object { companion object {
@JvmStatic @JvmStatic
fun newInstance(context: Context) = WiFiZone2GoogleMapFragment().apply { fun newInstance(context: Context, firstBind: Boolean) = WiFiZone2GoogleMapFragment().apply {
mContext = context mContext = context
isFirstBind = firstBind
} }
} }
@@ -67,7 +72,6 @@ class WiFiZone2GoogleMapFragment : BaseGoogleMapFragment() {
mMarker?.showInfoWindow() mMarker?.showInfoWindow()
} }
} }
getLastLocation()
} }
override fun liveDataObserve() { override fun liveDataObserve() {
@@ -106,6 +110,11 @@ class WiFiZone2GoogleMapFragment : BaseGoogleMapFragment() {
override fun locationSuccess(location: Location?) { override fun locationSuccess(location: Location?) {
location?.apply { location?.apply {
//首次添加设备,需要判断是否超出中国边界
if (isFirstBind) {
val isOutOfChina = LonAndLatUtil.isLocationOutOfChina(latitude, longitude)
MMKVUtil.putBoolean(MMKVKey.isGpsToGCJ02, !isOutOfChina)
}
val latLng = LatLng(latitude, longitude) val latLng = LatLng(latitude, longitude)
moveCameraLocation(latLng) moveCameraLocation(latLng)
if (null == mMarker) { if (null == mMarker) {

View File

@@ -0,0 +1,64 @@
package com.abbidot.tracker.util
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import com.abbidot.tracker.service.BaiduLocationService
import com.easysocket.utils.LogUtil
/**
* 百度定位管理器
*/
object BaiduLocationManager {
private var locationService: BaiduLocationService? = null
private var isServiceBound = false
//服务连接回调
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as BaiduLocationService.LocalBinder
locationService = binder.getService()
isServiceBound = true
}
override fun onServiceDisconnected(arg0: ComponentName) {
isServiceBound = false
locationService = null
}
}
// 初始化:绑定服务(建议在Application或首页初始化)
fun init(context: Context) {
if (!isServiceBound) {
Intent(context, BaiduLocationService::class.java).also { intent ->
context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
}
}
}
// 启动定位(所有页面统一调用此方法)
fun startLocation(locationPeriod: Int = 1, needStopLocation: Boolean = false) {
locationService?.startLocation(locationPeriod, needStopLocation)
}
// 停止定位
fun stopLocation() {
locationService?.stopLocation()
}
// 释放资源(如退出应用时调用)
fun releaseServer(context: Context) {
try {
if (isServiceBound) {
LogUtil.e("onDestroy: 释放定位服务")
context.unbindService(serviceConnection)
isServiceBound = false
}
} catch (e: Exception) {
LogUtil.e("释放定位服务失败,releaseServer:${e.message}")
}
}
}

View File

@@ -1,8 +1,10 @@
package com.abbidot.tracker.util package com.abbidot.tracker.util
import com.abbidot.baselibrary.constant.EventName import com.abbidot.baselibrary.constant.EventName
import com.abbidot.baselibrary.constant.MMKVKey
import com.abbidot.baselibrary.eventbus.XEventBus import com.abbidot.baselibrary.eventbus.XEventBus
import com.abbidot.baselibrary.util.LogUtil import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.baselibrary.util.MMKVUtil
import com.abbidot.tracker.bean.BleReportDataBean import com.abbidot.tracker.bean.BleReportDataBean
import com.abbidot.tracker.bean.HistoryDataBean import com.abbidot.tracker.bean.HistoryDataBean
import com.abbidot.tracker.constant.ConstantInt import com.abbidot.tracker.constant.ConstantInt
@@ -86,10 +88,12 @@ class BleReportManage(
//定位方式 //定位方式
add(4) add(4)
add(1) add(1)
val lon = (LonAndLatUtil.currentUserGPSLon * 1000000).toLong() val userGpsLat = MMKVUtil.getDouble(MMKVKey.UserGpsLat)
val userGpsLon = MMKVUtil.getDouble(MMKVKey.UserGpsLon)
val lon = (userGpsLat * 1000000).toLong()
val lonByteArray = SRBleCmdUtil.instance.longTo4ByteArray(lon) val lonByteArray = SRBleCmdUtil.instance.longTo4ByteArray(lon)
addAll(lonByteArray.toMutableList()) addAll(lonByteArray.toMutableList())
val lat = (LonAndLatUtil.currentUserGPSLat * 1000000).toLong() val lat = (userGpsLon * 1000000).toLong()
val latByteArray = SRBleCmdUtil.instance.longTo4ByteArray(lat) val latByteArray = SRBleCmdUtil.instance.longTo4ByteArray(lat)
addAll(latByteArray.toMutableList()) addAll(latByteArray.toMutableList())
addAll(timeStampByteArray.toMutableList()) addAll(timeStampByteArray.toMutableList())

View File

@@ -0,0 +1,64 @@
package com.abbidot.tracker.util
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import com.abbidot.tracker.service.GoogleLocationService
import com.easysocket.utils.LogUtil
/**
* 谷歌定位管理器
*/
object GoogleLocationManager {
private var locationService: GoogleLocationService? = null
private var isServiceBound = false
//服务连接回调
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as GoogleLocationService.LocalBinder
locationService = binder.getService()
isServiceBound = true
}
override fun onServiceDisconnected(arg0: ComponentName) {
isServiceBound = false
locationService = null
}
}
// 初始化:绑定服务(建议在Application或首页初始化)
fun init(context: Context) {
if (!isServiceBound) {
Intent(context, GoogleLocationService::class.java).also { intent ->
context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
}
}
}
// 启动定位(所有页面统一调用此方法)
fun startLocation() {
locationService?.startLocation()
}
// 停止定位
fun stopLocation() {
locationService?.stopLocation()
}
// 释放资源(如退出应用时调用)
fun releaseServer(context: Context) {
try {
if (isServiceBound) {
LogUtil.e("onDestroy: 释放定位服务")
context.unbindService(serviceConnection)
isServiceBound = false
}
} catch (e: Exception) {
LogUtil.e("释放定位服务失败,releaseServer:${e.message}")
}
}
}

View File

@@ -1,68 +0,0 @@
package com.abbidot.tracker.util;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.os.Looper;
import androidx.annotation.NonNull;
import com.abbidot.baselibrary.util.LogUtil;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
/**
* Created by .yzq on 2023/10/18/018.
*
* @link <a href="https://www.cnblogs.com/CharlesGrant/p/8242413.html"/>
* @description: 谷歌定位,暂未使用
*/
public class GoogleLocationUtil {
private LocationRequest mLocationRequest;
@SuppressLint("MissingPermission")
public GoogleLocationUtil(Context context) {
createLocationRequest();
FusedLocationProviderClient fusedLocationClient =
LocationServices.getFusedLocationProviderClient(context);
LogUtil.Companion.e("GoogleLocationUtil");
// LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
//
// builder.addLocationRequest(mLocationRequest);
fusedLocationClient.requestLocationUpdates(mLocationRequest, new LocationCallback() {
@Override
public void onLocationResult(@NonNull LocationResult locationResult) {
super.onLocationResult(locationResult);
LogUtil.Companion.e("onLocationResult" + locationResult.getLastLocation());
}
}, Looper.myLooper());
fusedLocationClient.getLastLocation().addOnSuccessListener((Activity) context, location -> {
if (location != null) {
// Logic to handle location object
LogUtil.Companion.e("addOnSuccessListener" + location.getLatitude());
} else {
// Handle null case or Request periodic location update https://developer.android.com/training/location/receive-location-updates
LogUtil.Companion.e("addOnSuccessListener,location == null");
}
});
}
private void createLocationRequest() {
mLocationRequest = LocationRequest.create();
//更新间隔
mLocationRequest.setInterval(2000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
}
}

View File

@@ -232,9 +232,7 @@ object ImageUtil {
*/ */
fun getBitmapFromDrawableAndSvg(context: Context, @DrawableRes drawableId: Int): Bitmap? { fun getBitmapFromDrawableAndSvg(context: Context, @DrawableRes drawableId: Int): Bitmap? {
return when (val drawable = ContextCompat.getDrawable(context, drawableId)) { return when (val drawable = ContextCompat.getDrawable(context, drawableId)) {
is BitmapDrawable -> { is BitmapDrawable -> drawable.bitmap
drawable.bitmap
}
is VectorDrawable, is VectorDrawableCompat -> { is VectorDrawable, is VectorDrawableCompat -> {
val bitmap = Bitmap.createBitmap( val bitmap = Bitmap.createBitmap(

View File

@@ -16,10 +16,6 @@ class LonAndLatUtil {
companion object { companion object {
//当前用户的GPS经纬度
var currentUserGPSLat = 0.0
var currentUserGPSLon = 0.0
private const val a = 6378245.0 private const val a = 6378245.0
private const val ee = 0.00669342162296594323 private const val ee = 0.00669342162296594323

View File

@@ -96,6 +96,16 @@ class Util {
return Utils.formatDecimal(dis).toDouble() return Utils.formatDecimal(dis).toDouble()
} }
/**
* 获取地图ui显示的距离,以10的倍数显示
*/
fun getShowDistance(distance: Int): Int {
val singleDigit = distance % 10
val integerDigit = distance / 10 * 10
return if (singleDigit > 4) integerDigit + 10
else integerDigit
}
/** /**
* 转换英制单位 * 转换英制单位
* @param type 0=in 1=lbs 2=mph 3=ft * @param type 0=in 1=lbs 2=mph 3=ft

View File

@@ -89,6 +89,8 @@ class DeviceDFUViewModel(application: Application) : AndroidViewModel(applicatio
newVersion = true newVersion = true
break break
} }
//只要有一位本地版本号大于服务版本号,就认为是新版本号,无需更新
else if (serviceVersions[i].toInt() < localVersions[i].toInt()) break
} }
return newVersion return newVersion
} catch (e: Exception) { } catch (e: Exception) {

View File

@@ -10,6 +10,7 @@ import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.ui.fragment.map.baidumap.BaseBaiduMapFragment import com.abbidot.tracker.ui.fragment.map.baidumap.BaseBaiduMapFragment
import com.abbidot.tracker.ui.fragment.map.googlemap.BaseGoogleMapFragment import com.abbidot.tracker.ui.fragment.map.googlemap.BaseGoogleMapFragment
import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.LatLng
import kotlin.math.abs
/** /**
*Created by .yzq on 2022/3/2/002. *Created by .yzq on 2022/3/2/002.
@@ -121,7 +122,7 @@ class FencesMapViewModel : ViewModel() {
} }
if (null == fencesList) return if (null == fencesList) return
if (fencesList.size == 0) return if (fencesList.isEmpty()) return
val saveFillColor = ContextCompat.getColor(context, R.color.select_color4) val saveFillColor = ContextCompat.getColor(context, R.color.select_color4)
var saveStrokeColor = ContextCompat.getColor(context, R.color.select_color) var saveStrokeColor = ContextCompat.getColor(context, R.color.select_color)
@@ -190,10 +191,24 @@ class FencesMapViewModel : ViewModel() {
} }
} else if (mapFragment is BaseBaiduMapFragment) { } else if (mapFragment is BaseBaiduMapFragment) {
if (it.fenceShapeType == ConstantInt.CircleShapeType) { if (it.fenceShapeType == ConstantInt.CircleShapeType) {
var mapRadius = it.radius
mapFragment.mBaiduMap?.let { map ->
val pointCentre = map.projection.toScreenLocation(
mapFragment.getBaiduMapLatLng(
it.latitudeCenter, it.longitudeCenter
)
)
val pointLineEnd = map.projection.toScreenLocation(
mapFragment.getBaiduMapLatLng(
it.ancillaryLatitude, it.ancillaryLongitude
)
)
mapRadius = abs(pointLineEnd.x - pointCentre.x)
}
mapFragment.addCircleDashedAndImageFence( mapFragment.addCircleDashedAndImageFence(
it.latitudeCenter, it.latitudeCenter,
it.longitudeCenter, it.longitudeCenter,
it.radius.toDouble(), mapRadius.toDouble(),
imageTypeResId, imageTypeResId,
strokeColor, strokeColor,
fillColor fillColor

View File

@@ -8,7 +8,6 @@ import androidx.lifecycle.ViewModel
import com.abbidot.baselibrary.constant.MMKVKey import com.abbidot.baselibrary.constant.MMKVKey
import com.abbidot.baselibrary.util.LogUtil import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.baselibrary.util.MMKVUtil import com.abbidot.baselibrary.util.MMKVUtil
import com.abbidot.tracker.util.LonAndLatUtil
import com.google.android.gms.location.FusedLocationProviderClient import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.Priority import com.google.android.gms.location.Priority
@@ -99,8 +98,6 @@ class GoogleLocationViewModel : ViewModel() {
MMKVUtil.putDouble(MMKVKey.UserGpsLon, longitude) MMKVUtil.putDouble(MMKVKey.UserGpsLon, longitude)
//单位是米/秒(m/s) //单位是米/秒(m/s)
MMKVUtil.putFloat(MMKVKey.UserGpsSpeed, speed) MMKVUtil.putFloat(MMKVKey.UserGpsSpeed, speed)
LonAndLatUtil.currentUserGPSLat = location.latitude
LonAndLatUtil.currentUserGPSLon = location.longitude
} }
} }

View File

@@ -64,7 +64,7 @@
android:gravity="start" android:gravity="start"
android:text="@string/txt_help_status_network" android:text="@string/txt_help_status_network"
android:textSize="@dimen/textSize16" android:textSize="@dimen/textSize16"
app:lineHeight="@dimen/textSize18" /> app:lineHeight="@dimen/textSize22" />
<com.abbidot.tracker.widget.TypefaceTextView <com.abbidot.tracker.widget.TypefaceTextView
style="@style/my_TextView_style_v2" style="@style/my_TextView_style_v2"
@@ -73,55 +73,7 @@
android:gravity="start" android:gravity="start"
android:text="@string/txt_help_status_bluetooth" android:text="@string/txt_help_status_bluetooth"
android:textSize="@dimen/textSize16" android:textSize="@dimen/textSize16"
app:lineHeight="@dimen/textSize18" /> app:lineHeight="@dimen/textSize22" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.abbidot.tracker.widget.TypefaceTextView
style="@style/my_TextView_style_v2"
android:layout_width="0dp"
android:layout_weight="1"
android:gravity="start"
android:text="@string/txt_help_status_wifi_zone"
android:textSize="@dimen/textSize16"
app:lineHeight="@dimen/textSize18" />
<com.abbidot.tracker.widget.TypefaceTextView
style="@style/my_TextView_style_v2"
android:layout_width="0dp"
android:layout_weight="1"
android:gravity="start"
android:text="@string/txt_help_status_battery"
android:textSize="@dimen/textSize16"
app:lineHeight="@dimen/textSize18" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.abbidot.tracker.widget.TypefaceTextView
style="@style/my_TextView_style_v2"
android:layout_width="0dp"
android:layout_weight="1"
android:gravity="start"
android:text="@string/txt_help_status_gps"
android:textSize="@dimen/textSize16"
app:lineHeight="@dimen/textSize18" />
<com.abbidot.tracker.widget.TypefaceTextView
style="@style/my_TextView_style_v2"
android:layout_width="0dp"
android:layout_weight="1"
android:gravity="start"
android:text="@string/txt_help_status_led"
android:textSize="@dimen/textSize16"
app:lineHeight="@dimen/textSize18" />
</androidx.appcompat.widget.LinearLayoutCompat> </androidx.appcompat.widget.LinearLayoutCompat>
<include <include
@@ -129,7 +81,7 @@
layout="@layout/layout_help_title1" layout="@layout/layout_help_title1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_18" /> android:layout_marginTop="@dimen/dp_16" />
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -43,43 +43,29 @@
<!--http://stackoverflow.com/questions/17502824/whats-wrong-with-this-format-string--> <!--http://stackoverflow.com/questions/17502824/whats-wrong-with-this-format-string-->
<!--简体中文-Android--> <!--简体中文-Android-->
<!-- diff -->
<string name="acccount_height_how_detail">从地面测量到宠物肩胛骨的最高点</string> <string name="acccount_height_how_detail">从地面测量到宠物肩胛骨的最高点</string>
<string name="tracker_manage_set_battery">电量:%s%%</string> <string name="tracker_manage_set_battery">电量:%s%%</string>
<string name="pet_managet_age">%s年</string> <string name="pet_managet_age">%s年</string>
<string name="pet_manage_weight">%d磅</string>
<string name="map_current_update_time">更新时间:%s</string>
<string name="select_puzzle_photos">请选择2 \~ 9张照片</string>
<string name="txt_about_version">版本%s</string> <string name="txt_about_version">版本%s</string>
<string name="txt_service_contract">服务协议</string> <string name="txt_service_contract">服务协议</string>
<string name="txt_read_and_accept">接受隐私政策与条款。</string> <string name="txt_read_and_accept">接受隐私政策与条款。</string>
<string name="txt_device_has_bind">该设备已被%s绑定</string> <string name="txt_device_has_bind">该设备已被%s绑定</string>
<string name="txt_activity_goal">运动目标</string> <string name="txt_activity_goal">运动目标</string>
<string name="txt_end_time">结束时间</string> <string name="txt_end_time">结束时间</string>
<string name="txt_fix_goal_tip">为宠物定制每日趣味活动,专注早晚互动,兼顾其需求、物种与品种</string> <string name="txt_fix_goal_tip">为宠物定制每日趣味活动,专注早晚互动,兼顾其需求、物种与品种</string>
<string name="txt_invite">+\t邀请</string> <string name="txt_invite">+\t邀请</string>
<string name="txt_invite_family_tip">共享的家庭成员可查看宠物位置和日期,但无法编辑</string> <string name="txt_invite_family_tip">共享的家庭成员可查看宠物位置和日期,但无法编辑</string>
<string name="txt_otp_verification_tips">请输入发送至 %s 的4位数验证码</string> <string name="txt_otp_verification_tips">请输入发送至 %s 的4位数验证码</string>
<string name="txt_time_remaining">剩余时间:\t</string> <string name="txt_time_remaining">剩余时间:\t</string>
<string name="txt_create_account_terms1">注册即表示接受服务条款和隐私政策</string>
<string name="txt_pair_tracker_tip">确认6字符ID与追踪器背面一致</string> <string name="txt_pair_tracker_tip">确认6字符ID与追踪器背面一致</string>
<string name="txt_input_id_tip">在设备背面找到6位数ID</string> <string name="txt_input_id_tip">在设备背面找到6位数ID</string>
<string name="txt_add_tracker_tip">设备ID错误,请核对后重试</string> <string name="txt_add_tracker_tip">设备ID错误,请核对后重试</string>
<string name="txt_success_paired">配对成功</string> <string name="txt_success_paired">配对成功</string>
<string name="txt_expires_on">有效期至</string>
<string name="txt_renew_year1">(续订价</string> <string name="txt_renew_year1">(续订价</string>
<string name="txt_is_pet_home">这是您宠物的常驻地吗?</string> <string name="txt_is_pet_home">这是您宠物的常驻地吗?</string>
<string name="txt_unassign_other">解绑 %s</string> <string name="txt_unassign_other">解绑 %s</string>
<string name="txt_family_delete">您确定要删除家庭成员%s</string>
<string name="txt_ble_permissions_tip">•\t 确保活动数据同步准确的必要条件。</string> <string name="txt_ble_permissions_tip">•\t 确保活动数据同步准确的必要条件。</string>
<string name="txt_location_permissions_tip">•\t 在地图上显示您自己的位置 \n•\t 同步活动数据所必需 \n•\t 提升追踪器精度</string> <string name="txt_location_permissions_tip">•\t 在地图上显示您自己的位置 \n•\t 同步活动数据所必需 \n•\t 提升追踪器精度</string>
<string name="txt_notice_permissions_tip">•\t 允许接收通知以掌握重要信息,例如您的爱宠是否离开了安全区域,或者您是否该考虑为设备充电了。</string> <string name="txt_notice_permissions_tip">•\t 允许接收通知以掌握重要信息,例如您的爱宠是否离开了安全区域,或者您是否该考虑为设备充电了。</string>
@@ -88,10 +74,7 @@
<string name="txt_tracker_battery_tip4">选择“宠物” > “追踪器” ,点击“GPS更新间隔” ,选择3/5/10/15分钟。</string> <string name="txt_tracker_battery_tip4">选择“宠物” > “追踪器” ,点击“GPS更新间隔” ,选择3/5/10/15分钟。</string>
<string name="txt_tracker_battery_tip5">(更短的网络连接间隔会更快耗尽设备电量。默认情况下,网络每15分钟重新连接一次。)</string> <string name="txt_tracker_battery_tip5">(更短的网络连接间隔会更快耗尽设备电量。默认情况下,网络每15分钟重新连接一次。)</string>
<string name="txt_tracker_battery_tip6">当直播开启时,追踪器进入快速定位和联网状态,通常在15-20秒内完成。此模式耗电最快,因此最好仅在紧急情况下使用。</string> <string name="txt_tracker_battery_tip6">当直播开启时,追踪器进入快速定位和联网状态,通常在15-20秒内完成。此模式耗电最快,因此最好仅在紧急情况下使用。</string>
<string name="txt_renewal_year1">续费:</string> <string name="txt_renewal_year1">续费:</string>
<string name="txt_month_unit">/月 x%s</string>
<string name="txt_change_email_tip">将发送验证码至 %s</string> <string name="txt_change_email_tip">将发送验证码至 %s</string>
<string name="txt_upgrade_unlock">升级至高级版,解锁独家功能!</string> <string name="txt_upgrade_unlock">升级至高级版,解锁独家功能!</string>
<string name="txt_new_firmware_version">检测到新固件版本:%s</string> <string name="txt_new_firmware_version">检测到新固件版本:%s</string>
@@ -115,67 +98,16 @@
<string name="txt_package_permission2">1.设备1次更换\n2. 专属客户支持\n3. 年度保障服务</string> <string name="txt_package_permission2">1.设备1次更换\n2. 专属客户支持\n3. 年度保障服务</string>
<string name="txt_package_permission3">1. VIP 优先支持\n2. 快速更换服务(含1次)\n3. 增强型保障\n4. 无忧宠物保护</string> <string name="txt_package_permission3">1. VIP 优先支持\n2. 快速更换服务(含1次)\n3. 增强型保障\n4. 无忧宠物保护</string>
<string name="txt_min_unit_lower">%s 分钟</string> <string name="txt_min_unit_lower">%s 分钟</string>
<string name="txt_duration_min_unit">%s 分钟</string> <string name="txt_duration_min_unit">%s 分钟</string>
<string name="txt_legal_info_content">欢迎使用爱彼宠物!为了更好地保障您的权益,我们将在本《隐私政策》声明中向您说明我们如何收集、使用、处理和保障您提供给我们的信息。请仔细阅读《隐私政策》和《服务条款》。</string>
<string name="start_txt_yes">是的</string> <string name="start_txt_yes">是的</string>
<string name="tracker_number">%d个设备</string>
<string name="pet_number">%d只</string>
<string name="pet_manage_height">%d 英寸</string>
<string name="txt_permissions_fail_tips">未能获得许可</string>
<string name="no_pet">无宠物</string>
<string name="no_bind_pet">请先绑定宠物</string>
<string name="txt_battery_unit">%d%%</string>
<string name="txt_pet_birthdayDate">%d年%d月</string>
<string name="selector_folder_video_easy_photos">全部视频</string>
<string name="selector_action_done_easy_photos">完成(%1$d/%2$d)</string>
<string name="selector_reach_max_hint_easy_photos">最多支持%d个图片或视频</string>
<string name="selector_reach_max_image_hint_easy_photos">最多支持%d个图片</string>
<string name="selector_reach_max_video_hint_easy_photos">最多支持%d个视频</string>
<string name="selector_image_size_error_easy_photos">照片的宽度应大于%1$d,高度应大于%1$d</string>
<string name="permissions_again_easy_photos">请允许相关权限</string>
<string name="permissions_die_easy_photos">请允许相关权限</string>
<string name="preview_current_number_easy_photos">%1$d/%2$d</string>
<string name="txt_today_date">今天\t%s</string>
<string name="video_selection_easy_photos">选择视频</string>
<string name="txt_dollar">¥\t%.2f</string>
<string name="txt_goal_percent">%s%%</string>
<string name="txt_reset_password_tips">输入您档案的注册邮箱,我们将发送4位数验证码至该邮箱</string>
<string name="txt_money_unit">$%s</string>
<string name="txt_per_month_money">$%s/月</string>
<string name="txt_per_year_money">$%s/年</string>
<string name="txt_delete_pet_data">这将从您的账户中永久删除所有 %s 数据</string>
<string name="txt_renew_year">(按每年 $%s 续订)</string>
<string name="txt_activity_success">激活成功!</string>
<string name="txt_start_min_live">正在启动 %s-分钟直播</string>
<string name="txt_code_valid_min">验证码有效期为 %ss</string>
<string name="txt_family_invitation_dec">您的朋友 %s 邀请您成为 %s 的家人。</string>
<string name="txt_renewal_year">续费:$%s/年,于%s</string>
<string name="txt_renewal_month">续费:$%s/月,于%s</string>
<string name="txt_annual_care">年度保险</string>
<string name="txt_auto_subscription_year">(此后按每年 $%s 续订)</string>
<string name="txt_auto_subscription_month">(此后按每月 $%s 续订)</string>
<string name="txt_fail">失败</string>
<string name="txt_edit_pay_method">编辑付款方式</string>
<string name="txt_no_signal_tip">无信号。请检查宠物是否在室内。</string>
<string name="txt_credit_card_exists">卡号已存在。是否覆盖?</string> <string name="txt_credit_card_exists">卡号已存在。是否覆盖?</string>
<string name="txt_please_enter_pws">请输入密码。</string>
<string name="txt_please_enter_email">请输入邮箱。</string>
<string name="txt_wifi_password_dec">当移动信号弱时,Wi-Fi可确保设备保持连接</string> <string name="txt_wifi_password_dec">当移动信号弱时,Wi-Fi可确保设备保持连接</string>
<string name="txt_renewal_day">续费:$%s/%s天,于%s</string> <string name="txt_renewal_day">续费:$%s/%s天,于%s</string>
<string name="txt_day_unit">/天 x%s</string> <string name="txt_day_unit">/天 x%s</string>
<string name="txt_location_tip">ABBIDOT应用收集位置数据,可计算当前位置与设备之间的路线和距离。</string>
<string name="txt_auto_subscription_day">(之后按$%s每天续费)</string>
<string name="txt_auto_subscription_days">(之后按$%s/%s天续费)</string>
<string name="txt_auto_subscription_years">(之后按$%s/%s年续费)</string>
<string name="txt_auto_subscription_months">(之后按$%s/%s月续费)</string>
<string name="txt_year_care">%s 年保险</string> <string name="txt_year_care">%s 年保险</string>
<string name="txt_expiry_time">到期时间:</string>
<string name="txt_replacement_year">1年 1 次无理由换新</string> <string name="txt_replacement_year">1年 1 次无理由换新</string>
<string name="txt_bluetooth_radar">蓝牙雷达</string> <string name="txt_bluetooth_radar">蓝牙雷达</string>
<string name="txt_fence_saved">已保存,上线时生效。</string> <string name="txt_fence_saved">已保存,上线时生效。</string>
<string name="txt_renewal_years">续订:$%s / %s 年,于 %s</string>
<string name="txt_renewal_months">续订:$%s / %s 月,于 %s</string>
<string name="txt_refund_expired">退款期限已过</string> <string name="txt_refund_expired">退款期限已过</string>
<string name="txt_refund_policy">退款政策\n</string> <string name="txt_refund_policy">退款政策\n</string>
<string name="txt_automatic_refund">自动退款(48小时内)</string> <string name="txt_automatic_refund">自动退款(48小时内)</string>
@@ -184,128 +116,77 @@
<string name="txt_standard_refund_dec">在最初的48小时之后,用户可在购买后30天内申请退款。\n\t1. 所有订阅计划(3个月、1年、2年)均符合条件\n\t2. 退款申请需经过审核和批准\n\t3. 退款可能会根据使用情况和服务消耗进行部分调整\n</string> <string name="txt_standard_refund_dec">在最初的48小时之后,用户可在购买后30天内申请退款。\n\t1. 所有订阅计划(3个月、1年、2年)均符合条件\n\t2. 退款申请需经过审核和批准\n\t3. 退款可能会根据使用情况和服务消耗进行部分调整\n</string>
<string name="txt_no_refund_dec">超过30天的订阅不可退款。</string> <string name="txt_no_refund_dec">超过30天的订阅不可退款。</string>
<string name="txt_no_refund">30天后不退款</string> <string name="txt_no_refund">30天后不退款</string>
<string name="txt_garden">花园</string>
<string name="txt_park">公园</string>
<string name="txt_play">玩耍</string>
<string name="txt_unsafe">不安全</string>
<string name="txt_vegetable_garden">菜园</string>
<string name="txt_water">水域</string>
<string name="login_txt_welcome">欢迎</string> <string name="login_txt_welcome">欢迎</string>
<string name="login_txt_email">邮箱</string> <string name="login_txt_email">邮箱</string>
<string name="login_txt_phone">手机号</string>
<string name="login_txt_password">密码</string> <string name="login_txt_password">密码</string>
<string name="login_txt_fogot">忘记密码?</string> <string name="login_txt_fogot">忘记密码?</string>
<string name="login_txt_login_wechat">微信登录</string>
<string name="login_txt_login_code">验证码登录</string>
<string name="txt_code_success">验证码已发送</string>
<string name="login_txt_no_account">没有账号?</string> <string name="login_txt_no_account">没有账号?</string>
<string name="login_txt_no_account_sign_up">注册</string> <string name="login_txt_no_account_sign_up">注册</string>
<string name="register_txt_back_login">返回登录</string> <string name="register_txt_back_login">返回登录</string>
<string name="register_txt_name">昵称</string> <string name="register_txt_name">昵称</string>
<string name="register_txt_next">下一步</string> <string name="register_txt_next">下一步</string>
<string name="register_txt_resend">重新发送</string> <string name="register_txt_resend">重新发送</string>
<string name="register_txt_agree">同意《服务协议》和《隐私政策》</string> <string name="register_txt_agree">同意《服务协议》和《隐私政策》</string>
<string name="register_txt_agree1">请阅读并同意</string>
<string name="register_txt_agree2">和</string>
<string name="register_txt_terms">《服务协议》</string>
<string name="register_txt_policy">《隐私政策》</string>
<string name="register_txt_submit">提交</string> <string name="register_txt_submit">提交</string>
<string name="system_txt_map">地图</string> <string name="system_txt_map">地图</string>
<string name="system_txt_profile">我的</string> <string name="system_txt_profile">我的</string>
<string name="txt_feedback">反馈中心</string>
<string name="txt_setting">设置</string> <string name="txt_setting">设置</string>
<string name="txt_setting_notification">消息中心</string> <string name="txt_setting_notification">消息中心</string>
<string name="txt_setting_account">帐户</string> <string name="txt_setting_account">帐户</string>
<string name="txt_setting_about">关于</string> <string name="txt_setting_about">关于</string>
<string name="txt_setting_clear">清除缓存</string> <string name="txt_setting_clear">清除缓存</string>
<string name="txt_feedback_title">反馈中心</string> <string name="txt_feedback_title">反馈中心</string>
<string name="txt_feedback_type">问题类型(必填)</string> <string name="txt_feedback_type">问题类型(必填)</string>
<string name="txt_feedback_type_app">关于APP</string> <string name="txt_feedback_type_app">关于APP</string>
<string name="txt_feedback_type_tracker">关于设备</string> <string name="txt_feedback_type_tracker">关于设备</string>
<string name="txt_feedback_type_others">其它</string> <string name="txt_feedback_type_others">其它</string>
<string name="txt_feedback_enter">请输入您的问题或建议</string> <string name="txt_feedback_enter">请输入您的问题或建议</string>
<string name="txt_feedback_notype">请选择问题类型</string>
<string name="txt_feedback_email">请留下您的邮箱,以便我们更快地帮助您</string> <string name="txt_feedback_email">请留下您的邮箱,以便我们更快地帮助您</string>
<string name="acccount_img">上传图片</string> <string name="acccount_img">上传图片</string>
<string name="acccount_name">名称</string> <string name="acccount_name">名称</string>
<string name="acccount_birthday">生日</string> <string name="acccount_birthday">生日</string>
<string name="acccount_email">邮箱</string> <string name="acccount_email">邮箱</string>
<string name="acccount_breed">品种</string>
<string name="acccount_weight">体重</string> <string name="acccount_weight">体重</string>
<string name="acccount_height">肩高</string> <string name="acccount_height">肩高</string>
<string name="acccount_height_how">如何测量身高</string> <string name="acccount_height_how">如何测量身高</string>
<string name="acccount_btn_save">保存</string> <string name="acccount_btn_save">保存</string>
<string name="acccount_label">标签</string> <string name="acccount_label">标签</string>
<string name="tracker_activate">激活</string> <string name="tracker_activate">激活</string>
<string name="tracker_activate_no">不用了,谢谢</string> <string name="tracker_activate_no">不用了,谢谢</string>
<string name="tracker_manage">我的设备</string> <string name="tracker_manage">我的设备</string>
<string name="tracker_manage_mine">我的设备</string>
<string name="tracker_manage_led">LED灯</string> <string name="tracker_manage_led">LED灯</string>
<string name="tracker_manage_add_pet">新宠物</string> <string name="tracker_manage_add_pet">新宠物</string>
<string name="tracker_manage_set_unbind">解绑</string> <string name="tracker_manage_set_unbind">解绑</string>
<string name="tracker_manage_set_network">网络</string> <string name="tracker_manage_set_network">网络</string>
<string name="tracker_manage_set_gps">GPS</string> <string name="tracker_manage_set_gps">GPS</string>
<string name="tracker_manage_set_ble_connect">蓝牙已连接</string> <string name="tracker_manage_set_ble_connect">蓝牙已连接</string>
<string name="tracker_manage_set_ble_unconnect">蓝牙未连接</string> <string name="tracker_manage_set_ble_unconnect">蓝牙未连接</string>
<string name="tracker_manage_set_led">LED灯</string>
<string name="tracker_manage_set_led_off">关</string> <string name="tracker_manage_set_led_off">关</string>
<string name="tracker_manage_set_led_on">开</string> <string name="tracker_manage_set_led_on">开</string>
<string name="tracker_manage_set_family">家人</string>
<string name="tracker_manage_set_add_family_invite">邀请</string> <string name="tracker_manage_set_add_family_invite">邀请</string>
<string name="tracker_manage_set_add_family_succ">发送成功</string> <string name="tracker_manage_set_add_family_succ">发送成功</string>
<string name="tracker_manage_set_add_family_back">返回</string>
<string name="tracker_manage_set_duration">追踪间隔</string> <string name="tracker_manage_set_duration">追踪间隔</string>
<string name="tracker_manage_set_fence_name">名称</string> <string name="tracker_manage_set_fence_name">名称</string>
<string name="tracker_manage_set_fence_shape">形式</string> <string name="tracker_manage_set_fence_shape">形式</string>
<string name="tracker_manage_set_fence_activate">启用围栏</string> <string name="tracker_manage_set_fence_activate">启用围栏</string>
<string name="tracker_manage_set_finish">完成</string> <string name="tracker_manage_set_finish">完成</string>
<string name="tracker_light_mode_sustained">常亮</string> <string name="tracker_light_mode_sustained">常亮</string>
<string name="tracker_light_mode_breathing">呼吸</string> <string name="tracker_light_mode_breathing">呼吸</string>
<string name="tracker_light_mode_flash">快闪</string> <string name="tracker_light_mode_flash">快闪</string>
<string name="pet_manage">我的宠物</string> <string name="pet_manage">我的宠物</string>
<string name="pet_manage_gender_male">雄</string> <string name="pet_manage_gender_male">雄</string>
<string name="pet_manage_gender_female">雌</string> <string name="pet_manage_gender_female">雌</string>
<string name="pet_manage_detail_edit">编辑</string> <string name="pet_manage_detail_edit">编辑</string>
<string name="pet_manage_detail_title2">活动勋章</string>
<string name="map_live_btn_stop">停止直播</string> <string name="map_live_btn_stop">停止直播</string>
<string name="map_navigate_select_map">选择地图</string>
<string name="map_navigate_map_google">谷歌地图</string>
<string name="map_navigate_map_gaode">高德地图</string>
<string name="map_navigate_cancel">取消</string> <string name="map_navigate_cancel">取消</string>
<string name="txt_no_install">APP未安装,请先下载安装</string>
<string name="data_active_time">运动时间</string> <string name="data_active_time">运动时间</string>
<string name="data_active_calories">卡路里</string> <string name="data_active_calories">卡路里</string>
<string name="data_active_goal_set">设置目标</string> <string name="data_active_goal_set">设置目标</string>
<string name="data_active_btn_change">修改</string> <string name="data_active_btn_change">修改</string>
<string name="data_active_btn_current">当前</string> <string name="data_active_btn_current">当前</string>
@@ -315,24 +196,16 @@
<string name="txt_not_null">请完整填写</string> <string name="txt_not_null">请完整填写</string>
<string name="txt_successful">成功</string> <string name="txt_successful">成功</string>
<string name="txt_upload_successful">上传成功</string> <string name="txt_upload_successful">上传成功</string>
<string name="txt_add_successful">添加成功</string>
<string name="txt_save_successful">保存成功</string> <string name="txt_save_successful">保存成功</string>
<string name="txt_login_successful">登录成功</string> <string name="txt_login_successful">登录成功</string>
<string name="txt_change_successful">修改成功</string> <string name="txt_change_successful">修改成功</string>
<string name="txt_tips">提示</string> <string name="txt_tips">提示</string>
<string name="txt_add_fences">添加围栏</string> <string name="txt_add_fences">添加围栏</string>
<string name="no_data">无数据</string> <string name="no_data">无数据</string>
<string name="txt_delete_success">成功删除</string>
<string name="txt_delete_tips">确定要删除?</string> <string name="txt_delete_tips">确定要删除?</string>
<string name="txt_unbind_tips">确定要解绑设备?</string>
<string name="txt_unbind_success">解绑成功</string>
<string name="txt_bind_success">绑定成功</string>
<string name="txt_today">今天</string> <string name="txt_today">今天</string>
<string name="txt_min">分钟</string> <string name="txt_min">分钟</string>
<string name="txt_distance_unit">英里</string>
<string name="txt_calorie_unit">大卡</string>
<string name="txt_persisted_unit">天</string> <string name="txt_persisted_unit">天</string>
<string name="txt_device_renewal">您的设备已过期,请充值</string>
<string name="txt_stop_live_tips">停止直播?</string> <string name="txt_stop_live_tips">停止直播?</string>
<string name="txt_delete">删除</string> <string name="txt_delete">删除</string>
<string name="txt_cancel">取消</string> <string name="txt_cancel">取消</string>
@@ -340,110 +213,43 @@
<string name="txt_sure">确定</string> <string name="txt_sure">确定</string>
<string name="txt_notifications">通知</string> <string name="txt_notifications">通知</string>
<string name="txt_net_error">请求失败,请重试</string> <string name="txt_net_error">请求失败,请重试</string>
<string name="txt_load_map">地图加载中&#8230;</string>
<string name="hello_blank_fragment">你好,空白片段</string>
<string name="selector_folder_all_easy_photos">全部图片</string> <string name="selector_folder_all_easy_photos">全部图片</string>
<string name="selector_folder_all_video_photo_easy_photos">图片和视频</string>
<string name="selector_easy_photos">选择</string>
<string name="selector_preview_easy_photos">预览</string>
<string name="selector_single_type_hint_easy_photos">只能选择一种类型的文件</string>
<string name="msg_no_camera_easy_photos">无法启动相机</string>
<string name="camera_temp_file_error_easy_photos">图片错误</string>
<string name="selector_permission_error_easy_photos">请允许相关权限</string> <string name="selector_permission_error_easy_photos">请允许相关权限</string>
<string name="selector_image_type_error_easy_photos">不支持该图像格式</string>
<string name="edit_easy_photos">编辑</string> <string name="edit_easy_photos">编辑</string>
<string name="empty_easy_photos">清除</string>
<string name="no_photos_easy_photos">没有匹配的照片</string>
<string name="no_videos_easy_photos">没有匹配的视频</string>
<string name="original_easy_photos">原始</string>
<string name="done_easy_photos">完成</string>
<string name="cancel_easy_photos">取消</string>
<string name="template_easy_photos">模板</string>
<string name="text_sticker_easy_photos">文本</string>
<string name="text_sticker_date_easy_photos">日期</string>
<string name="text_sticker_hint_easy_photos">双击编辑</string>
<string name="text_sticker_hint_name_easy_photos">自定义</string>
<string name="picture_selection_easy_photos">选择照片</string>
<string name="gif_easy_photos">GIF</string>
<string name="txt_card_auto_sub">自动订阅:</string> <string name="txt_card_auto_sub">自动订阅:</string>
<string name="txt_card_recharge">充值</string> <string name="txt_card_recharge">充值</string>
<string name="txt_pay_order_total">总计</string> <string name="txt_pay_order_total">总计</string>
<string name="txt_pay_order_add_card">添加新卡</string>
<string name="txt_pay_order_payment_title">支付详情</string>
<string name="txt_pay_order_payment_again">重试</string> <string name="txt_pay_order_payment_again">重试</string>
<string name="txt_pay_order_payment_back">返回</string> <string name="txt_pay_order_payment_back">返回</string>
<string name="txt_log_out_tips">确定要退出登录吗?</string> <string name="txt_log_out_tips">确定要退出登录吗?</string>
<string name="txt_clear_cache_tips">确定要清除缓存?</string> <string name="txt_clear_cache_tips">确定要清除缓存?</string>
<string name="txt_light_mode">灯光模式</string> <string name="txt_light_mode">灯光模式</string>
<string name="txt_firmware_upgrade">固件升级</string>
<string name="txt_feedback_success">提交成功</string>
<string name="txt_clear_cache_success">清除成功</string>
<string name="txt_loading">加载中...</string> <string name="txt_loading">加载中...</string>
<string name="txt_token_overdue">登录失败,请重新登录</string>
<string name="txt_auto_recharge_title">确定要取消自动订阅?</string> <string name="txt_auto_recharge_title">确定要取消自动订阅?</string>
<string name="txt_auto_recharge_content">自动订阅更方便,因为您不必担心订阅过期</string> <string name="txt_auto_recharge_content">自动订阅更方便,因为您不必担心订阅过期</string>
<string name="txt_card_number">卡号</string> <string name="txt_card_number">卡号</string>
<string name="txt_cardholder_name">持卡人姓名</string>
<string name="card_holder">持卡人</string>
<string name="expiry">截止日期</string>
<string name="txt_validity_card">MM/YY</string> <string name="txt_validity_card">MM/YY</string>
<string name="txt_cvv_card">CVV</string> <string name="txt_cvv_card">CVV</string>
<string name="txt_pay_success">支付成功</string> <string name="txt_pay_success">支付成功</string>
<string name="txt_pay_fail">支付失败,请重试</string> <string name="txt_pay_fail">支付失败,请重试</string>
<string name="txt_card_validity_format">失效日期</string>
<string name="txt_card_number_format">信用卡格式无效</string>
<string name="txt_turnoff_tips">您确定要关闭设备吗?</string>
<string name="txt_crop">裁剪图片</string>
<string name="txt_connecting">连接中&#8230;</string> <string name="txt_connecting">连接中&#8230;</string>
<string name="txt_close_account_tips">注销账户将删除账户下所有的数据,是否继续?</string> <string name="txt_close_account_tips">注销账户将删除账户下所有的数据,是否继续?</string>
<string name="txt_exit_return">再次返回退出程序</string>
<string name="txt_user_password_error">用户名或密码错误</string> <string name="txt_user_password_error">用户名或密码错误</string>
<string name="txt_verify_code_error">验证码错误</string> <string name="txt_verify_code_error">验证码错误</string>
<string name="txt_verify_code_expire">验证码已过期</string> <string name="txt_verify_code_expire">验证码已过期</string>
<string name="txt_register_fail">注册失败</string>
<string name="txt_user_no_exist">用户不存在</string> <string name="txt_user_no_exist">用户不存在</string>
<string name="txt_user_has_exist">用户已存在</string> <string name="txt_user_has_exist">用户已存在</string>
<string name="txt_email_format_error">邮箱格式不对</string>
<string name="txt_disconnect_tips">是否断开连接设备?</string>
<string name="txt_connect_success">连接成功</string>
<string name="txt_connect_fail">连接失败</string>
<string name="txt_register_phone">请输入手机号</string>
<string name="txt_find_password">找回密码</string> <string name="txt_find_password">找回密码</string>
<string name="txt_about_app_name">爱彼宠物</string>
<string name="txt_privacy_policy">隐私政策</string> <string name="txt_privacy_policy">隐私政策</string>
<string name="txt_website">官网</string> <string name="txt_website">官网</string>
<string name="txt_change_pwd">修改密码</string>
<string name="txt_cancel_pay">取消支付</string>
<string name="txt_ble_enable">请打开手机蓝牙</string> <string name="txt_ble_enable">请打开手机蓝牙</string>
<string name="txt_no_share_myself">不能分享给自己</string> <string name="txt_no_share_myself">不能分享给自己</string>
<string name="txt_device_has_bound">当前用户已经绑定该设备</string>
<string name="txt_first_name">姓</string>
<string name="txt_last_name">名</string>
<string name="txt_online">在线</string> <string name="txt_online">在线</string>
<string name="txt_offline">离线</string> <string name="txt_offline">离线</string>
<string name="txt_legal_info_title">法律信息</string>
<string name="txt_accept">我接受</string>
<string name="txt_deny">拒绝</string>
<string name="txt_no_down_url">没有下载地址</string>
<string name="txt_please_wait">请稍等&#8230;</string>
<string name="txt_release_notes">版本说明</string>
<string name="txt_firmware_name">固件名称</string>
<string name="txt_firmware_version">固件版本</string> <string name="txt_firmware_version">固件版本</string>
<string name="txt_firmware_size">固件大小</string>
<string name="txt_upgrade">升级</string> <string name="txt_upgrade">升级</string>
<string name="txt_upgrade_success">升级成功</string>
<string name="txt_upgrade_fail">升级失败</string>
<string name="txt_down_firmware">下载固件</string>
<string name="txt_dfu_model">进入DFU模式</string>
<string name="txt_search_dfu">搜索DUF设备</string>
<string name="txt_no_dfu">设备不存在</string> <string name="txt_no_dfu">设备不存在</string>
<string name="txt_connect_device">连接设备</string>
<string name="txt_reconnect_device">重连设备</string>
<string name="txt_unconnect">设备已断开</string>
<string name="txt_unconnect_no">断开连接</string> <string name="txt_unconnect_no">断开连接</string>
<string name="txt_upgrading">升级中</string>
<string name="txt_upgrade_start">准备升级</string>
<string name="txt_device_connect_success">设备连接成功</string>
<string name="txt_latest_version">已是最新版本</string> <string name="txt_latest_version">已是最新版本</string>
<string name="txt_activity">运动</string> <string name="txt_activity">运动</string>
<string name="txt_route">历史</string> <string name="txt_route">历史</string>
@@ -460,7 +266,6 @@
<string name="txt_low_zone">WiFi区域</string> <string name="txt_low_zone">WiFi区域</string>
<string name="txt_connected">已连接</string> <string name="txt_connected">已连接</string>
<string name="txt_weak_signal">信号弱</string> <string name="txt_weak_signal">信号弱</string>
<string name="txt_battery">电量</string>
<string name="txt_bluetooth">蓝牙</string> <string name="txt_bluetooth">蓝牙</string>
<string name="txt_light">指示灯</string> <string name="txt_light">指示灯</string>
<string name="txt_track_and_points">检查轨迹和地点</string> <string name="txt_track_and_points">检查轨迹和地点</string>
@@ -489,18 +294,6 @@
<string name="txt_october">十月</string> <string name="txt_october">十月</string>
<string name="txt_november">十一月</string> <string name="txt_november">十一月</string>
<string name="txt_december">十二月</string> <string name="txt_december">十二月</string>
<string name="txt_january_abbr">1月</string>
<string name="txt_february_abbr">2月</string>
<string name="txt_march_abbr">3月</string>
<string name="txt_april_abbr">4月</string>
<string name="txt_may_abbr">5月</string>
<string name="txt_june_abbr">6月</string>
<string name="txt_july_abbr">7月</string>
<string name="txt_august_abbr">8月</string>
<string name="txt_september_abbr">9月</string>
<string name="txt_october_abbr">10月</string>
<string name="txt_november_abbr">11月</string>
<string name="txt_december_abbr">12月</string>
<string name="txt_find_device_tips">声音传播速度加快时,距离更近。</string> <string name="txt_find_device_tips">声音传播速度加快时,距离更近。</string>
<string name="txt_stop_radar">停止雷达</string> <string name="txt_stop_radar">停止雷达</string>
<string name="txt_edit_power_zone">编辑WiFi区域</string> <string name="txt_edit_power_zone">编辑WiFi区域</string>
@@ -516,12 +309,9 @@
<string name="txt_add_no_go_zone">添加禁止区域</string> <string name="txt_add_no_go_zone">添加禁止区域</string>
<string name="txt_edit_no_go_zone">编辑禁止区域</string> <string name="txt_edit_no_go_zone">编辑禁止区域</string>
<string name="txt_data_board">数据面板</string> <string name="txt_data_board">数据面板</string>
<string name="txt_minimum">最小值</string>
<string name="txt_recommenced">推荐值</string>
<string name="txt_hr">小时</string> <string name="txt_hr">小时</string>
<string name="txt_fix_daily_goal">设置每日目标</string> <string name="txt_fix_daily_goal">设置每日目标</string>
<string name="txt_awesome_ready_begin">太棒了!开始吧!</string> <string name="txt_awesome_ready_begin">太棒了!开始吧!</string>
<string name="txt_total_activity_distance">活动总距离</string>
<string name="txt_km_small">公里</string> <string name="txt_km_small">公里</string>
<string name="txt_avg_activity_time">日均活动时长</string> <string name="txt_avg_activity_time">日均活动时长</string>
<string name="txt_avg_calories">平均卡路里</string> <string name="txt_avg_calories">平均卡路里</string>
@@ -549,7 +339,6 @@
<string name="txt_minimum_characters">至少6个字符</string> <string name="txt_minimum_characters">至少6个字符</string>
<string name="txt_country">国家/地区</string> <string name="txt_country">国家/地区</string>
<string name="txt_email_address">电子邮箱</string> <string name="txt_email_address">电子邮箱</string>
<string name="txt_welcome_back">欢迎回来</string>
<string name="txt_continue">继续</string> <string name="txt_continue">继续</string>
<string name="txt_otp_verification">验证码</string> <string name="txt_otp_verification">验证码</string>
<string name="txt_sec">秒</string> <string name="txt_sec">秒</string>
@@ -586,15 +375,15 @@
<string name="txt_monthly_subscription">月付</string> <string name="txt_monthly_subscription">月付</string>
<string name="txt_per_month">/月</string> <string name="txt_per_month">/月</string>
<string name="txt_per_year">/年</string> <string name="txt_per_year">/年</string>
<string name="txt_popular">热门</string> <string name="txt_popular">超值</string>
<string name="txt_confirm_plan">确认您的套餐</string> <string name="txt_confirm_plan">确认您的套餐</string>
<string name="txt_device_number">设备编号</string> <string name="txt_device_number">设备编号</string>
<string name="txt_terms_conditions_v2">条款与条件</string> <string name="txt_terms_conditions_v2">条款与条件</string>
<string name="txt_summary">摘要</string> <string name="txt_summary">摘要</string>
<string name="txt_sales_tax">税费</string> <string name="txt_sales_tax">税费</string>
<string name="txt_payment_method">支付方式</string> <string name="txt_payment_method">支付方式</string>
<string name="txt_my_card">我的卡片</string> <string name="txt_choose_card">选择卡片</string>
<string name="txt_no_card">未找到卡片</string> <string name="txt_no_card">没有支付信息</string>
<string name="txt_add_card">添加新卡片</string> <string name="txt_add_card">添加新卡片</string>
<string name="txt_primary">主要支付方式</string> <string name="txt_primary">主要支付方式</string>
<string name="txt_make_payment">立即支付</string> <string name="txt_make_payment">立即支付</string>
@@ -602,18 +391,14 @@
<string name="txt_add_payment">添加支付方式</string> <string name="txt_add_payment">添加支付方式</string>
<string name="txt_save_card">保存新卡片</string> <string name="txt_save_card">保存新卡片</string>
<string name="txt_payment_success">支付成功</string> <string name="txt_payment_success">支付成功</string>
<string name="txt_mm_dd">月/年 (MM/YY)</string>
<string name="txt_cvc">安全码 (CVC)</string>
<string name="txt_accepted_cards">接受的支付卡</string> <string name="txt_accepted_cards">接受的支付卡</string>
<string name="txt_set_primary_card">设为主要卡片</string> <string name="txt_set_primary_card">设为主要卡片</string>
<string name="txt_name_card">持卡人姓名</string> <string name="txt_name_card">持卡人姓名</string>
<string name="txt_permissions">权限</string> <string name="txt_permissions">权限</string>
<string name="txt_skip">跳过</string> <string name="txt_skip">跳过</string>
<string name="txt_enable">启用</string>
<string name="txt_grant_permissions">授予权限以提升体验。</string> <string name="txt_grant_permissions">授予权限以提升体验。</string>
<string name="txt_tracker_id">设备ID</string> <string name="txt_tracker_id">设备ID</string>
<string name="txt_plan">套餐:</string> <string name="txt_plan">套餐:</string>
<string name="txt_renews_on">续订日期:</string> <string name="txt_renews_on">续订日期:</string>
<string name="txt_power_saving_zone_tip">添加常驻地可提升电池续航并提供额外安全保障</string> <string name="txt_power_saving_zone_tip">添加常驻地可提升电池续航并提供额外安全保障</string>
<string name="txt_power_saving_zone">建立WiFi区域</string> <string name="txt_power_saving_zone">建立WiFi区域</string>
@@ -629,7 +414,6 @@
<string name="txt_about_power_saving_zone">关于WiFi区域</string> <string name="txt_about_power_saving_zone">关于WiFi区域</string>
<string name="txt_office_tip">在您宠物常驻地(如家中)选择一个网络。一旦进入覆盖范围,您的设备将识别此网络为WiFi区域。</string> <string name="txt_office_tip">在您宠物常驻地(如家中)选择一个网络。一旦进入覆盖范围,您的设备将识别此网络为WiFi区域。</string>
<string name="txt_office">办公室</string> <string name="txt_office">办公室</string>
<string name="txt_save_power_tip">只要设备检测到您的爱宠处于WiFi区域内,就会关闭实时追踪以延长电池续航。</string>
<string name="txt_save_power">省电模式</string> <string name="txt_save_power">省电模式</string>
<string name="txt_tracking_pet_tip">在蓝牙范围内?可使用雷达精确定位附近y设备。实时追踪也将可用,但使用它会结束省电模式。</string> <string name="txt_tracking_pet_tip">在蓝牙范围内?可使用雷达精确定位附近y设备。实时追踪也将可用,但使用它会结束省电模式。</string>
<string name="txt_tracking_pet">正在追踪您的宠物</string> <string name="txt_tracking_pet">正在追踪您的宠物</string>
@@ -654,30 +438,22 @@
<string name="txt_to_abbidot">发送至ABBIDOT</string> <string name="txt_to_abbidot">发送至ABBIDOT</string>
<string name="txt_password_no_same">输入的密码不一致!</string> <string name="txt_password_no_same">输入的密码不一致!</string>
<string name="txt_no_member_yet">尚无成员</string> <string name="txt_no_member_yet">尚无成员</string>
<string name="txt_invite_new">+邀请</string>
<string name="txt_invite_members">邀请成员</string> <string name="txt_invite_members">邀请成员</string>
<string name="txt_home">家</string> <string name="txt_home">家</string>
<string name="txt_live_duration">直播时长</string> <string name="txt_live_duration">直播时长</string>
<string name="txt_about_live_duration">关于直播时长</string> <string name="txt_about_live_duration">关于直播时长</string>
<string name="txt_keep_short_dec">直播模式可帮助寻找宠物,每2~3秒更新一次位置,但会消耗更多电量。默认追踪仍会提供常规更新。</string> <string name="txt_keep_short_dec">直播模式可帮助寻找宠物,每2~3秒更新一次位置,但会消耗更多电量。默认追踪仍会提供常规更新。</string>
<string name="txt_stop_live_dec">直播将在设定的时长结束时停止,但您也可以提前停止以节省电量。</string> <string name="txt_stop_live_dec">直播将在设定的时长结束时停止,但您也可以提前停止以节省电量。</string>
<string name="txt_keep_it_short">请尽量缩短时长</string> <string name="txt_keep_it_short">请尽量缩短时长</string>
<string name="txt_bluetooth_enabled">蓝牙</string>
<string name="txt_location_enabled">GPS 位置</string> <string name="txt_location_enabled">GPS 位置</string>
<string name="txt_receive_notice">接收通知</string> <string name="txt_receive_notice">接收通知</string>
<string name="txt_turn_on_upper">开启</string> <string name="txt_turn_on_upper">开启</string>
<string name="txt_activated_tips">设备未激活。请订阅后激活。</string> <string name="txt_activated_tips">设备未激活。请订阅后激活。</string>
<string name="txt_search_device">正在搜索…</string>
<string name="txt_no_search_device">请保持设备开机并靠近扫描。</string> <string name="txt_no_search_device">请保持设备开机并靠近扫描。</string>
<string name="txt_outside">区域外</string> <string name="txt_outside">区域外</string>
<string name="txt_inside">区域内</string> <string name="txt_inside">区域内</string>
<string name="txt_7days_avg">7日均值</string>
<string name="txt_created_many_fences">创建的围栏太多了</string> <string name="txt_created_many_fences">创建的围栏太多了</string>
<string name="txt_live_ended">直播已结束。直播时长可通过“直播时长”设置。</string> <string name="txt_live_ended">直播已结束。直播时长可通过“直播时长”设置。</string>
<string name="txt_weak_gps_signal">GPS信号弱</string>
<string name="map_current_no_signal">无网络信号</string>
<string name="txt_tracker_power_off">设备已关机</string> <string name="txt_tracker_power_off">设备已关机</string>
<string name="txt_starting_live">正在启动直播…</string> <string name="txt_starting_live">正在启动直播…</string>
<string name="txt_con_network">正在连接网络</string> <string name="txt_con_network">正在连接网络</string>
@@ -690,14 +466,11 @@
<string name="txt_about_live_tip">直播将在一小时后停止,但您也可以提前停止以节省电量。</string> <string name="txt_about_live_tip">直播将在一小时后停止,但您也可以提前停止以节省电量。</string>
<string name="txt_resting">休息中</string> <string name="txt_resting">休息中</string>
<string name="txt_resting_time">休息时长</string> <string name="txt_resting_time">休息时长</string>
<string name="txt_resting_time_uppercase">休息时间</string>
<string name="txt_no_signal">无信号</string> <string name="txt_no_signal">无信号</string>
<string name="txt_wifi">WiFi</string> <string name="txt_wifi">WiFi</string>
<string name="txt_set_measurement_units">选择计量单位</string> <string name="txt_set_measurement_units">选择计量单位</string>
<string name="txt_metric">公制 (厘米, 千克) </string> <string name="txt_metric">公制 (厘米, 千克)</string>
<string name="txt_imperial">英制 (英寸, 磅)</string> <string name="txt_imperial">英制 (英寸, 磅)</string>
<string name="txt_km_h">公里/小时 (km/h)</string>
<string name="txt_mph">英里/小时 (mph)</string>
<string name="txt_m">米 (m)</string> <string name="txt_m">米 (m)</string>
<string name="txt_ft">英尺 (ft)</string> <string name="txt_ft">英尺 (ft)</string>
<string name="txt_fences_alerts">围栏告警</string> <string name="txt_fences_alerts">围栏告警</string>
@@ -715,7 +488,7 @@
<string name="txt_yesterday">昨天</string> <string name="txt_yesterday">昨天</string>
<string name="txt_power_on_off">开机/关机</string> <string name="txt_power_on_off">开机/关机</string>
<string name="txt_power_on_off_tip">充电后拔掉电源即可开机。 \n绿灯闪烁 = 已开机。</string> <string name="txt_power_on_off_tip">充电后拔掉电源即可开机。 \n绿灯闪烁 = 已开机。</string>
<string name="txt_active_tracker_tip">选择一个订阅 \n点击以激活追踪器 \n启用GPS和蜂窝网络追踪。</string> <string name="txt_active_tracker_tip">1. 选择一个订阅.\n2. 点击以激活追踪器 \n3. 启用GPS和蜂窝网络追踪。</string>
<string name="txt_active_tracker">激活追踪器</string> <string name="txt_active_tracker">激活追踪器</string>
<string name="txt_check_tracker_status_tip">(GPS和移动网络状态可能因环境而异。在给宠物佩戴前,请检查您周围的不同位置以评估GPS和网络状态。)</string> <string name="txt_check_tracker_status_tip">(GPS和移动网络状态可能因环境而异。在给宠物佩戴前,请检查您周围的不同位置以评估GPS和网络状态。)</string>
<string name="txt_check_tracker_status">检查设备状态</string> <string name="txt_check_tracker_status">检查设备状态</string>
@@ -723,7 +496,6 @@
<string name="txt_tracker_battery_tip2">将设备连接到家庭WiFi(无需密码)。在WiFi区域内,GPS将停止工作。每10-60分钟连接一次网络,功耗极低。</string> <string name="txt_tracker_battery_tip2">将设备连接到家庭WiFi(无需密码)。在WiFi区域内,GPS将停止工作。每10-60分钟连接一次网络,功耗极低。</string>
<string name="txt_tracker_battery_tip3">当您的追踪器在WiFi区域外时,它会激活GPS并每3/5/10/15分钟连接一次网络。</string> <string name="txt_tracker_battery_tip3">当您的追踪器在WiFi区域外时,它会激活GPS并每3/5/10/15分钟连接一次网络。</string>
<string name="txt_tracker_battery_life">设备电池续航</string> <string name="txt_tracker_battery_life">设备电池续航</string>
<string name="txt_create_fence_tip1">前往“宠物” > “我的宠物围栏” > “管理” > “+ 新增”</string>
<string name="txt_create_fence_tip2">定义边界:在地图上选择一个位置,调整围栏的半径或形状。</string> <string name="txt_create_fence_tip2">定义边界:在地图上选择一个位置,调整围栏的半径或形状。</string>
<string name="txt_create_fence_tip3">当宠物进入或离开区域时发出警报。</string> <string name="txt_create_fence_tip3">当宠物进入或离开区域时发出警报。</string>
<string name="txt_create_pet_fence">创建宠物围栏</string> <string name="txt_create_pet_fence">创建宠物围栏</string>
@@ -780,14 +552,11 @@
<string name="txt_how_to_get">如何获取?</string> <string name="txt_how_to_get">如何获取?</string>
<string name="txt_family_invitation">邀请家人</string> <string name="txt_family_invitation">邀请家人</string>
<string name="txt_active_time1">活跃时长:</string> <string name="txt_active_time1">活跃时长:</string>
<string name="txt_expires_on1">有效期至:</string> <string name="txt_expires_on1">有效期至:</string>
<string name="txt_expires_on2">过期于:</string> <string name="txt_expires_on2">过期于:</string>
<string name="txt_years">年</string> <string name="txt_years">年</string>
<string name="txt_mouths">月</string> <string name="txt_mouths">月</string>
<string name="txt_days">天</string>
<string name="txt_subscription_history">订阅订单</string> <string name="txt_subscription_history">订阅订单</string>
<string name="txt_order_id">订单号:</string> <string name="txt_order_id">订单号:</string>
<string name="txt_request_refund_dec">请输入您的退款原因</string> <string name="txt_request_refund_dec">请输入您的退款原因</string>
@@ -796,8 +565,9 @@
<string name="txt_waiting">等待处理</string> <string name="txt_waiting">等待处理</string>
<string name="txt_refunding">退款中</string> <string name="txt_refunding">退款中</string>
<string name="txt_refunded">已退款</string> <string name="txt_refunded">已退款</string>
<string name="txt_renewal_year2">/年,于</string>
<string name="txt_renewal_month2">/月,于</string>
<string name="txt_replace_guarantee">换新保障</string>
<string name="txt_annual_care_text">年度护理</string> <string name="txt_annual_care_text">年度护理</string>
<string name="txt_annual_care_text1">年度护理:</string> <string name="txt_annual_care_text1">年度护理:</string>
<string name="txt_led_light_set">LED灯设置</string> <string name="txt_led_light_set">LED灯设置</string>
@@ -846,31 +616,20 @@
<string name="txt_account_exists_log_in">账户已存在。立即登录?</string> <string name="txt_account_exists_log_in">账户已存在。立即登录?</string>
<string name="txt_time_out_of_range">所选日期超出范围</string> <string name="txt_time_out_of_range">所选日期超出范围</string>
<string name="txt_power_on_off_install_tip">摇一摇开机 \n绿灯闪烁表示已开机。</string> <string name="txt_power_on_off_install_tip">摇一摇开机 \n绿灯闪烁表示已开机。</string>
<string name="txt_check_tracker_status_top_tip">前往“宠物 > 追踪器” \n检查:网络、GPS、电池、WiFi、区域、蓝牙、LED。 \nGPS和蜂窝网络信号可能因位置而异。使用前请在不同位置进行测试。</string> <string name="txt_check_tracker_status_top_tip">GPS 和蜂窝网络信号可能因位置而异。\n使用前,请在不同位置进行测试。</string>
<string name="txt_on_charging">设备充电中</string> <string name="txt_on_charging">设备充电中</string>
<string name="txt_active_subscribed">已订阅</string> <string name="txt_active_subscribed">已订阅</string>
<string name="map_baidu_map">百度地图</string> <string name="map_baidu_map">百度地图</string>
<string name="txt_send">发送</string> <string name="txt_send">发送</string>
<string name="txt_turn_on_power">首次开机请连接电源线。之后可通过摇动开机。</string> <string name="txt_turn_on_power">首次开机请连接电源线。之后可通过摇动开机。</string>
<string name="txt_1_year_subscription">1年订阅</string>
<string name="txt_2_year_subscription">2年订阅</string>
<string name="txt_3_year_subscription">3年订阅</string>
<string name="txt_as_low_as">低至</string> <string name="txt_as_low_as">低至</string>
<string name="txt_payment_manager">支付管理</string> <string name="txt_payment_manager">支付管理</string>
<string name="txt_billed_annually">按年计费</string>
<string name="txt_basic_plan">基础计划</string> <string name="txt_basic_plan">基础计划</string>
<string name="txt_premium_plan">高级计划</string> <string name="txt_premium_plan">高级计划</string>
<string name="txt_real_time_tracking">实时追踪</string>
<string name="txt_activity_logs">活动/休息</string>
<string name="txt_notifications_emergencies">告警日志</string>
<string name="txt_customized_led">自定义LED灯</string> <string name="txt_customized_led">自定义LED灯</string>
<string name="txt_geofencing">电子围栏</string> <string name="txt_geofencing">电子围栏</string>
<string name="txt_route_records">路线历史记录</string> <string name="txt_route_records">路线历史记录</string>
<string name="txt_family_sharing">家庭成员共享</string>
<string name="txt_customer_support">30天退款保证</string>
<string name="txt_show_crash">程序出现异常,即将退出</string>
<string name="txt_activate_subscribe">激活订阅</string> <string name="txt_activate_subscribe">激活订阅</string>
<string name="txt_powered_off">已关机</string>
<string name="txt_charging">充电中</string> <string name="txt_charging">充电中</string>
<string name="txt_total_time">总时间</string> <string name="txt_total_time">总时间</string>
<string name="txt_live_works_cellular">直播仅限移动网络</string> <string name="txt_live_works_cellular">直播仅限移动网络</string>
@@ -886,8 +645,6 @@
<string name="txt_tone">提示音</string> <string name="txt_tone">提示音</string>
<string name="txt_locate_works">定位仅适用于移动网络</string> <string name="txt_locate_works">定位仅适用于移动网络</string>
<string name="txt_pet_close">宠物在附近,请尝试雷达</string> <string name="txt_pet_close">宠物在附近,请尝试雷达</string>
<string name="txt_load_more_pull_text">下拉加载更多</string>
<string name="txt_load_more_release_text">释放加载</string>
<string name="txt_fully_charged">已充满电</string> <string name="txt_fully_charged">已充满电</string>
<string name="txt_time_line">时间线</string> <string name="txt_time_line">时间线</string>
<string name="txt_phone_close_device">保持手机靠近设备</string> <string name="txt_phone_close_device">保持手机靠近设备</string>
@@ -896,26 +653,292 @@
<string name="txt_first_use">首次使用</string> <string name="txt_first_use">首次使用</string>
<string name="txt_daily_use">日常使用</string> <string name="txt_daily_use">日常使用</string>
<string name="txt_sleep_mode">休眠模式</string> <string name="txt_sleep_mode">休眠模式</string>
<string name="txt_sleep_mode_help">15分钟无移动 → 进入休眠模式。 \n移动时自动唤醒。 \n电量每24小时更新一次</string> <string name="txt_sleep_mode_help">1. 15分钟无移动 → 进入休眠模式; \n2. 移动时自动唤醒; \n3. 电量每24小时更新一次。</string>
<string name="txt_wifi_zone_home">WiFi区域(家)</string> <string name="txt_wifi_zone_home">WiFi区域(家)</string>
<string name="txt_wifi_zone_home_help">连接家庭WiFi \n GPS关闭 → 节省电池。\n约每60分钟更新一次</string> <string name="txt_wifi_zone_home_help">1. 连接家庭WiFi; \n2. GPS关闭 → 节省电池;\n3. 约每60分钟更新一次。</string>
<string name="txt_gps_update_help">宠物 > 追踪器 > GPS更新 \n选择3–15分钟。 \n间隔越短,耗电越高。 \n默认:5分钟</string> <string name="txt_gps_update_help">1. 选择 3–15 分钟。\n\n2. 间隔越短,耗电越高。\n\n3. 默认:5 分钟。</string>
<string name="txt_set_fence_type">设置围栏类型</string> <string name="txt_set_fence_type">设置围栏类型</string>
<string name="txt_fence_type_help">安全区域 或 禁止区</string> <string name="txt_fence_type_help">安全区域 或 禁止区</string>
<string name="txt_set_boundary">设置边界</string> <string name="txt_set_boundary">设置边界</string>
<string name="txt_enable_set_notify">在“账户 > 设置 > 通知”中启用提醒</string> <string name="txt_enable_set_notify">在“账户 > 设置 > 通知”中启用提醒</string>
<string name="txt_edit_delete_fence">在“管理”中编辑或删除围栏</string> <string name="txt_edit_delete_fence">在“管理”中编辑或删除围栏</string>
<string name="txt_total">总计</string>
<string name="txt_init_device">正在初始化设备</string> <string name="txt_init_device">正在初始化设备</string>
<string name="txt_add_wifi_tips">添加wifi区域可延长使用时长</string> <string name="txt_add_wifi_tips">添加wifi区域可延长使用时长</string>
<string name="txt_add">去添加</string> <string name="txt_add">去添加</string>
<string name="txt_already_min_size">已是最小尺寸</string> <string name="txt_already_min_size">已是最小尺寸</string>
<string name="txt_3_months_subscription">3个月灵活套餐</string>
<string name="txt_1_year_subscription">1年Plus套餐</string>
<string name="txt_2_years_subscription">2年Protection+套餐</string>
<string name="txt_billed_quarterly">按季度计费</string>
<string name="txt_billed_annually">按年计费</string>
<string name="txt_billed_every_2_years">每两年计费</string>
<string name="txt_login_with">使用以下方式登录</string>
<string name="txt_my_card">我的卡片</string>
<string name="txt_edit_my_card">编辑支付信息</string>
<string name="txt_phone_has_bound">该手机号码已被绑定</string>
<string name="txt_go_to">前往</string>
<string name="txt_pet_tracker">宠物 > 定位器</string>
<string name="txt_pet_tracker_gps">宠物 > 定位器 > GPS 更新</string>
<string name="txt_pet_fence_add">宠物 > 我的宠物围栏 > 管理 > + 新增</string>
<string name="txt_check">检查:</string>
<string name="txt_help_status_network">· 网络\n· WiFi Zone\n· GPS</string>
<string name="txt_help_status_bluetooth">· 蓝牙\n· 电量\n· LED</string>
<string name="register_txt_policy">《隐私政策》</string>
<string name="txt_expires_on">过期于</string>
<string name="map_navigate_map_google">谷歌地图</string>
<string name="txt_upgrade_success">升级成功</string>
<string name="txt_upgrade_fail">升级失败</string>
<string name="txt_please_enter_email">请输入邮箱。</string>
<string name="tracker_enter_id">输入设备ID</string>
<string name="txt_no_signal_tip">无信号。请检查宠物是否在室内。</string>
<string name="txt_recommenced">推荐值</string>
<string name="txt_expiry_time">到期时间:</string>
<string name="txt_activity_logs">活动/休息</string>
<string name="txt_real_time_tracking">实时追踪</string>
<string name="register_txt_noreceive">还没有收到验证码?</string>
<string name="pet_managet_age_1">%d年</string>
<string name="pet_manage_detail_earned">%d/100 已获得</string>
<string name="map_current_update_time">更新时间:%s</string>
<string name="txt_show_track_point">显示轨迹/点</string>
<string name="txt_share_pet_tips">确定要分享\'%s\'的宠物数据</string>
<string name="select_puzzle_photos">请选择2 \~ 9张照片</string>
<string name="txt_pay_amount_detail1">此后以%.2f/年续订,可随时取消</string>
<string name="txt_pay_order_off">已优惠%d</string>
<string name="txt_pay_order_detail_sub_on">订阅计划有效期至%s</string>
<string name="txt_pay_order_detail_sub_off">自动续订已关闭,订阅计划将在%s之后不可用</string>
<string name="txt_confirm_save_card">保存并确认</string>
<string name="txt_perMonth">$%s/月</string>
<string name="txt_congratulations_tip">宠物信息设置成功,获得安全徽章!</string>
<string name="txt_add_tracker_tip2">设备已被绑定,请核对后重试</string>
<string name="txt_ft_unit">%s英尺 (ft)</string>
<string name="txt_mph_unit">%s英里/小时 (mph)</string>
<string name="txt_family_delete">您确定要删除家庭成员%s</string>
<string name="txt_create_fence_tip4">开启通知:前往“账户” > \"设置\"。点击\"通知\"并开启。</string>
<string name="txt_month_unit">/月 x%s</string>
<string name="txt_year_unit">/%s 年</string>
<string name="txt_card_list_end">截止至%s</string>
<string name="txt_legal_info_content">欢迎使用爱彼宠物!为了更好地保障您的权益,我们将在本《隐私政策》声明中向您说明我们如何收集、使用、处理和保障您提供给我们的信息。请仔细阅读《隐私政策》和《服务条款》。</string>
<string name="login_txt_phone">手机号</string>
<string name="login_txt_login_wechat">微信登录</string>
<string name="login_txt_login_code">验证码登录</string>
<string name="login_txt_login_apple">Apple登录</string>
<string name="login_txt_login_account">账号登录</string>
<string name="txt_set_new_password">设置新密码</string>
<string name="txt_code_success">验证码已发送</string>
<string name="login_txt_login_password">密码登录</string>
<string name="register_txt_hey">嗨,</string>
<string name="register_txt_set_password">设置密码</string>
<string name="register_txt_get_code">获取</string>
<string name="register_txt_sented_code">我们已将验证码发送到您的电子邮件</string>
<string name="register_txt_verification">验证码</string>
<string name="register_txt_agree1">请阅读并同意</string>
<string name="register_txt_agree2">和</string>
<string name="register_txt_terms">《服务协议》</string>
<string name="register_txt_bind_phone">绑定</string>
<string name="login_txt_login_finish">完成</string>
<string name="system_txt_data">数据</string>
<string name="txt_my_orders">我的订单</string>
<string name="txt_help_center">帮助中心</string>
<string name="txt_feedback">反馈中心</string>
<string name="txt_setting_title">设置</string>
<string name="txt_setting_language">语言</string>
<string name="txt_setting_logout">退出登录</string>
<string name="txt_feedback_notype">请选择问题类型</string>
<string name="acccount_gender">性别</string>
<string name="acccount_location">地点</string>
<string name="acccount_phone">手机</string>
<string name="acccount_breed">品种</string>
<string name="tracker_activate_cancel">激活并继续</string>
<string name="tracker_activate_yes">激活</string>
<string name="tracker_manage_title">设备</string>
<string name="tracker_manage_mine">我的设备</string>
<string name="tracker_manage_authorized">被授权的</string>
<string name="tracker_manage_fence">围栏</string>
<string name="tracker_manage_set">设置</string>
<string name="tracker_manage_set_card_day">天</string>
<string name="tracker_manage_set_led">LED灯</string>
<string name="tracker_manage_set_Fence">围栏</string>
<string name="tracker_manage_set_family">家人</string>
<string name="tracker_manage_set_add_family">添加家人</string>
<string name="tracker_manage_set_add_family_detail">邀请您的家人分享宠物的位置或活动。 家庭成员不能创建围栏或修改设置。</string>
<string name="tracker_manage_set_add_family_back">返回</string>
<string name="tracker_manage_set_power">关机</string>
<string name="pet_manage_detail_title2">活动勋章</string>
<string name="map_navigate_select_map">选择地图</string>
<string name="map_navigate_map_gaode">高德地图</string>
<string name="txt_no_install">APP未安装,请先下载安装</string>
<string name="txt_add_successful">添加成功</string>
<string name="txt_delete_success">成功删除</string>
<string name="txt_unbind_tips">确定要解绑设备?</string>
<string name="txt_unbind_success">解绑成功</string>
<string name="txt_bind_success">绑定成功</string>
<string name="txt_distance_unit">英里</string>
<string name="txt_calorie_unit">大卡</string>
<string name="txt_device_renewal">您的设备已过期,请充值</string>
<string name="txt_load_map">地图加载中&#8230;</string>
<string name="hello_blank_fragment">你好,空白片段</string>
<string name="selector_folder_all_video_photo_easy_photos">图片和视频</string>
<string name="selector_easy_photos">选择</string>
<string name="selector_preview_easy_photos">预览</string>
<string name="selector_single_type_hint_easy_photos">只能选择一种类型的文件</string>
<string name="msg_no_camera_easy_photos">无法启动相机</string>
<string name="camera_temp_file_error_easy_photos">图片错误</string>
<string name="selector_image_type_error_easy_photos">不支持该图像格式</string>
<string name="empty_easy_photos">清除</string>
<string name="no_photos_easy_photos">没有匹配的照片</string>
<string name="no_videos_easy_photos">没有匹配的视频</string>
<string name="original_easy_photos">原始</string>
<string name="done_easy_photos">完成</string>
<string name="cancel_easy_photos">取消</string>
<string name="template_easy_photos">模板</string>
<string name="text_sticker_easy_photos">文本</string>
<string name="text_sticker_date_easy_photos">日期</string>
<string name="text_sticker_hint_easy_photos">双击编辑</string>
<string name="text_sticker_hint_name_easy_photos">自定义</string>
<string name="picture_selection_easy_photos">选择照片</string>
<string name="gif_easy_photos">GIF</string>
<string name="txt_pay_order_add_card">添加新卡</string>
<string name="txt_pay_order_payment_title">支付详情</string>
<string name="txt_pay_order_detail_plan">订阅计划:</string>
<string name="txt_firmware_upgrade">固件升级</string>
<string name="txt_feedback_success">提交成功</string>
<string name="txt_clear_cache_success">清除成功</string>
<string name="txt_token_overdue">登录失败,请重新登录</string>
<string name="txt_cardholder_name">持卡人姓名</string>
<string name="card_holder">持卡人</string>
<string name="expiry">截止日期</string>
<string name="txt_card_validity_format">失效日期</string>
<string name="txt_card_number_format">信用卡格式无效</string>
<string name="txt_turnoff_tips">您确定要关闭设备吗?</string>
<string name="txt_crop">裁剪图片</string>
<string name="txt_exit_return">再次返回退出程序</string>
<string name="txt_register_fail">注册失败</string>
<string name="txt_email_format_error">邮箱格式不对</string>
<string name="txt_disconnect_tips">是否断开连接设备?</string>
<string name="txt_connect_success">连接成功</string>
<string name="txt_connect_fail">连接失败</string>
<string name="txt_register_phone">请输入手机号</string>
<string name="txt_about_app_name">爱彼宠物</string>
<string name="txt_change_pwd">修改密码</string>
<string name="txt_cancel_pay">取消支付</string>
<string name="txt_device_has_bound">当前用户已经绑定该设备</string>
<string name="txt_first_name">姓</string>
<string name="txt_last_name">名</string>
<string name="txt_legal_info_title">法律信息</string>
<string name="txt_accept">我接受</string>
<string name="txt_deny">拒绝</string>
<string name="txt_no_down_url">没有下载地址</string>
<string name="txt_please_wait">请稍等&#8230;</string>
<string name="txt_release_notes">版本说明</string>
<string name="txt_firmware_name">固件名称</string>
<string name="txt_firmware_size">固件大小</string>
<string name="txt_down_firmware">下载固件</string>
<string name="txt_dfu_model">进入DFU模式</string>
<string name="txt_search_dfu">搜索DUF设备</string>
<string name="txt_connect_device">连接设备</string>
<string name="txt_reconnect_device">重连设备</string>
<string name="txt_unconnect">设备已断开</string>
<string name="txt_upgrading">升级中</string>
<string name="txt_upgrade_start">准备升级</string>
<string name="txt_device_connect_success">设备连接成功</string>
<string name="txt_battery">电量</string>
<string name="txt_january_abbr">1月</string>
<string name="txt_february_abbr">2月</string>
<string name="txt_march_abbr">3月</string>
<string name="txt_april_abbr">4月</string>
<string name="txt_may_abbr">5月</string>
<string name="txt_june_abbr">6月</string>
<string name="txt_july_abbr">7月</string>
<string name="txt_august_abbr">8月</string>
<string name="txt_september_abbr">9月</string>
<string name="txt_october_abbr">10月</string>
<string name="txt_november_abbr">11月</string>
<string name="txt_december_abbr">12月</string>
<string name="txt_minimum">最小值</string>
<string name="txt_total_activity_distance">活动总距离</string>
<string name="txt_welcome_back">欢迎回来</string>
<string name="txt_mm_dd">月/年 (MM/YY)</string>
<string name="txt_cvc">安全码 (CVC)</string>
<string name="txt_enable">启用</string>
<string name="txt_renew_year2">/年)</string>
<string name="txt_save_power_tip">只要设备检测到您的爱宠处于WiFi区域内,就会关闭实时追踪以延长电池续航。</string>
<string name="txt_invite_new">+邀请</string>
<string name="txt_delete_pet_data1">这将从您的账户中永久删除所有</string>
<string name="txt_delete_pet_data2">数据</string>
<string name="txt_bluetooth_enabled">蓝牙</string>
<string name="txt_search_device">正在搜索…</string>
<string name="txt_7days_avg">7日均值</string>
<string name="txt_weak_gps_signal">GPS信号弱</string>
<string name="map_current_no_signal">无网络信号</string>
<string name="txt_resting_time_uppercase">休息时间</string>
<string name="txt_km_h">公里/小时 (km/h)</string>
<string name="txt_mph">英里/小时 (mph)</string>
<string name="txt_family_invitation_dec1">您的朋友</string>
<string name="txt_family_invitation_dec2">邀请您成为</string>
<string name="txt_family_invitation_dec3">的家人。</string>
<string name="txt_auto_renew1">自动续费</string>
<string name="txt_renewal_month1">续费:</string>
<string name="txt_notifications_emergencies">告警日志</string>
<string name="txt_family_sharing">家庭成员共享</string>
<string name="txt_customer_support">30天退款保证</string>
<string name="txt_show_crash">程序出现异常,即将退出</string>
<string name="txt_powered_off">已关机</string>
<string name="txt_load_more_pull_text">下拉加载更多</string>
<string name="txt_load_more_release_text">释放加载</string>
<string name="txt_total">总计</string>
<string name="txt_show_all_pet">显示所有宠物</string> <string name="txt_show_all_pet">显示所有宠物</string>
<string name="txt_use_valid_phone">请使用有效的手机号码</string> <string name="txt_use_valid_phone">请输入有效的电话号码</string>
<string name="txt_account">账户</string> <string name="txt_account">账户</string>
<string name="txt_3_months_includes">1. 灵活短期保障\n\n2. 30天退款保证</string>
<string name="txt_1_year_includes">1. 专属客户支持\n\n2. 全年保障\n\n3. 30天退款保证</string>
<string name="txt_2_years_includes">1. 免费设备更换(1次)\n\n2. 增强保障\n\n3. 宠物无忧保障\n\n4. 30天退款保证</string>
<string name="tracker_number">%d个设备</string>
<string name="pet_number">%d只</string>
<string name="pet_manage_height">%d 英寸</string>
<string name="txt_permissions_fail_tips">未能获得许可</string>
<string name="no_pet">无宠物</string>
<string name="no_bind_pet">请先绑定宠物</string>
<string name="txt_battery_unit">%d%%</string>
<string name="txt_pet_birthdayDate">%d年%d月</string>
<string name="selector_folder_video_easy_photos">全部视频</string>
<string name="selector_action_done_easy_photos">完成(%1$d/%2$d)</string>
<string name="selector_reach_max_hint_easy_photos">最多支持%d个图片或视频</string>
<string name="selector_reach_max_image_hint_easy_photos">最多支持%d个图片</string>
<string name="selector_reach_max_video_hint_easy_photos">最多支持%d个视频</string>
<string name="selector_image_size_error_easy_photos">照片的宽度应大于%1$d,高度应大于%1$d</string>
<string name="permissions_again_easy_photos">请允许相关权限</string>
<string name="permissions_die_easy_photos">请允许相关权限</string>
<string name="preview_current_number_easy_photos">%1$d/%2$d</string>
<string name="txt_today_date">今天\t%s</string>
<string name="video_selection_easy_photos">选择视频</string>
<string name="txt_dollar">¥\t%.2f</string>
<string name="txt_goal_percent">%s%%</string>
<string name="txt_reset_password_tips">输入您档案的注册邮箱,我们将发送4位数验证码至该邮箱</string>
<string name="txt_money_unit">$%s</string>
<string name="txt_per_month_money">$%s/月</string>
<string name="txt_per_year_money">$%s/年</string>
<string name="txt_delete_pet_data">这将从您的账户中永久删除所有 %s 数据</string>
<string name="txt_renew_year">(按每年 $%s 续订)</string>
<string name="txt_activity_success">激活成功!</string>
<string name="txt_start_min_live">正在启动 %s-分钟直播</string>
<string name="txt_code_valid_min">验证码有效期为 %ss</string>
<string name="txt_family_invitation_dec">您的朋友 %s 邀请您成为 %s 的家人。</string>
<string name="txt_renewal_year">续费:$%s/年,于%s</string>
<string name="txt_renewal_month">续费:$%s/月,于%s</string>
<string name="txt_annual_care">年度保险</string>
<string name="txt_auto_subscription_year">(此后按每年 $%s 续订)</string>
<string name="txt_auto_subscription_month">(此后按每月 $%s 续订)</string>
<string name="txt_fail">失败</string>
<string name="txt_edit_pay_method">编辑付款方式</string>
<string name="txt_please_enter_pws">请输入密码。</string>
<string name="txt_location_tip">ABBIDOT应用收集位置数据,可计算当前位置与设备之间的路线和距离。</string>
<string name="txt_auto_subscription_day">(之后按$%s每天续费)</string>
<string name="txt_auto_subscription_days">(之后按$%s/%s天续费)</string>
<string name="txt_auto_subscription_years">(之后按$%s/%s年续费)</string>
<string name="txt_auto_subscription_months">(之后按$%s/%s月续费)</string>
<string name="txt_renewal_years">续订:$%s / %s 年,于 %s</string>
<string name="txt_renewal_months">续订:$%s / %s 月,于 %s</string>
<string name="txt_terms_html">terms_zh.html</string> <string name="txt_terms_html">terms_zh.html</string>
<string name="txt_privacy_html">privacy_zh.html</string> <string name="txt_privacy_html">privacy_zh.html</string>
<string name="txt_subscription_terms_conditions_html">subscription_terms_conditions_zh.html</string> <string name="txt_subscription_terms_conditions_html">subscription_terms_conditions_zh.html</string>
<string name="txt_phone_has_bound">该手机号码已被绑定</string>
</resources> </resources>

File diff suppressed because it is too large Load Diff

View File

@@ -35,7 +35,7 @@ import androidx.annotation.StringDef
EventName.LiveAutoEnd, EventName.LiveAutoEnd,
EventName.LiveOpenTimeOut, EventName.LiveOpenTimeOut,
EventName.SetGoal, EventName.SetGoal,
EventName.RefreshMessage, EventName.LocationData,
EventName.BluetoothSwitch, EventName.BluetoothSwitch,
EventName.PostValue, EventName.PostValue,
EventName.BleReport, EventName.BleReport,
@@ -54,7 +54,7 @@ annotation class EventName {
const val UpdateUserInfo = "updateUserInfo" const val UpdateUserInfo = "updateUserInfo"
const val UpdateData = "updateData" const val UpdateData = "updateData"
const val RefreshFences = "refreshFences" const val RefreshFences = "refreshFences"
const val RefreshMessage = "refreshMessage" const val LocationData = "locationData"
const val DeleteFences = "deleteFences" const val DeleteFences = "deleteFences"
const val RefreshDevice = "refreshDevice" const val RefreshDevice = "refreshDevice"
const val DeleteDevice = "deleteDevice" const val DeleteDevice = "deleteDevice"

View File

@@ -94,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)) {
//只启用谷歌地图 //只启用谷歌地图