package com.xw.yunwei.ui.work.checkInMission
|
|
import android.os.Bundle
|
import android.util.Log
|
import android.view.View
|
import androidx.core.os.bundleOf
|
import com.amap.api.maps.AMap
|
import com.amap.api.maps.CameraUpdateFactory
|
import com.amap.api.maps.model.BitmapDescriptorFactory
|
import com.amap.api.maps.model.CameraPosition
|
import com.amap.api.maps.model.LatLng
|
import com.amap.api.maps.model.MarkerOptions
|
import com.amap.api.navi.AMapNavi
|
import com.amap.api.navi.AMapNaviListener
|
import com.amap.api.navi.TTSPlayListener
|
import com.amap.api.navi.enums.NaviType
|
import com.amap.api.navi.enums.TransportType
|
import com.amap.api.navi.enums.TravelStrategy
|
import com.amap.api.navi.model.AMapCalcRouteResult
|
import com.amap.api.navi.model.AMapLaneInfo
|
import com.amap.api.navi.model.AMapModelCross
|
import com.amap.api.navi.model.AMapNaviCameraInfo
|
import com.amap.api.navi.model.AMapNaviCross
|
import com.amap.api.navi.model.AMapNaviLocation
|
import com.amap.api.navi.model.AMapNaviRouteNotifyData
|
import com.amap.api.navi.model.AMapNaviTrafficFacilityInfo
|
import com.amap.api.navi.model.AMapServiceAreaInfo
|
import com.amap.api.navi.model.AMapTravelInfo
|
import com.amap.api.navi.model.AimLessModeCongestionInfo
|
import com.amap.api.navi.model.AimLessModeStat
|
import com.amap.api.navi.model.NaviInfo
|
import com.amap.api.navi.model.NaviLatLng
|
import com.amap.api.navi.model.NaviPoi
|
import com.amap.api.navi.model.RouteOverlayOptions
|
import com.amap.api.navi.view.RouteOverLay
|
import com.blankj.utilcode.util.GsonUtils
|
import com.blankj.utilcode.util.SpanUtils
|
import com.google.gson.reflect.TypeToken
|
import com.xw.common.CommonDialog
|
import com.xw.common.utils.BindUtils.getResColor
|
import com.xw.yunwei.BR
|
import com.xw.yunwei.BaseBusinessActivity
|
import com.xw.yunwei.R
|
import com.xw.yunwei.constants.Key
|
import com.xw.yunwei.databinding.ActivityCruiseCheckInBinding
|
import com.xw.yunwei.model.CheckInMissionPointInfo
|
import com.xw.yunwei.model.CruiseCheckInOperationResult
|
import com.xw.yunwei.ui.work.amap.custom.view.CarOverlay
|
import com.xw.yunwei.ui.work.amap.util.NaviUtil
|
import com.xw.yunwei.ui.work.checkInMission.util.Utils
|
import com.xw.yunwei.ui.work.checkInMission.viewmodel.CruiseCheckInViewModel
|
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.Subscribe
|
import org.greenrobot.eventbus.ThreadMode
|
import java.text.SimpleDateFormat
|
import java.util.Date
|
|
//巡游打卡页
|
class CruiseCheckInActivity :
|
BaseBusinessActivity<ActivityCruiseCheckInBinding, CruiseCheckInViewModel>(),
|
AMapNaviListener, TTSPlayListener {
|
companion object {
|
//获取跳转此页面参数
|
fun getParams(
|
id: String,
|
points: List<CheckInMissionPointInfo>,
|
startPoint: NaviPoi,
|
endPoint: NaviPoi,
|
passPoints: List<NaviPoi>? = null,
|
type: Int,
|
): Bundle {
|
return bundleOf(
|
Key.ID to id,
|
Key.POINTS to GsonUtils.toJson(points),
|
Key.START_POINT to startPoint,
|
Key.END_POINT to endPoint,
|
Key.PASS_POINTS to GsonUtils.toJson(passPoints),
|
Key.TYPE to type
|
)
|
}
|
}
|
|
//导航对象
|
var aMapNavi: AMapNavi? = null
|
|
//设备位置类
|
var carOverlay: CarOverlay? = null
|
|
//路线OverLay
|
var routeOverLay: RouteOverLay? = null
|
|
override fun getBindingVariable() = BR.viewModel
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
super.onCreate(savedInstanceState)
|
if (!EventBus.getDefault().isRegistered(this)) {
|
EventBus.getDefault().register(this)
|
}
|
|
binding.amapView.onCreate(savedInstanceState)
|
|
initAMapView()
|
|
aMapNavi = AMapNavi.getInstance(applicationContext)?.also {
|
it.isNaviTravelView = true
|
it.addAMapNaviListener(this)
|
it.addTTSPlayListener(this)
|
it.setUseInnerVoice(true, true)
|
}
|
|
viewModel.id = intent.getStringExtra(Key.ID) ?: ""
|
viewModel.points.postValue(
|
GsonUtils.fromJson(
|
intent.getStringExtra(Key.POINTS),
|
object : TypeToken<List<CheckInMissionPointInfo>>() {}.type
|
)
|
)
|
viewModel.startPoint = intent.getParcelableExtra(Key.START_POINT)
|
viewModel.endPoint = intent.getParcelableExtra(Key.END_POINT)
|
viewModel.passPoints = GsonUtils.fromJson(
|
intent.getStringExtra(Key.PASS_POINTS),
|
object : TypeToken<List<NaviPoi>>() {}.type
|
)
|
viewModel.type = intent.getIntExtra(Key.TYPE, 0)
|
|
viewModel.checkOutTimeOut()
|
}
|
|
//初始化高德导航控件
|
private fun initAMapView() {
|
binding.amapView.map?.also { it ->
|
it.mapType = AMap.MAP_TYPE_NAVI
|
|
it.uiSettings?.setZoomInByScreenCenter(false)
|
it.uiSettings?.isZoomControlsEnabled = false
|
it.setOnMapLoadedListener {
|
it.setPointToCenter(
|
binding.amapView.width / 2,
|
binding.amapView.height / 2
|
)
|
it.moveCamera(CameraUpdateFactory.zoomTo(16f))
|
carOverlay = CarOverlay(this, binding.amapView)
|
viewModel.needCalculateRideRoute.postValue(true)
|
}
|
it.setOnMarkerClickListener { marker ->
|
viewModel.points.value?.find {
|
LatLng(
|
it.lat?.toDoubleOrNull() ?: 0.0,
|
it.lon?.toDoubleOrNull() ?: 0.0
|
) == marker.`object`
|
}?.also {
|
viewModel.choicePoint.postValue(it)
|
}
|
return@setOnMarkerClickListener true
|
}
|
}
|
}
|
|
override fun setObservable() {
|
super.setObservable()
|
viewModel.needCalculateRideRoute.observe(this) { it ->
|
if (!it) {
|
return@observe
|
}
|
aMapNavi?.also {
|
if (viewModel.type == 0) {
|
it.travelInfo = AMapTravelInfo(TransportType.Walk)
|
val success = it.calculateWalkRoute(
|
viewModel.startPoint,
|
viewModel.passPoints,
|
viewModel.endPoint,
|
TravelStrategy.SINGLE
|
)
|
if (!success) {
|
Log.d(TAG, "步行路线计算失败,检查参数情况")
|
}
|
}
|
if (viewModel.type == 1) {
|
it.travelInfo = AMapTravelInfo(TransportType.Ride)
|
val success = it.calculateRideRoute(
|
viewModel.startPoint,
|
viewModel.passPoints,
|
viewModel.endPoint,
|
TravelStrategy.SINGLE
|
)
|
if (!success) {
|
Log.d(TAG, "骑行路线计算失败,检查参数情况")
|
}
|
}
|
}
|
}
|
viewModel.points.observe(this) {
|
refreshNextPointInfo()
|
}
|
viewModel.isOverview.observe(this) { it ->
|
binding.ivOverview.setImageResource(if (it) R.mipmap.ic_route_arrow_close else R.mipmap.ic_route_arrow)
|
binding.tvOverview.text = if (it) "退出全览" else "全览"
|
if (it) {
|
routeOverLay?.zoomToSpan()
|
} else {
|
binding.amapView.map?.also {
|
viewModel.aMapNaviLocation?.also { location ->
|
it.animateCamera(
|
CameraUpdateFactory.newCameraPosition(
|
CameraPosition.fromLatLngZoom(
|
LatLng(
|
location.coord.latitude,
|
location.coord.longitude
|
), 16f
|
)
|
)
|
)
|
}
|
}
|
}
|
}
|
viewModel.hadExpand.observe(this) {
|
binding.ivFlexing.setImageResource(if (it) R.mipmap.ic_down else R.mipmap.ic_up)
|
binding.llLocationInfo.visibility = if (it) View.VISIBLE else View.GONE
|
}
|
viewModel.couldCheckIn.observe(this) {
|
binding.tvCheckIn.setBackgroundResource(if (it) R.drawable.shape_blue_5_bg_4 else R.drawable.shape_gray_4_bg_4)
|
binding.tvCheckInNotice.visibility = if (it) View.INVISIBLE else View.VISIBLE
|
binding.tvFloatCheckIn.setBackgroundResource(if (it) R.drawable.shape_blue_5_bg_4 else R.drawable.shape_gray_4_bg_4)
|
if (!it) {
|
binding.tvFloatDelayCheckIn.setOnClickListener(null)
|
binding.tvFloatCheckIn.setOnClickListener(null)
|
binding.tvCheckIn.setOnClickListener(null)
|
}
|
}
|
viewModel.checkInOperationInfo.observe(this) {
|
if (!it.isEffective()) {
|
binding.llTimeoutNotice.visibility = View.GONE
|
binding.slFloatNotice.visibility = View.GONE
|
viewModel.couldCheckIn.postValue(false)
|
return@observe
|
}
|
viewModel.getNextPoint()?.also { nextPoint ->
|
binding.tvTime.text = nextPoint.time
|
binding.tvAddress.text = nextPoint.address
|
|
if (it.needShowCheckInNotice()) {
|
viewModel.choicePoint.postValue(null)
|
viewModel.hadExpand.postValue(false)
|
viewModel.couldCheckIn.postValue(true)
|
binding.slFloatNotice.visibility = View.VISIBLE
|
SpanUtils.with(binding.tvFloatNotice)
|
.append("您已到达")
|
.setForegroundColor(getResColor(com.xw.common.R.color.gray_9))
|
.append(it.message ?: nextPoint.address ?: "")
|
.setForegroundColor(getResColor(com.xw.common.R.color.blue_5))
|
.append("打卡点,是否立即打卡?")
|
.setForegroundColor(getResColor(com.xw.common.R.color.gray_9))
|
.create()
|
binding.tvFloatDelayCheckIn.setOnClickListener { _ ->
|
binding.slFloatNotice.visibility = View.GONE
|
}
|
binding.tvFloatCheckIn.setOnClickListener { _ ->
|
binding.slFloatNotice.visibility = View.GONE
|
viewModel.jumpToCheckInPage(nextPoint)
|
}
|
}
|
if (it.needShowTimeoutNotice()) {
|
binding.tvTimeoutNotice.text = it.message
|
binding.llTimeoutNotice.visibility = View.VISIBLE
|
binding.llTimeoutNotice.postDelayed(Runnable {
|
if (isFinishing || isDestroyed) {
|
return@Runnable
|
}
|
binding.llTimeoutNotice.visibility = View.GONE
|
}, 3000)
|
}
|
}
|
}
|
viewModel.choicePoint.observe(this) {
|
if (it == null) {
|
binding.llClickLocationInfo.visibility = View.GONE
|
binding.tvClickLocationCheckIn.setOnClickListener(null)
|
return@observe
|
}
|
binding.tvClickLocationTime.text = it.time
|
binding.tvClickLocationAddress.text = it.address
|
if (it.locationId == viewModel.checkInOperationInfo.value?.checkLocationId) {
|
binding.tvClickLocationCheckIn.setBackgroundResource(R.drawable.shape_blue_5_bg_4)
|
binding.tvClickLocationCheckInNotice.visibility = View.INVISIBLE
|
} else {
|
binding.tvClickLocationCheckIn.setBackgroundResource(R.drawable.shape_gray_4_bg_4)
|
binding.tvClickLocationCheckInNotice.visibility = View.VISIBLE
|
}
|
binding.tvClickLocationCheckIn.setOnClickListener { _ ->
|
binding.llClickLocationInfo.visibility = View.GONE
|
binding.tvClickLocationCheckIn.setOnClickListener(null)
|
viewModel.jumpToCheckInPage(it)
|
}
|
}
|
}
|
|
//刷新下一个打卡点信息
|
private fun refreshNextPointInfo() {
|
viewModel.getNextPoint()?.also {
|
binding.tvTime.text = it.time
|
binding.tvAddress.text = it.address
|
}
|
}
|
|
override fun setListener() {
|
super.setListener()
|
binding.llExit.setOnClickListener {
|
CommonDialog.showTipsDialog(
|
context = this,
|
content = "是否退出导航?",
|
rightText = "确认退出",
|
rightBlock = {
|
finish()
|
return@showTipsDialog true
|
})
|
}
|
binding.llOverview.setOnClickListener {
|
viewModel.isOverview.postValue(!(viewModel.isOverview.value ?: false))
|
}
|
binding.ivFlexing.setOnClickListener {
|
viewModel.hadExpand.postValue(!(viewModel.hadExpand.value ?: false))
|
binding.slFloatNotice.visibility = View.GONE
|
}
|
binding.ivCloseTimeoutNotice.setOnClickListener {
|
binding.llTimeoutNotice.visibility = View.GONE
|
}
|
binding.llClickLocationInfoBack.setOnClickListener {
|
viewModel.choicePoint.postValue(null)
|
}
|
}
|
|
override fun onResume() {
|
super.onResume()
|
binding.amapView.onResume()
|
}
|
|
override fun onPause() {
|
super.onPause()
|
binding.amapView.onPause()
|
}
|
|
override fun onSaveInstanceState(outState: Bundle) {
|
super.onSaveInstanceState(outState)
|
binding.amapView.onSaveInstanceState(outState)
|
}
|
|
override fun onBackPressed() {
|
//super.onBackPressed()
|
binding.llExit.performClick()
|
}
|
|
override fun onDestroy() {
|
super.onDestroy()
|
if (EventBus.getDefault().isRegistered(this)) {
|
EventBus.getDefault().unregister(this)
|
}
|
binding.amapView.onDestroy()
|
aMapNavi?.also {
|
it.removeAMapNaviListener(this)
|
it.removeTTSPlayListener(this)
|
it.stopNavi()
|
AMapNavi.destroy()
|
}
|
carOverlay?.also {
|
it.destroy()
|
}
|
routeOverLay?.also {
|
it.removeFromMap()
|
it.destroy()
|
}
|
routeOverLay = null
|
carOverlay = null
|
}
|
|
override fun onInitNaviFailure() {
|
|
}
|
|
override fun onInitNaviSuccess() {
|
|
}
|
|
override fun onStartNavi(p0: Int) {
|
|
}
|
|
override fun onTrafficStatusUpdate() {
|
|
}
|
|
override fun onLocationChange(p0: AMapNaviLocation?) {
|
carOverlay?.also { it ->
|
p0?.also { location ->
|
viewModel.aMapNaviLocation = location
|
val latLng = LatLng(location.coord.latitude, location.coord.longitude)
|
it.draw(binding.amapView.map, latLng, location.bearing)
|
}
|
}
|
refreshNextPointInfo()
|
}
|
|
override fun onGetNavigationText(p0: Int, p1: String?) {
|
|
}
|
|
override fun onGetNavigationText(p0: String?) {
|
|
}
|
|
override fun onEndEmulatorNavi() {
|
|
}
|
|
override fun onArriveDestination() {
|
|
}
|
|
override fun onCalculateRouteFailure(p0: Int) {
|
Log.d(TAG, "${if (viewModel.type == 0) "步行" else "骑行"}路线计算失败,$p0")
|
}
|
|
override fun onReCalculateRouteForYaw() {
|
|
}
|
|
override fun onReCalculateRouteForTrafficJam() {
|
|
}
|
|
override fun onArrivedWayPoint(p0: Int) {
|
|
}
|
|
override fun onGpsOpenStatus(p0: Boolean) {
|
|
}
|
|
override fun onNaviInfoUpdate(p0: NaviInfo?) {
|
|
}
|
|
override fun updateCameraInfo(p0: Array<out AMapNaviCameraInfo?>?) {
|
|
}
|
|
override fun updateIntervalCameraInfo(
|
p0: AMapNaviCameraInfo?,
|
p1: AMapNaviCameraInfo?,
|
p2: Int
|
) {
|
|
}
|
|
override fun onServiceAreaUpdate(p0: Array<out AMapServiceAreaInfo?>?) {
|
|
}
|
|
override fun showCross(p0: AMapNaviCross?) {
|
|
}
|
|
override fun hideCross() {
|
|
}
|
|
override fun showModeCross(p0: AMapModelCross?) {
|
|
}
|
|
override fun hideModeCross() {
|
|
}
|
|
override fun showLaneInfo(
|
p0: Array<out AMapLaneInfo?>?,
|
p1: ByteArray?,
|
p2: ByteArray?
|
) {
|
|
}
|
|
override fun showLaneInfo(p0: AMapLaneInfo?) {
|
|
}
|
|
override fun hideLaneInfo() {
|
|
}
|
|
override fun onCalculateRouteSuccess(p0: IntArray?) {
|
|
}
|
|
override fun notifyParallelRoad(p0: Int) {
|
|
}
|
|
override fun OnUpdateTrafficFacility(p0: Array<out AMapNaviTrafficFacilityInfo?>?) {
|
|
}
|
|
override fun OnUpdateTrafficFacility(p0: AMapNaviTrafficFacilityInfo?) {
|
|
}
|
|
override fun updateAimlessModeStatistics(p0: AimLessModeStat?) {
|
|
}
|
|
override fun updateAimlessModeCongestionInfo(p0: AimLessModeCongestionInfo?) {
|
|
}
|
|
override fun onPlayRing(p0: Int) {
|
|
}
|
|
override fun onCalculateRouteSuccess(p0: AMapCalcRouteResult?) {
|
Log.d(TAG, "${if (viewModel.type == 0) "步行" else "骑行"}路线计算成功,$p0")
|
aMapNavi?.naviPath?.also { path ->
|
binding.tvDistanceCostTime.text =
|
"${Utils.getFriendlyDistance(path.allLength)} ${
|
Utils.getFriendlyTime(path.allTime)
|
}"
|
val arrivalTime = System.currentTimeMillis() + (path.allTime * 1000)
|
binding.tvEstimatedTimeOfArrival.text =
|
SimpleDateFormat("HH:mm").format(Date(arrivalTime))
|
if (routeOverLay == null) {
|
routeOverLay = RouteOverLay(binding.amapView.map, path, this)
|
}
|
routeOverLay?.also {
|
it.aMapNaviPath = path
|
it.setTrafficLine(true)
|
it.setLightsVisible(false)
|
it.setStartPointBitmap(null)
|
it.setEndPointBitmap(null)
|
it.setWayPointBitmap(null)
|
it.routeOverlayOptions = RouteOverlayOptions().apply {
|
setOnRouteCameShow(false)
|
}
|
it.addToMap()
|
}
|
carOverlay?.also { it ->
|
it.reset()
|
it.setLock(true)
|
path.endPoint?.also { end ->
|
it.setEndPoi(LatLng(end.latitude, end.longitude))
|
}
|
val rotate = NaviUtil.getRotate(
|
NaviLatLng(
|
viewModel.startPoint!!.coordinate.latitude,
|
viewModel.startPoint!!.coordinate.longitude
|
), path.coordList.first()
|
)
|
it.draw(binding.amapView.map, viewModel.startPoint!!.coordinate, rotate)
|
runOnUiThread {
|
it.setLock(false)
|
}
|
}
|
// 开启导航
|
aMapNavi?.startNavi(NaviType.GPS)
|
initMarker()
|
}
|
}
|
|
//初始化marker
|
private fun initMarker() {
|
binding.amapView.map?.also {
|
viewModel.startPoint?.also { startPoint ->
|
it.addMarker(
|
MarkerOptions()
|
.position(
|
LatLng(
|
startPoint.coordinate.latitude,
|
startPoint.coordinate.longitude
|
)
|
)
|
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_start_point))
|
)?.apply {
|
isClickable = true
|
`object` = startPoint
|
}
|
}
|
viewModel.endPoint?.also { endPoint ->
|
it.addMarker(
|
MarkerOptions()
|
.position(
|
LatLng(
|
endPoint.coordinate.latitude,
|
endPoint.coordinate.longitude
|
)
|
)
|
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_end_point))
|
)?.apply {
|
isClickable = true
|
`object` = endPoint
|
}
|
}
|
viewModel.passPoints?.forEach { point ->
|
it.addMarker(
|
MarkerOptions()
|
.position(
|
LatLng(
|
point.coordinate.latitude,
|
point.coordinate.longitude
|
)
|
)
|
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_pass_point))
|
)?.apply {
|
isClickable = true
|
`object` = point
|
}
|
}
|
}
|
}
|
|
override fun onCalculateRouteFailure(p0: AMapCalcRouteResult?) {
|
|
}
|
|
override fun onNaviRouteNotify(p0: AMapNaviRouteNotifyData?) {
|
|
}
|
|
override fun onGpsSignalWeak(p0: Boolean) {
|
|
}
|
|
override fun onPlayStart(p0: String?) {
|
viewModel.hadPlayTTS = true
|
}
|
|
override fun onPlayEnd(p0: String?) {
|
viewModel.hadPlayTTS = false
|
}
|
|
@Suppress("unused")
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
fun onMessageEvent(event: CruiseCheckInOperationResult) {
|
if (event.id != viewModel.id) {
|
return
|
}
|
viewModel.refreshPoints(event.checkLocationId, event.checkIn, event.checkInResult)
|
}
|
}
|