diff --git a/OCH/taxi/unmanned-driver/src/main/AndroidManifest.xml b/OCH/taxi/unmanned-driver/src/main/AndroidManifest.xml index fb42392054..3ab0402e38 100644 --- a/OCH/taxi/unmanned-driver/src/main/AndroidManifest.xml +++ b/OCH/taxi/unmanned-driver/src/main/AndroidManifest.xml @@ -1,5 +1,9 @@ - - / + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/bean/TaxiRoutingBean.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/bean/TaxiRoutingBean.kt new file mode 100644 index 0000000000..3411b14cdb --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/bean/TaxiRoutingBean.kt @@ -0,0 +1,61 @@ +package com.mogo.och.taxi.bean + +import com.mogo.eagle.core.data.BaseData + +data class GrayLineBean( + var lineId: Long?, //线路id + var lineName: String?, //线路名称 + var contrailId: Long?, //轨迹id + var carVerificationCount: Int?, //本次今日已验证次数 + var lineSuccessCount: Int?, //线路累计反馈可用次数 + var lineFailCount: Int?, //线路累计反馈不可用次数 + var isChoosed: Boolean = false, //当前是否选中 + var startSite: RoutingSite?, + var endSite: RoutingSite? +) + +data class RoutingSite( + var siteId: Long, + var siteName: String, + var gcjLat: Double, + var gcjLon: Double, + var wgs84Lon: Double, + var wgs84Lat: Double +) + +data class ContrailBean( + var lineId: Long = -1L, + var lineName: String = "", + var contrailId: Long = -1L, + var csvFileUrl: String = "", + var csvFileMd5: String = "", + var txtFileUrl: String = "", + var txtFileMd5: String = "", + var contrailSaveTime: Long = -1L, + var csvFileUrlDPQP: String = "", + var csvFileMd5DPQP: String = "", + var txtFileUrlDPQP: String = "", + var txtFileMd5DPQP: String = "", + var contrailSaveTimeDPQP: Long = -1L, + var version: Long = -1L +) + +data class QueryGrayContrailListRsp(var data: MutableList?) : BaseData() +data class StartGrayContrailTaskReq(var sn: String, var contrailId: Long) +data class StartGrayContrailTaskRsp(var data: Long?) : BaseData() +data class QueryRoutingContrailByIdRsp(var data: ContrailBean?) : BaseData() +data class SubmitGrayLineIssueLocationReq(var grayId: Long, var gcjLon: Double, var gcjLat: Double) +data class EndGrayContrailTaskReq(var grayId: Long, var feedback: Int) //feedback 1:成功 2:失败 +data class StartGrayAndQueryContrailRsp( + var taskId: Long?, + var contrail: ContrailBean?, + var grayLineBean: GrayLineBean +) : BaseData() + +enum class EndGrayTaskFeedbackType(var type: Int) { + USABLE_YES(1), + USABLE_NO(2) +} + + + diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/callback/ITaxiRoutingCallback.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/callback/ITaxiRoutingCallback.kt new file mode 100644 index 0000000000..980921759f --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/callback/ITaxiRoutingCallback.kt @@ -0,0 +1,15 @@ +package com.mogo.och.taxi.callback + +import com.mogo.och.taxi.bean.GrayLineBean +import com.mogo.och.taxi.bean.StartGrayAndQueryContrailRsp + +interface ITaxiRoutingCallback { + fun onQueryRoutingGrayLineListSuccess(data: MutableList) + fun onQueryRoutingGrayLineListFailed(errorStr: String) + fun onStartGrayTaskAndQueryContrailSuccess(data: StartGrayAndQueryContrailRsp) + fun onStartGrayTaskAndQueryContrailFailed(errorStr: String) + fun onSubmitGrayLineIssueLocationSuccess() + fun onSubmitGrayLineIssueLocationFailed(errorStr: String) + fun onSubmitEndTaskSuccess() + fun onSubmitEndTaskFailed(errorStr: String) +} diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/constant/TaxiDriverEventConst.java b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/constant/TaxiDriverEventConst.java index f2dc8a3cff..ed2c9f757d 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/constant/TaxiDriverEventConst.java +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/constant/TaxiDriverEventConst.java @@ -13,4 +13,8 @@ public interface TaxiDriverEventConst { String EVENT_TYPE_SHOW_RED_POINT = "event_type_tab_fragment_show_red_point"; String EVENT_TYPE_TASK_WITH_ORDER_CHANGED = "event_type_tab_fragment_task_with_order_changed"; } + + interface RoutingActivityEvent { + String EVENT_TYPE_GET_CHOSEN_LINE_TASK = "event_type_get_chosen_line_task"; + } } diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/network/TaxiRoutingServiceApi.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/network/TaxiRoutingServiceApi.kt new file mode 100644 index 0000000000..f1857459e4 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/network/TaxiRoutingServiceApi.kt @@ -0,0 +1,75 @@ +package com.mogo.och.taxi.network + +import com.mogo.cloud.passport.MoGoAiCloudClientConfig +import com.mogo.eagle.core.data.BaseData +import com.mogo.och.taxi.bean.EndGrayContrailTaskReq +import com.mogo.och.taxi.bean.QueryGrayContrailListRsp +import com.mogo.och.taxi.bean.QueryRoutingContrailByIdRsp +import com.mogo.och.taxi.bean.StartGrayContrailTaskReq +import com.mogo.och.taxi.bean.StartGrayContrailTaskRsp +import com.mogo.och.taxi.bean.SubmitGrayLineIssueLocationReq +import io.reactivex.Observable +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.Header +import retrofit2.http.Headers +import retrofit2.http.POST +import retrofit2.http.Query + +interface TaxiRoutingServiceApi { + + /** + * 查询灰度线路列表 + */ + @Headers("Content-type:application/json;charset=UTF-8") + @GET("/och-taxi-cabin/api/business/v1/queryGrayContrailList") + fun queryRoutingGrayLineList( + @Header("appId") appId: String = MoGoAiCloudClientConfig.getInstance().serviceAppId, + @Header("ticket") ticket: String = MoGoAiCloudClientConfig.getInstance().token, + @Query("sn") sn: String? + ): Observable + + /** + * 开始一个路线的灰度任务 + */ + @Headers("Content-type:application/json;charset=UTF-8") + @POST("/och-taxi-cabin/api/business/v1/startGray") + fun startGrayTask( + @Header("appId") appId: String = MoGoAiCloudClientConfig.getInstance().serviceAppId, + @Header("ticket") ticket: String = MoGoAiCloudClientConfig.getInstance().token, + @Body data: StartGrayContrailTaskReq + ): Observable + + /** + * 根据id查询灰度轨迹详情 + */ + @Headers("Content-type:application/json;charset=UTF-8") + @GET("/och-taxi-cabin/api/business/v1/gray/contrail") + fun queryRoutingContrailById( + @Header("appId") appId: String = MoGoAiCloudClientConfig.getInstance().serviceAppId, + @Header("ticket") ticket: String = MoGoAiCloudClientConfig.getInstance().token, + @Query("id") contrailId: Long + ): Observable + + /** + * 上报路线打点 + */ + @Headers("Content-type:application/json;charset=UTF-8") + @POST("/och-taxi-cabin/api/business/v1/saveDotDetail") + fun submitGrayLineIssueLocation( + @Header("appId") appId: String = MoGoAiCloudClientConfig.getInstance().serviceAppId, + @Header("ticket") ticket: String = MoGoAiCloudClientConfig.getInstance().token, + @Body data: SubmitGrayLineIssueLocationReq + ): Observable + + /** + * 结束一个路线的灰度任务 + */ + @Headers("Content-type:application/json;charset=UTF-8") + @POST("/och-taxi-cabin/api/business/v1/endGray") + fun endGrayTask( + @Header("appId") appId: String = MoGoAiCloudClientConfig.getInstance().serviceAppId, + @Header("ticket") ticket: String = MoGoAiCloudClientConfig.getInstance().token, + @Body data: EndGrayContrailTaskReq + ): Observable +} \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/network/TaxiRoutingServiceManager.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/network/TaxiRoutingServiceManager.kt new file mode 100644 index 0000000000..aaa1b5c288 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/network/TaxiRoutingServiceManager.kt @@ -0,0 +1,134 @@ +package com.mogo.och.taxi.network + +import android.content.Context +import com.mogo.cloud.passport.MoGoAiCloudClientConfig +import com.mogo.eagle.core.data.BaseData +import com.mogo.eagle.core.network.MoGoRetrofitFactory +import com.mogo.och.common.module.biz.constant.OchCommonConst +import com.mogo.och.common.module.biz.network.OchCommonServiceCallback +import com.mogo.och.common.module.biz.network.OchCommonSubscribeImpl +import com.mogo.och.common.module.biz.network.interceptor.transformTry +import com.mogo.och.taxi.bean.EndGrayContrailTaskReq +import com.mogo.och.taxi.bean.GrayLineBean +import com.mogo.och.taxi.bean.QueryGrayContrailListRsp +import com.mogo.och.taxi.bean.QueryRoutingContrailByIdRsp +import com.mogo.och.taxi.bean.StartGrayAndQueryContrailRsp +import com.mogo.och.taxi.bean.StartGrayContrailTaskReq +import com.mogo.och.taxi.bean.StartGrayContrailTaskRsp +import com.mogo.och.taxi.bean.SubmitGrayLineIssueLocationReq +import io.reactivex.Observable + +object TaxiRoutingServiceManager { + + private var mRoutingServiceApi: TaxiRoutingServiceApi = + MoGoRetrofitFactory.getInstance(OchCommonConst.getBaseUrl()).create( + TaxiRoutingServiceApi::class.java + ) + + /** + * 查询灰度路线列表 + */ + fun queryRoutingGrayLineList( + context: Context, + callback: OchCommonServiceCallback + ) { + mRoutingServiceApi.queryRoutingGrayLineList( + sn = MoGoAiCloudClientConfig.getInstance().sn + ) + .transformTry() + .subscribe(OchCommonSubscribeImpl(context, callback, "queryRoutingGrayLineList")) + } + + /** + * 开始一个灰度任务 + */ + fun startGrayTask( + context: Context, + data: StartGrayContrailTaskReq, + callback: OchCommonServiceCallback + ) { + mRoutingServiceApi.startGrayTask(data = data).transformTry() + .subscribe(OchCommonSubscribeImpl(context, callback, "startGrayTask")) + } + + /** + * 通过id查询轨迹详情 + */ + fun queryRoutingContrailById( + context: Context, + contrailId: Long, + callback: OchCommonServiceCallback + ) { + mRoutingServiceApi.queryRoutingContrailById(contrailId = contrailId).transformTry() + .subscribe(OchCommonSubscribeImpl(context, callback, "queryRoutingContrailById")) + } + + /** + * 上报线路打点 + */ + fun submitGrayLineIssueLocation( + context: Context, + data: SubmitGrayLineIssueLocationReq, + callback: OchCommonServiceCallback + ) { + mRoutingServiceApi.submitGrayLineIssueLocation(data = data).transformTry() + .subscribe(OchCommonSubscribeImpl(context, callback, "submitGrayLineIssueLocation")) + } + + /** + * 结束一个灰度任务 + */ + fun endGrayTask( + context: Context, + data: EndGrayContrailTaskReq, + callback: OchCommonServiceCallback + ) { + mRoutingServiceApi.endGrayTask(data = data).transformTry() + .subscribe(OchCommonSubscribeImpl(context, callback, "endGrayTask")) + } + + fun startGrayTaskAndQueryRoutingContrail( + context: Context, + sn: String, + contrailId: Long, + grayLineBean: GrayLineBean, + callback: OchCommonServiceCallback + ) { + val data = StartGrayContrailTaskReq(sn = sn, contrailId = contrailId) + var taskId: Long + mRoutingServiceApi.startGrayTask(data = data) + .flatMap { startGrayRsp -> + if (startGrayRsp.data == null) { + taskId = -1L + val result = StartGrayAndQueryContrailRsp( + taskId = taskId, + contrail = null, + grayLineBean = grayLineBean + ) + result.code = startGrayRsp.code + result.msg = startGrayRsp.msg + return@flatMap Observable.just(result) + } + taskId = startGrayRsp.data!! + return@flatMap mRoutingServiceApi.queryRoutingContrailById(contrailId = contrailId) + .map { queryRoutingContrailRsp -> + val result = StartGrayAndQueryContrailRsp( + taskId = taskId, + contrail = queryRoutingContrailRsp.data, + grayLineBean = grayLineBean + ) + result.code = queryRoutingContrailRsp.code + result.msg = queryRoutingContrailRsp.msg + result + } + } + .transformTry() + .subscribe( + OchCommonSubscribeImpl( + context, + callback, + "startGrayTaskAndQueryRoutingContrail" + ) + ) + } +} \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/BaseTaxiTabFragment.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/BaseTaxiTabFragment.kt index e6f02a643e..a2aac8167a 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/BaseTaxiTabFragment.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/BaseTaxiTabFragment.kt @@ -11,6 +11,7 @@ import android.view.animation.LinearInterpolator import androidx.fragment.app.FragmentTransaction import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.mogo.commons.AbsMogoApplication +import com.mogo.commons.module.status.MogoStatusManager import com.mogo.commons.mvp.IView import com.mogo.commons.mvp.MvpFragment import com.mogo.commons.mvp.Presenter @@ -26,6 +27,7 @@ import com.mogo.eagle.core.function.hmi.ui.widget.ParallelDriveView import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant import com.mogo.eagle.core.utilcode.mogo.view.OnPreventFastClickListener +import com.mogo.eagle.core.utilcode.util.ToastUtils import com.mogo.eagle.core.utilcode.util.UiThreadHandler import com.mogo.map.listener.IMogoMapListener import com.mogo.map.uicontroller.VisualAngleMode @@ -197,6 +199,10 @@ abstract class BaseTaxiTabFragment> : MvpFragment(), private var taskTabFragment: WeakReference? = null private var personalDialogFragment: WeakReference? = null + private var routingVerifyFragment: WeakReference? = null private var loginService: LoginService? = null @Subscribe(threadMode = ThreadMode.MAIN) @@ -151,15 +155,56 @@ class TaxiFragment : BaseTaxiTabFragment(), } private fun initFragment() { - taskTabFragment = WeakReference(TaxiTaskTabFragment.newInstance()) + showTaskFragment() + MogoStatusManager.getInstance() + .registerStatusChangedListener( + TAG, StatusDescriptor.TAXI_UNMANED_DRIVER_LINE_ROUTING_VERIFY_MODE + ) { descriptor, isTrue -> + if (StatusDescriptor.TAXI_UNMANED_DRIVER_LINE_ROUTING_VERIFY_MODE == descriptor) { + UiThreadHandler.post { + if (isTrue) { + showRoutingFragment() + } else { + showTaskFragment() + } + updateOperationBtnStatusOnModeChange(isTrue) + } + } + } + } + + private fun showTaskFragment() { val transaction: FragmentTransaction = childFragmentManager.beginTransaction() - //默认显示OCHTaxiServerOrdersFragment - taskTabFragment?.get()?.let { - transaction.add(R.id.fragment_container, it).show( - it - ) + if (routingVerifyFragment?.get()?.isVisible == true) { + routingVerifyFragment?.get()?.also { + transaction.remove(it) + routingVerifyFragment = null + } + } + if (taskTabFragment?.get() == null) { + taskTabFragment = WeakReference(TaxiTaskTabFragment.newInstance()) + } + taskTabFragment?.get()?.also { + transaction.replace(R.id.fragment_container, it).show(it) + transaction.commitAllowingStateLoss() + } + } + + private fun showRoutingFragment() { + val transaction: FragmentTransaction = childFragmentManager.beginTransaction() + if (taskTabFragment?.get()?.isVisible == true) { + taskTabFragment?.get()?.also { + transaction.remove(it) + taskTabFragment = null + } + } + if (routingVerifyFragment?.get() == null) { + routingVerifyFragment = WeakReference(TaxiRoutingFragment.newInstance()) + } + routingVerifyFragment?.get()?.also { + transaction.replace(R.id.fragment_container, it).show(it) + transaction.commitAllowingStateLoss() } - transaction.commitAllowingStateLoss() } override fun createPresenter(): TaxiPresenter { @@ -220,6 +265,31 @@ class TaxiFragment : BaseTaxiTabFragment(), null ) } + updateOperationBtnStatusOnModeChange(MogoStatusManager.getInstance().isTaxiUnmanedDriverLineRoutingVerifyMode) + MogoStatusManager.getInstance().setTaxiUnmanedDriverTakingOrders(TAG, inOperation) + } + + private fun updateOperationBtnStatusOnModeChange(isRoutingVerifyMode: Boolean) { + if (MogoStatusManager.getInstance().isTaxiUnmanedDriverTakingOrders) { + return + } + module_mogo_och_operation_status.isEnabled = !isRoutingVerifyMode + val isBtnEnable = module_mogo_och_operation_status.isEnabled + if (isBtnEnable) { + module_mogo_och_operation_status.setCompoundDrawablesWithIntrinsicBounds( + resources.getDrawable(R.drawable.shape_size_operation_out), + null, + null, + null + ) + } else { + module_mogo_och_operation_status.setCompoundDrawablesWithIntrinsicBounds( + resources.getDrawable(R.drawable.shape_size_operation_out_disable), + null, + null, + null + ) + } } override fun onMapLoaded() {} @@ -230,8 +300,12 @@ class TaxiFragment : BaseTaxiTabFragment(), fun onNaviToEnd(isAmap: Boolean, isShow: Boolean) { if (isAmap) { - if (null == taskTabFragment || taskTabFragment!!.get() == null) return - taskTabFragment!!.get()!!.onNaviToEndStationByAMap(isShow) + if (MogoStatusManager.getInstance().isTaxiUnmanedDriverLineRoutingVerifyMode) { + showAmapNaviToStationFragment(isShow) + } else { + if (null == taskTabFragment || taskTabFragment!!.get() == null) return + taskTabFragment!!.get()!!.onNaviToEndStationByAMap(isShow) + } } else if (isShow) { //使用routing数据 showRoutingToStationFragment(true) } else { @@ -262,8 +336,8 @@ class TaxiFragment : BaseTaxiTabFragment(), if (it.order != null && it.order!!.orderStatus >= TaxiOrderStatusEnum.ArriveAtStart.code) it.order!!.orderLine else - it.lineId - ,true) + it.lineId, true + ) } } diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/TaxiPresenter.java b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/TaxiPresenter.java index 8fc079b3bb..7cf4e7c07b 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/TaxiPresenter.java +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/TaxiPresenter.java @@ -6,6 +6,7 @@ import androidx.annotation.NonNull; import androidx.lifecycle.LifecycleOwner; import com.mogo.commons.AbsMogoApplication; +import com.mogo.commons.module.status.MogoStatusManager; import com.mogo.commons.mvp.Presenter; import com.mogo.eagle.core.data.map.MogoLocation; import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; @@ -20,6 +21,7 @@ import com.mogo.och.taxi.callback.ITaxiOrderStatusCallback; import com.mogo.och.taxi.constant.TaxiCarServingStatusManager; import com.mogo.och.taxi.constant.TaxiDriverRoleEnum; import com.mogo.och.taxi.constant.TaxiUnmannedConst; +import com.mogo.och.taxi.ui.routing.TaxiRoutingModel; import com.mogo.och.taxi.ui.task.TaxiTaskModel; /** @@ -51,6 +53,8 @@ public class TaxiPresenter extends Presenter implements ITaxiADASS TaxiTaskModel.INSTANCE.setADASStatusCallback(this); TaxiTaskModel.INSTANCE.setControllerStatusCallback(this); TaxiTaskModel.INSTANCE.setOrderStatusCallback(this); + TaxiRoutingModel.INSTANCE.setControllerStatusCallback(this); + TaxiRoutingModel.INSTANCE.setOrderStatusCallback(this); } private void releaseListeners() { @@ -76,7 +80,11 @@ public class TaxiPresenter extends Presenter implements ITaxiADASS * 开启自动驾驶 自驾模式 */ public void startAutoPilot() { - TaxiTaskModel.INSTANCE.startAutopilotByClick(); + if (MogoStatusManager.getInstance().isTaxiUnmanedDriverLineRoutingVerifyMode()) { + TaxiRoutingModel.INSTANCE.startAutoPilotByClick(); + } else { + TaxiTaskModel.INSTANCE.startAutopilotByClick(); + } } // 登出 diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/debug/DebugView.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/debug/DebugView.kt index a5ff83c463..041b821113 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/debug/DebugView.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/debug/DebugView.kt @@ -16,10 +16,14 @@ import android.widget.TextView import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.mogo.commons.module.status.IMogoStatusChangedListener +import com.mogo.commons.module.status.MogoStatusManager +import com.mogo.commons.module.status.StatusDescriptor import com.mogo.commons.utils.MogoAnalyticUtils import com.mogo.eagle.core.function.main.MainMoGoApplication import com.mogo.eagle.core.network.utils.GsonUtil import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d +import com.mogo.eagle.core.utilcode.util.AppUtils import com.mogo.eagle.core.utilcode.util.UiThreadHandler import com.mogo.och.common.module.utils.DateTimeUtil import com.mogo.och.taxi.R @@ -30,6 +34,8 @@ import com.mogo.och.taxi.constant.TaskStatusEnum import com.mogo.och.taxi.constant.TaskTypeEnum import com.mogo.och.taxi.constant.TaxiOrderStatusEnum import com.mogo.och.taxi.ui.task.TaxiTaskModel +import kotlinx.android.synthetic.main.taxi_debug_order.view.btnContainer +import kotlinx.android.synthetic.main.taxi_debug_order.view.currentBusinessModeTextView import kotlinx.android.synthetic.main.taxi_debug_order.view.currentCarStatus import kotlinx.android.synthetic.main.taxi_debug_order.view.currentDataTimestamps import kotlinx.android.synthetic.main.taxi_debug_order.view.currentLineId @@ -39,6 +45,7 @@ import kotlinx.android.synthetic.main.taxi_debug_order.view.currentOrderTrajecto import kotlinx.android.synthetic.main.taxi_debug_order.view.currentStatus import kotlinx.android.synthetic.main.taxi_debug_order.view.currentTaskType import kotlinx.android.synthetic.main.taxi_debug_order.view.debugLogHistoryTextView +import kotlinx.android.synthetic.main.taxi_debug_order.view.debugLogTitleTextView import kotlinx.android.synthetic.main.taxi_debug_order.view.orderEndSiteInfo import kotlinx.android.synthetic.main.taxi_debug_order.view.orderNo import kotlinx.android.synthetic.main.taxi_debug_order.view.orderPreLoadLines @@ -46,13 +53,15 @@ import kotlinx.android.synthetic.main.taxi_debug_order.view.orderStartSiteInfo import kotlinx.android.synthetic.main.taxi_debug_order.view.orderStatus import kotlinx.android.synthetic.main.taxi_debug_order.view.taskEndSite import kotlinx.android.synthetic.main.taxi_debug_order.view.taskStartSite +import kotlinx.android.synthetic.main.taxi_debug_order.view.unmanedTaskOrderContainer import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch public class DebugView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 -) : LinearLayout(context, attrs, defStyleAttr, defStyleRes), ITaxiTaskWithOrderCallback { +) : LinearLayout(context, attrs, defStyleAttr, defStyleRes), ITaxiTaskWithOrderCallback, + IMogoStatusChangedListener { companion object { const val TAG = "DebugView" private const val ANALYTICS_EVENT_TYPE_DRIVER_UNMANNED_OPERATION_PROCESS_KEY_NODE_LOG = @@ -104,7 +113,10 @@ public class DebugView @JvmOverloads constructor( val map: MutableMap = HashMap() map["level"] = level map["msg"] = msg - MogoAnalyticUtils.track(ANALYTICS_EVENT_TYPE_DRIVER_UNMANNED_OPERATION_PROCESS_KEY_NODE_LOG, map) + MogoAnalyticUtils.track( + ANALYTICS_EVENT_TYPE_DRIVER_UNMANNED_OPERATION_PROCESS_KEY_NODE_LOG, + map + ) } } @@ -128,9 +140,11 @@ public class DebugView @JvmOverloads constructor( init { initBroadcastReceiver() LayoutInflater.from(context).inflate(R.layout.taxi_debug_order, this, true) - debugLogHistoryTextView.setMovementMethod(ScrollingMovementMethod.getInstance()) + debugLogHistoryTextView.movementMethod = ScrollingMovementMethod.getInstance() visibility = GONE logHistoryTextView = debugLogHistoryTextView + + initView() } private fun initBroadcastReceiver() { @@ -142,8 +156,7 @@ public class DebugView @JvmOverloads constructor( fun toggleOrderDebugView() { visibility = if (visibility == View.VISIBLE) View.GONE else View.VISIBLE - val data = TaxiTaskModel.getCurrentTaskWithOrder() - initViewByData(data) + initView() } private fun initTaskWithOrderDataListener() { @@ -154,17 +167,49 @@ public class DebugView @JvmOverloads constructor( TaxiTaskModel.removeTaskWithOrderListener(TAG) } + private fun initCurrentBusinessModeListener() { + MogoStatusManager.getInstance() + .registerStatusChangedListener( + TAG, StatusDescriptor.TAXI_UNMANED_DRIVER_LINE_ROUTING_VERIFY_MODE, this + ) + } + + private fun removeCurrentBusinessModeListener() { + MogoStatusManager.getInstance().unregisterStatusChangedListener( + TAG, + StatusDescriptor.TAXI_UNMANED_DRIVER_LINE_ROUTING_VERIFY_MODE, + this + ) + } + override fun onAttachedToWindow() { super.onAttachedToWindow() initTaskWithOrderDataListener() + initCurrentBusinessModeListener() } override fun onDetachedFromWindow() { super.onDetachedFromWindow() removeTaskWithOrderDataListener() + removeCurrentBusinessModeListener() } - private fun initViewByData(data: QueryCurrentTaskRespBean.Result?) { + private fun initView() { + initCurrentBusinessMode() + initViewByTaskData(TaxiTaskModel.getCurrentTaskWithOrder()) + initDebugLogTextViewTitle() + } + + private fun initCurrentBusinessMode() { + val isRoutingVerifyMode = + MogoStatusManager.getInstance().isTaxiUnmanedDriverLineRoutingVerifyMode + currentBusinessModeTextView.text = + "当前业务模式:${if (isRoutingVerifyMode) "自主算路验证模式" else "无人化运营流程模式"}" + } + + private fun initViewByTaskData(data: QueryCurrentTaskRespBean.Result?) { + //release包下隐藏Mock按钮,避免司机误操作 + btnContainer.visibility = if (AppUtils.isAppDebug()) View.INVISIBLE else View.VISIBLE val curContrail = TaxiTaskModel.getCurrentTaskTrajectory() currentDataTimestamps.text = "【当前数据返回时间】${currentDateTimeString()}" currentCarStatus.text = @@ -194,9 +239,16 @@ public class DebugView @JvmOverloads constructor( "【当前任务Stop信息】StopMd5=${curContrail?.txtFileMd5}, StopDPQPMd5=${curContrail?.txtFileMd5DPQP}" } + private fun initDebugLogTextViewTitle() { + val isRoutingVerifyMode = + MogoStatusManager.getInstance().isTaxiUnmanedDriverLineRoutingVerifyMode + debugLogTitleTextView.text = + if (isRoutingVerifyMode) "自主算路验证模式关键节点日志(司机端)" else "无人化运营流程关键节点日志(司机端)" + } + override fun onTaskWithOrderDataChanged(taskWithOrder: QueryCurrentTaskRespBean.Result?) { d(TAG, "onTaskWithOrderDataChanged") - initViewByData(taskWithOrder) + initViewByTaskData(taskWithOrder) } override fun onTaskCompleted(result: QueryCurrentTaskRespBean.Result?) { @@ -234,4 +286,16 @@ public class DebugView @JvmOverloads constructor( override fun onTaskTripInfoLocalCalculateChanged(meters: Long, timeInSecond: Long) { } + + override fun onStatusChanged(descriptor: StatusDescriptor?, isTrue: Boolean) { + if (StatusDescriptor.TAXI_UNMANED_DRIVER_LINE_ROUTING_VERIFY_MODE == descriptor) { + UiThreadHandler.post { + initCurrentBusinessMode() + initDebugLogTextViewTitle() + unmanedTaskOrderContainer.visibility = if (isTrue) View.GONE else View.VISIBLE + debugLogHistoryTextView.maxLines = if (isTrue) 30 else 15 + } + printInfoMsg("[当前业务模式变化] afterValue=${if (isTrue) "自主算路验证模式" else "无人化运营流程模式"}") + } + } } \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineActivity.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineActivity.kt new file mode 100644 index 0000000000..e9c72c0f2a --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineActivity.kt @@ -0,0 +1,170 @@ +package com.mogo.och.taxi.ui.routing + +import android.graphics.Point +import android.os.Bundle +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger +import com.mogo.eagle.core.utilcode.mogo.view.SpacesItemDecoration +import com.mogo.eagle.core.utilcode.util.ToastUtils +import com.mogo.och.common.module.utils.FlowBus +import com.mogo.och.taxi.R +import com.mogo.och.taxi.bean.GrayLineBean +import com.mogo.och.taxi.constant.TaxiDriverEventConst +import com.mogo.och.taxi.ui.debug.DebugView +import kotlinx.android.synthetic.main.routing_choose_task_activity.btnChooseLineSubmit +import kotlinx.android.synthetic.main.routing_choose_task_activity.btnClose +import kotlinx.android.synthetic.main.routing_choose_task_activity.chooseLineListView +import kotlinx.android.synthetic.main.routing_no_data_common_view.noDataContainer +import kotlinx.coroutines.flow.map + +class TaxiRoutingChooseLineActivity : AppCompatActivity() { + + companion object { + const val TAG = "TaxiRoutingChooseLineActivity" + } + + private val mViewModel: TaxiRoutingChooseLineViewModel by lazy { + ViewModelProvider( + this, + ViewModelProvider.NewInstanceFactory() + )[TaxiRoutingChooseLineViewModel::class.java] + } + + private val mLoadingDialog: TaxiRoutingLoadingDialog by lazy { + TaxiRoutingLoadingDialog( + this + ) + } + private lateinit var mChooseLineListAdapter: TaxiRoutingChooseLineAdapter + private lateinit var mLinearLayoutManager: LinearLayoutManager + private val mRoutingLineList: MutableList = ArrayList() + private var mCurrentChosenPosition: Int = -1 + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.routing_choose_task_activity) + initWindowParams() + initView() + initViewListener() + initViewModelObserver() + loadData() + } + + private fun initWindowParams() { + val window = window + val params = window.attributes + val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager + val point = Point() + windowManager.defaultDisplay.getSize(point) //用于获取屏幕高度 + params.width = (point.x * 0.375).toInt() + params.height = ViewGroup.LayoutParams.MATCH_PARENT + window.attributes = params + window.setGravity(Gravity.START or Gravity.BOTTOM) + } + + private fun initView() { + mLinearLayoutManager = LinearLayoutManager(this) + chooseLineListView.layoutManager = mLinearLayoutManager + chooseLineListView.itemAnimator = + TaxiRoutingChooseLineItemOpenAnimator() + mChooseLineListAdapter = TaxiRoutingChooseLineAdapter(applicationContext, mRoutingLineList) + chooseLineListView.addItemDecoration(SpacesItemDecoration(4)) + chooseLineListView.adapter = mChooseLineListAdapter + //设置item 点击事件 + mChooseLineListAdapter.setOnLineItemClickListener(object : + TaxiRoutingChooseLineAdapter.OnChooseLineItemClickListener { + override fun onItemClick(position: Int, close: Boolean) { + mCurrentChosenPosition = position + } + }) + } + + private fun initViewListener() { + btnClose.setOnClickListener { + finish() + } + btnChooseLineSubmit.setOnClickListener { + if (mCurrentChosenPosition == -1) { + ToastUtils.showLong("请先选择任务") + return@setOnClickListener + } + DebugView.printInfoMsg("[选择灰度任务] 当前选择 mCurrentChosenPosition=$mCurrentChosenPosition, ") + mLoadingDialog.showLoading() + val chosenItem = mRoutingLineList[mCurrentChosenPosition] + mViewModel.sendUiIntent( + TaxiRoutingUiIntent.StartTaskAndQueryContrail(chosenItem) + ) + } + } + + private fun initViewModelObserver() { + lifecycleScope.launchWhenStarted { + mViewModel.uiStateFlow.map { it.routingUiState }.collect { routingUiState -> + CallerLogger.d( + TAG, + "uiStateFlow-initViewModelObserver: $routingUiState" + ) + when (routingUiState) { + is RoutingUIState.Init -> { + showEmptyView() + } + + is RoutingUIState.ShowGrayLineList -> { + onRoutingGrayLineListChanged(routingUiState.data) + } + + is RoutingUIState.HideChooseLineLoading -> { + mLoadingDialog.hideLoading() + if (routingUiState.isCosePage) { + mChooseLineListAdapter.setOnLineItemClickListener(null) + finish() + } + } + + is RoutingUIState.PostRoutingTaskResult -> { + FlowBus.with(TaxiDriverEventConst.RoutingActivityEvent.EVENT_TYPE_GET_CHOSEN_LINE_TASK) + .post(this, RoutingUIState.RoutingTask( + grayLineBean = routingUiState.grayLineBean, + contrailBean = routingUiState.contrailBean, + grayId = routingUiState.grayId + )) + } + } + } + } + } + + private fun showEmptyView() { + chooseLineListView.visibility = View.GONE + btnChooseLineSubmit.visibility = View.GONE + noDataContainer.visibility = View.VISIBLE + } + + private fun showRecyclerView() { + chooseLineListView.visibility = View.VISIBLE + btnChooseLineSubmit.visibility = View.VISIBLE + noDataContainer.visibility = View.GONE + } + + private fun loadData() { + mViewModel.sendUiIntent(TaxiRoutingUiIntent.QueryRoutingGrayLineList(System.currentTimeMillis())) + } + + private fun onRoutingGrayLineListChanged(data: MutableList) { + if (data.isNotEmpty()) { + showRecyclerView() + mRoutingLineList.clear() + mRoutingLineList.addAll(data) + mChooseLineListAdapter.notifyDataSetChanged() + } else { + showEmptyView() + } + } +} \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineAdapter.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineAdapter.kt new file mode 100644 index 0000000000..501cc62945 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineAdapter.kt @@ -0,0 +1,87 @@ +package com.mogo.och.taxi.ui.routing + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.widget.AppCompatTextView +import androidx.recyclerview.widget.RecyclerView +import com.mogo.och.taxi.R +import com.mogo.och.taxi.bean.GrayLineBean + +class TaxiRoutingChooseLineAdapter( + private val mContext: Context, + private val mData: List +) : RecyclerView.Adapter() { + + companion object { + const val TAG = "TaxiRoutingChooseLineAdapter" + } + + private var mItemClickListener: OnChooseLineItemClickListener? = null + private var mLastChoosedLineIndex = -1 + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SwitchLineViewHolder { + val view = LayoutInflater.from(mContext).inflate( + R.layout.routing_choose_line_list_item, parent, false + ) + return SwitchLineViewHolder(view) + } + + override fun onBindViewHolder(holder: SwitchLineViewHolder, position: Int) { + val currentPosition = holder.bindingAdapterPosition + val data = mData[currentPosition] + holder.lineNameTextView.text = data.lineName + holder.todayVerifyNumTextView.text = "本车今日已验证:${data.carVerificationCount}次" + holder.historyVerifyNumTextView.text = + "路线累计反馈${data.lineSuccessCount}可用,${data.lineFailCount}不可用" + if (data.isChoosed) { + holder.itemView.setBackgroundResource(R.drawable.routing_choose_line_shape_select_line_item_bg_selected) + } else { + holder.itemView.setBackgroundColor(Color.parseColor("#162761")) + } + + //设置item点击事件 + holder.itemView.setOnClickListener { + mData.forEachIndexed { index, result -> + if (result.isChoosed && index != currentPosition) { + result.isChoosed = false + notifyItemChanged(index) + } + } + val isCurrentItemSelected = !mData[currentPosition].isChoosed + mData[currentPosition].isChoosed = isCurrentItemSelected + notifyItemChanged(currentPosition) + mItemClickListener?.onItemClick( + currentPosition, + isCurrentItemSelected + ) + mLastChoosedLineIndex = currentPosition + } + } + + override fun getItemCount(): Int { + return mData.size + } + + fun setOnLineItemClickListener(itemClickListener: OnChooseLineItemClickListener?) { + mItemClickListener = itemClickListener + } + + interface OnChooseLineItemClickListener { + fun onItemClick(position: Int, isChoosed: Boolean) + } + + class SwitchLineViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val lineNameTextView: AppCompatTextView//线路名称 + val todayVerifyNumTextView: AppCompatTextView //本车今天验证次数 + val historyVerifyNumTextView: AppCompatTextView //路线累计验证次数 + + init { + lineNameTextView = itemView.findViewById(R.id.switchLineNameTextView) + todayVerifyNumTextView = itemView.findViewById(R.id.todayVerifyNumTextView) + historyVerifyNumTextView = itemView.findViewById(R.id.historyVerifyNumTextView) + } + } +} \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineItemOpenAnimator.java b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineItemOpenAnimator.java new file mode 100644 index 0000000000..323ec5e83a --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineItemOpenAnimator.java @@ -0,0 +1,641 @@ +package com.mogo.och.taxi.ui.routing; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator; +import android.view.View; +import android.view.ViewPropertyAnimator; + +import androidx.annotation.NonNull; +import androidx.core.view.ViewCompat; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; +import java.util.List; + +/** + * This implementation of {@link RecyclerView.ItemAnimator} provides basic + * animations on remove, add, and move events that happen to the items in + * a RecyclerView. RecyclerView uses a DefaultItemAnimator by default. + * + * @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator) + */ +public class TaxiRoutingChooseLineItemOpenAnimator extends DefaultItemAnimator { + private static final boolean DEBUG = false; + private static TimeInterpolator sDefaultInterpolator; + private final ArrayList mPendingRemovals = new ArrayList<>(); + private final ArrayList mPendingAdditions = new ArrayList<>(); + private final ArrayList mPendingMoves = new ArrayList<>(); + private final ArrayList mPendingChanges = new ArrayList<>(); + private final ArrayList> mAdditionsList = new ArrayList<>(); + private final ArrayList> mMovesList = new ArrayList<>(); + private final ArrayList> mChangesList = new ArrayList<>(); + private final ArrayList mAddAnimations = new ArrayList<>(); + private final ArrayList mMoveAnimations = new ArrayList<>(); + private final ArrayList mRemoveAnimations = new ArrayList<>(); + private final ArrayList mChangeAnimations = new ArrayList<>(); + + private static class MoveInfo { + public RecyclerView.ViewHolder holder; + public int fromX, fromY, toX, toY; + + MoveInfo(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) { + this.holder = holder; + this.fromX = fromX; + this.fromY = fromY; + this.toX = toX; + this.toY = toY; + } + } + + private static class ChangeInfo { + public RecyclerView.ViewHolder oldHolder, newHolder; + public int fromX, fromY, toX, toY; + + private ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder) { + this.oldHolder = oldHolder; + this.newHolder = newHolder; + } + + ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, + int fromX, int fromY, int toX, int toY) { + this(oldHolder, newHolder); + this.fromX = fromX; + this.fromY = fromY; + this.toX = toX; + this.toY = toY; + } + + @Override + public String toString() { + return "ChangeInfo{" + + "oldHolder=" + oldHolder + + ", newHolder=" + newHolder + + ", fromX=" + fromX + + ", fromY=" + fromY + + ", toX=" + toX + + ", toY=" + toY + + '}'; + } + } + + @Override + public void runPendingAnimations() { + boolean removalsPending = !mPendingRemovals.isEmpty(); + boolean movesPending = !mPendingMoves.isEmpty(); + boolean changesPending = !mPendingChanges.isEmpty(); + boolean additionsPending = !mPendingAdditions.isEmpty(); + if (!removalsPending && !movesPending && !additionsPending && !changesPending) { + // nothing to animate + return; + } + // First, remove stuff + for (RecyclerView.ViewHolder holder : mPendingRemovals) { + animateRemoveImpl(holder); + } + mPendingRemovals.clear(); + // Next, move stuff + if (movesPending) { + final ArrayList moves = new ArrayList<>(mPendingMoves); + mMovesList.add(moves); + mPendingMoves.clear(); + Runnable mover = () -> { + for (MoveInfo moveInfo : moves) { + animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, + moveInfo.toX, moveInfo.toY); + } + moves.clear(); + mMovesList.remove(moves); + }; + if (removalsPending) { + View view = moves.get(0).holder.itemView; + ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration()); + } else { + mover.run(); + } + } + // Next, change stuff, to run in parallel with move animations + if (changesPending) { + final ArrayList changes = new ArrayList<>(mPendingChanges); + mChangesList.add(changes); + mPendingChanges.clear(); + Runnable changer = () -> { + for (ChangeInfo change : changes) { + animateChangeImpl(change); + } + changes.clear(); + mChangesList.remove(changes); + }; + if (removalsPending) { + RecyclerView.ViewHolder holder = changes.get(0).oldHolder; + ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration()); + } else { + changer.run(); + } + } + // Next, add stuff + if (additionsPending) { + final ArrayList additions = new ArrayList<>(mPendingAdditions); + mAdditionsList.add(additions); + mPendingAdditions.clear(); + Runnable adder = () -> { + for (RecyclerView.ViewHolder holder : additions) { + animateAddImpl(holder); + } + additions.clear(); + mAdditionsList.remove(additions); + }; + if (removalsPending || movesPending || changesPending) { + long removeDuration = removalsPending ? getRemoveDuration() : 0; + long moveDuration = movesPending ? getMoveDuration() : 0; + long changeDuration = changesPending ? getChangeDuration() : 0; + long totalDelay = removeDuration + Math.max(moveDuration, changeDuration); + View view = additions.get(0).itemView; + ViewCompat.postOnAnimationDelayed(view, adder, totalDelay); + } else { + adder.run(); + } + } + } + + @Override + public boolean animateRemove(final RecyclerView.ViewHolder holder) { + resetAnimation(holder); + mPendingRemovals.add(holder); + return true; + } + + private void animateRemoveImpl(final RecyclerView.ViewHolder holder) { + final View view = holder.itemView; + final ViewPropertyAnimator animation = view.animate(); + mRemoveAnimations.add(holder); + animation.setDuration(getRemoveDuration()).alpha(0).setListener( + new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animator) { + dispatchRemoveStarting(holder); + } + + @Override + public void onAnimationEnd(Animator animator) { + animation.setListener(null); + view.setAlpha(1); + dispatchRemoveFinished(holder); + mRemoveAnimations.remove(holder); + dispatchFinishedWhenDone(); + } + }).start(); + } + + @Override + public boolean animateAdd(final RecyclerView.ViewHolder holder) { + resetAnimation(holder); + holder.itemView.setAlpha(0); + mPendingAdditions.add(holder); + return true; + } + + void animateAddImpl(final RecyclerView.ViewHolder holder) { + final View view = holder.itemView; + final ViewPropertyAnimator animation = view.animate(); + mAddAnimations.add(holder); + animation.alpha(1).setDuration(getAddDuration()) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animator) { + dispatchAddStarting(holder); + } + + @Override + public void onAnimationCancel(Animator animator) { + view.setAlpha(1); + } + + @Override + public void onAnimationEnd(Animator animator) { + animation.setListener(null); + dispatchAddFinished(holder); + mAddAnimations.remove(holder); + dispatchFinishedWhenDone(); + } + }).start(); + } + + @Override + public boolean animateMove(final RecyclerView.ViewHolder holder, int fromX, int fromY, + int toX, int toY) { + final View view = holder.itemView; + fromX += (int) holder.itemView.getTranslationX(); + fromY += (int) holder.itemView.getTranslationY(); + resetAnimation(holder); + int deltaX = toX - fromX; + int deltaY = toY - fromY; + if (deltaX == 0 && deltaY == 0) { + dispatchMoveFinished(holder); + return false; + } + if (deltaX != 0) { + view.setTranslationX(-deltaX); + } + if (deltaY != 0) { + view.setTranslationY(-deltaY); + } + mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY)); + return true; + } + + void animateMoveImpl(final RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) { + final View view = holder.itemView; + final int deltaX = toX - fromX; + final int deltaY = toY - fromY; + if (deltaX != 0) { + view.animate().translationX(0); + } + if (deltaY != 0) { + view.animate().translationY(0); + } + // TODO: make EndActions end listeners instead, since end actions aren't called when + // vpas are canceled (and can't end them. why?) + // need listener functionality in VPACompat for this. Ick. + final ViewPropertyAnimator animation = view.animate(); + mMoveAnimations.add(holder); + animation.setDuration(getMoveDuration()).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animator) { + dispatchMoveStarting(holder); + } + + @Override + public void onAnimationCancel(Animator animator) { + if (deltaX != 0) { + view.setTranslationX(0); + } + if (deltaY != 0) { + view.setTranslationY(0); + } + } + + @Override + public void onAnimationEnd(Animator animator) { + animation.setListener(null); + dispatchMoveFinished(holder); + mMoveAnimations.remove(holder); + dispatchFinishedWhenDone(); + } + }).start(); + } + + @Override + public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, + int fromX, int fromY, int toX, int toY) { + if (oldHolder == newHolder) { + // Don't know how to run change animations when the same view holder is re-used. + // run a move animation to handle position changes. + return animateMove(oldHolder, fromX, fromY, toX, toY); + } + final float prevTranslationX = oldHolder.itemView.getTranslationX(); + final float prevTranslationY = oldHolder.itemView.getTranslationY(); + final float prevAlpha = oldHolder.itemView.getAlpha(); + resetAnimation(oldHolder); + int deltaX = (int) (toX - fromX - prevTranslationX); + int deltaY = (int) (toY - fromY - prevTranslationY); + // recover prev translation state after ending animation + oldHolder.itemView.setTranslationX(prevTranslationX); + oldHolder.itemView.setTranslationY(prevTranslationY); + oldHolder.itemView.setAlpha(prevAlpha); + if (newHolder != null) { + // carry over translation values + resetAnimation(newHolder); + newHolder.itemView.setTranslationX(-deltaX); + newHolder.itemView.setTranslationY(-deltaY); + newHolder.itemView.setAlpha(0); + } + mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY)); + return true; + } + + void animateChangeImpl(final ChangeInfo changeInfo) { + final RecyclerView.ViewHolder holder = changeInfo.oldHolder; + final View view = holder == null ? null : holder.itemView; + final RecyclerView.ViewHolder newHolder = changeInfo.newHolder; + final View newView = newHolder != null ? newHolder.itemView : null; + if (view != null) { + final ViewPropertyAnimator oldViewAnim = view.animate().setDuration( + getChangeDuration()); + mChangeAnimations.add(changeInfo.oldHolder); + oldViewAnim.translationX((float) (changeInfo.toX - changeInfo.fromX)); + oldViewAnim.translationY((float) (changeInfo.toY - changeInfo.fromY)); + oldViewAnim.alpha(0).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animator) { + dispatchChangeStarting(changeInfo.oldHolder, true); + } + + @Override + public void onAnimationEnd(Animator animator) { + oldViewAnim.setListener(null); + view.setAlpha(1); + view.setTranslationX(0); + view.setTranslationY(0); + dispatchChangeFinished(changeInfo.oldHolder, true); + mChangeAnimations.remove(changeInfo.oldHolder); + dispatchFinishedWhenDone(); + } + }).start(); + } + if (newView != null) { + final ViewPropertyAnimator newViewAnimation = newView.animate(); + mChangeAnimations.add(changeInfo.newHolder); + newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()) + .alpha(1).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animator) { + dispatchChangeStarting(changeInfo.newHolder, false); + } + + @Override + public void onAnimationEnd(Animator animator) { + newViewAnimation.setListener(null); + newView.setAlpha(1); + newView.setTranslationX(0); + newView.setTranslationY(0); + dispatchChangeFinished(changeInfo.newHolder, false); + mChangeAnimations.remove(changeInfo.newHolder); + dispatchFinishedWhenDone(); + } + }).start(); + } + } + + private void endChangeAnimation(List infoList, RecyclerView.ViewHolder item) { + for (int i = infoList.size() - 1; i >= 0; i--) { + ChangeInfo changeInfo = infoList.get(i); + if (endChangeAnimationIfNecessary(changeInfo, item)) { + if (changeInfo.oldHolder == null && changeInfo.newHolder == null) { + infoList.remove(changeInfo); + } + } + } + } + + private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) { + if (changeInfo.oldHolder != null) { + endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder); + } + if (changeInfo.newHolder != null) { + endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder); + } + } + + private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, RecyclerView.ViewHolder item) { + boolean oldItem = false; + if (changeInfo.newHolder == item) { + changeInfo.newHolder = null; + } else if (changeInfo.oldHolder == item) { + changeInfo.oldHolder = null; + oldItem = true; + } else { + return false; + } + item.itemView.setAlpha(1); + item.itemView.setTranslationX(0); + item.itemView.setTranslationY(0); + dispatchChangeFinished(item, oldItem); + return true; + } + + @Override + public void endAnimation(RecyclerView.ViewHolder item) { + final View view = item.itemView; + // this will trigger end callback which should set properties to their target values. + view.animate().cancel(); + // TODO if some other animations are chained to end, how do we cancel them as well? + for (int i = mPendingMoves.size() - 1; i >= 0; i--) { + MoveInfo moveInfo = mPendingMoves.get(i); + if (moveInfo.holder == item) { + view.setTranslationY(0); + view.setTranslationX(0); + dispatchMoveFinished(item); + mPendingMoves.remove(i); + } + } + endChangeAnimation(mPendingChanges, item); + if (mPendingRemovals.remove(item)) { + view.setAlpha(1); + dispatchRemoveFinished(item); + } + if (mPendingAdditions.remove(item)) { + view.setAlpha(1); + dispatchAddFinished(item); + } + + for (int i = mChangesList.size() - 1; i >= 0; i--) { + ArrayList changes = mChangesList.get(i); + endChangeAnimation(changes, item); + if (changes.isEmpty()) { + mChangesList.remove(i); + } + } + for (int i = mMovesList.size() - 1; i >= 0; i--) { + ArrayList moves = mMovesList.get(i); + for (int j = moves.size() - 1; j >= 0; j--) { + MoveInfo moveInfo = moves.get(j); + if (moveInfo.holder == item) { + view.setTranslationY(0); + view.setTranslationX(0); + dispatchMoveFinished(item); + moves.remove(j); + if (moves.isEmpty()) { + mMovesList.remove(i); + } + break; + } + } + } + for (int i = mAdditionsList.size() - 1; i >= 0; i--) { + ArrayList additions = mAdditionsList.get(i); + if (additions.remove(item)) { + view.setAlpha(1); + dispatchAddFinished(item); + if (additions.isEmpty()) { + mAdditionsList.remove(i); + } + } + } + + // animations should be ended by the cancel above. + //noinspection Pointless BooleanExpression,ConstantConditions + if (mRemoveAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mRemoveAnimations list"); + } + + //noinspection Pointless BooleanExpression,ConstantConditions + if (mAddAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mAddAnimations list"); + } + + //noinspection Pointless BooleanExpression,ConstantConditions + if (mChangeAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mChangeAnimations list"); + } + + //noinspection Pointless BooleanExpression,ConstantConditions + if (mMoveAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mMoveAnimations list"); + } + dispatchFinishedWhenDone(); + } + + private void resetAnimation(RecyclerView.ViewHolder holder) { + if (sDefaultInterpolator == null) { + sDefaultInterpolator = new ValueAnimator().getInterpolator(); + } + holder.itemView.animate().setInterpolator(sDefaultInterpolator); + endAnimation(holder); + } + + @Override + public boolean isRunning() { + return (!mPendingAdditions.isEmpty() + || !mPendingChanges.isEmpty() + || !mPendingMoves.isEmpty() + || !mPendingRemovals.isEmpty() + || !mMoveAnimations.isEmpty() + || !mRemoveAnimations.isEmpty() + || !mAddAnimations.isEmpty() + || !mChangeAnimations.isEmpty() + || !mMovesList.isEmpty() + || !mAdditionsList.isEmpty() + || !mChangesList.isEmpty()); + } + + /** + * Check the state of currently pending and running animations. If there are none + * pending/running, call {@link #dispatchAnimationsFinished()} to notify any + * listeners. + */ + void dispatchFinishedWhenDone() { + if (!isRunning()) { + dispatchAnimationsFinished(); + } + } + + @Override + public void endAnimations() { + int count = mPendingMoves.size(); + for (int i = count - 1; i >= 0; i--) { + MoveInfo item = mPendingMoves.get(i); + View view = item.holder.itemView; + view.setTranslationY(0); + view.setTranslationX(0); + dispatchMoveFinished(item.holder); + mPendingMoves.remove(i); + } + count = mPendingRemovals.size(); + for (int i = count - 1; i >= 0; i--) { + RecyclerView.ViewHolder item = mPendingRemovals.get(i); + dispatchRemoveFinished(item); + mPendingRemovals.remove(i); + } + count = mPendingAdditions.size(); + for (int i = count - 1; i >= 0; i--) { + RecyclerView.ViewHolder item = mPendingAdditions.get(i); + item.itemView.setAlpha(1); + dispatchAddFinished(item); + mPendingAdditions.remove(i); + } + count = mPendingChanges.size(); + for (int i = count - 1; i >= 0; i--) { + endChangeAnimationIfNecessary(mPendingChanges.get(i)); + } + mPendingChanges.clear(); + if (!isRunning()) { + return; + } + + int listCount = mMovesList.size(); + for (int i = listCount - 1; i >= 0; i--) { + ArrayList moves = mMovesList.get(i); + count = moves.size(); + for (int j = count - 1; j >= 0; j--) { + MoveInfo moveInfo = moves.get(j); + RecyclerView.ViewHolder item = moveInfo.holder; + View view = item.itemView; + view.setTranslationY(0); + view.setTranslationX(0); + dispatchMoveFinished(moveInfo.holder); + moves.remove(j); + if (moves.isEmpty()) { + mMovesList.remove(moves); + } + } + } + listCount = mAdditionsList.size(); + for (int i = listCount - 1; i >= 0; i--) { + ArrayList additions = mAdditionsList.get(i); + count = additions.size(); + for (int j = count - 1; j >= 0; j--) { + RecyclerView.ViewHolder item = additions.get(j); + View view = item.itemView; + view.setAlpha(1); + dispatchAddFinished(item); + additions.remove(j); + if (additions.isEmpty()) { + mAdditionsList.remove(additions); + } + } + } + listCount = mChangesList.size(); + for (int i = listCount - 1; i >= 0; i--) { + ArrayList changes = mChangesList.get(i); + count = changes.size(); + for (int j = count - 1; j >= 0; j--) { + endChangeAnimationIfNecessary(changes.get(j)); + if (changes.isEmpty()) { + mChangesList.remove(changes); + } + } + } + + cancelAll(mRemoveAnimations); + cancelAll(mMoveAnimations); + cancelAll(mAddAnimations); + cancelAll(mChangeAnimations); + + dispatchAnimationsFinished(); + } + + void cancelAll(List viewHolders) { + for (int i = viewHolders.size() - 1; i >= 0; i--) { + viewHolders.get(i).itemView.animate().cancel(); + } + } + + /** + * {@inheritDoc} + *

+ * If the payload list is not empty, DefaultItemAnimator returns true. + * When this is the case: + *

    + *
  • If you override {@link #animateChange(RecyclerView.ViewHolder, RecyclerView.ViewHolder, int, int, int, int)}, both + * ViewHolder arguments will be the same instance. + *
  • + *
  • + * If you are not overriding {@link #animateChange(RecyclerView.ViewHolder, RecyclerView.ViewHolder, int, int, int, int)}, + * then DefaultItemAnimator will call {@link #animateMove(RecyclerView.ViewHolder, int, int, int, int)} and + * run a move animation instead. + *
  • + *
+ */ + @Override + public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, + @NonNull List payloads) { + return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads); + } +} \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineViewModel.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineViewModel.kt new file mode 100644 index 0000000000..9f48d57ca1 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineViewModel.kt @@ -0,0 +1,111 @@ +package com.mogo.och.taxi.ui.routing + +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import com.mogo.eagle.core.utilcode.util.ToastUtils +import com.mogo.och.taxi.base.BaseViewModel +import com.mogo.och.taxi.base.IUiIntent +import com.mogo.och.taxi.bean.GrayLineBean +import com.mogo.och.taxi.bean.StartGrayAndQueryContrailRsp +import com.mogo.och.taxi.callback.ITaxiRoutingCallback +import com.mogo.och.taxi.ui.debug.DebugView + +class TaxiRoutingChooseLineViewModel : BaseViewModel(), + ITaxiRoutingCallback { + + private val TAG = SceneConstant.M_TAXI + "TaxiRoutingChooseLineViewModel" + + init { + TaxiRoutingModel.addTaxiRoutingListener(TAG, this) + } + + override fun initUiState(): TaxiRoutingUiState { + return TaxiRoutingUiState(RoutingUIState.Init) + } + + override fun handleIntent(intent: IUiIntent) { + when (intent) { + is TaxiRoutingUiIntent.QueryRoutingGrayLineList -> { + TaxiRoutingModel.queryRoutingGrayLineList() + } + + is TaxiRoutingUiIntent.StartTaskAndQueryContrail -> { + val contrailId = intent.grayLineBean.contrailId + TaxiRoutingModel.startGrayTaskAndQueryRoutingContrail( + contrailId ?: -1L, + intent.grayLineBean + ) + } + } + } + + override fun onQueryRoutingGrayLineListSuccess(data: MutableList) { + sendUiState { + copy( + routingUiState = RoutingUIState.ShowGrayLineList(data) + ) + } + } + + override fun onQueryRoutingGrayLineListFailed(errorStr: String) { + ToastUtils.showShort(errorStr) + DebugView.printErrorMsg("[查询灰度任务] 失败, error=$errorStr") + sendUiState { + copy( + routingUiState = RoutingUIState.Init + ) + } + } + + override fun onStartGrayTaskAndQueryContrailSuccess(data: StartGrayAndQueryContrailRsp) { + if (data.taskId == -1L) { + onStartGrayTaskAndQueryContrailFailed("开始任务失败, 请稍后重试") + DebugView.printErrorMsg("[开始灰度任务] 开始任务失败, 请稍后重试") + return + } + sendUiState { + copy( + routingUiState = RoutingUIState.PostRoutingTaskResult( + grayLineBean = data.grayLineBean, + contrailBean = data.contrail, + grayId = data.taskId + ) + ) + } + sendUiState { + copy( + routingUiState = RoutingUIState.HideChooseLineLoading( + isCosePage = true + ) + ) + } + } + + override fun onStartGrayTaskAndQueryContrailFailed(errorStr: String) { + ToastUtils.showShort(errorStr) + DebugView.printErrorMsg("[开始灰度任务&查询轨迹详情] 操作失败, 请稍后重试") + sendUiState { + copy( + routingUiState = RoutingUIState.HideChooseLineLoading( + isCosePage = false + ) + ) + } + } + + override fun onSubmitGrayLineIssueLocationSuccess() { + } + + override fun onSubmitGrayLineIssueLocationFailed(errorStr: String) { + } + + override fun onSubmitEndTaskSuccess() { + } + + override fun onSubmitEndTaskFailed(errorStr: String) { + } + + override fun onCleared() { + super.onCleared() + TaxiRoutingModel.removeTaxiRoutingListener(TAG) + } +} \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFeedbackDialog.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFeedbackDialog.kt new file mode 100644 index 0000000000..dfd851184e --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFeedbackDialog.kt @@ -0,0 +1,98 @@ +package com.mogo.och.taxi.ui.routing + +import android.content.Context +import android.widget.ImageView +import android.widget.TextView +import androidx.lifecycle.LifecycleObserver +import com.mogo.eagle.core.function.hmi.dialog.BaseFloatDialog +import com.mogo.och.taxi.R + +class TaxiRoutingFeedbackDialog : BaseFloatDialog, LifecycleObserver { + + private var commonConfirm: TextView? = null + private var commonCancel: TextView? = null + private var commonTips: TextView? = null + private var commonCloseIcon: ImageView? = null + private var clickListener: TaxiRoutingFeedBackDialogClickListener? = null + + constructor(builder: Builder, context: Context) : super(context) { + commonTips?.text = builder.tipsStr + commonCancel?.text = builder.cancelStr + commonConfirm?.text = builder.confirmStr + clickListener = builder.clickListener + } + + init { + setContentView(R.layout.dialog_routing_feedback_result) + + setCanceledOnTouchOutside(true) + + commonConfirm = findViewById(R.id.routing_common_confirm) + commonCancel = findViewById(R.id.routing_common_cancel) + commonTips = findViewById(R.id.routing_common_tips) + commonCloseIcon = findViewById(R.id.closeDialogIcon) + + commonCloseIcon?.setOnClickListener { + dismiss() + } + + commonConfirm?.setOnClickListener { + clickListener?.confirm() + dismiss() + } + + commonCancel?.setOnClickListener { + clickListener?.cancel() + dismiss() + } + } + + fun showDialog() { + if (isShowing) { + return + } + show() + } + + fun hideDialog() { + if (isShowing) { + dismiss() + } + } + + interface TaxiRoutingFeedBackDialogClickListener { + fun confirm() + fun cancel() + } + + class Builder { + var tipsStr: String = "" + var confirmStr: String = "" + var cancelStr: String = "" + var clickListener: TaxiRoutingFeedBackDialogClickListener? = null + + fun tips(tips: String): Builder { + this.tipsStr = tips + return this + } + + fun confirmStr(commit: String): Builder { + this.confirmStr = commit + return this + } + + fun cancelStr(cancel: String): Builder { + this.cancelStr = cancel + return this + } + + fun clickListener(listener: TaxiRoutingFeedBackDialogClickListener): Builder { + this.clickListener = listener + return this + } + + fun build(context: Context): TaxiRoutingFeedbackDialog? { + return TaxiRoutingFeedbackDialog(this, context) + } + } +} \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragment.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragment.kt new file mode 100644 index 0000000000..038ca5f52d --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragment.kt @@ -0,0 +1,326 @@ +package com.mogo.och.taxi.ui.routing + +import android.os.Bundle +import android.view.View +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import com.amap.api.navi.model.NaviLatLng +import com.mogo.commons.mvp.BaseFragment +import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager +import com.mogo.eagle.core.function.main.MainMoGoApplication +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import com.mogo.eagle.core.utilcode.util.UiThreadHandler +import com.mogo.och.common.module.map.AmapNaviToDestinationModel +import com.mogo.och.common.module.map.ICommonNaviChangedCallback +import com.mogo.och.common.module.utils.FlowBus +import com.mogo.och.taxi.R +import com.mogo.och.taxi.bean.EndGrayTaskFeedbackType +import com.mogo.och.taxi.constant.TaxiDriverEventConst +import com.mogo.och.taxi.utils.TaskUtils +import kotlinx.android.synthetic.main.routing_fragment.btnChooseTask +import kotlinx.android.synthetic.main.routing_fragment.btnFinishTask +import kotlinx.android.synthetic.main.routing_fragment.btnStartTask +import kotlinx.android.synthetic.main.routing_fragment.btnSummitIssue +import kotlinx.android.synthetic.main.routing_fragment.endPoint +import kotlinx.android.synthetic.main.routing_fragment.endStationName +import kotlinx.android.synthetic.main.routing_fragment.finishSubmitIssueGroup +import kotlinx.android.synthetic.main.routing_fragment.headerTitleContainer +import kotlinx.android.synthetic.main.routing_fragment.mCurrentTaskLayout +import kotlinx.android.synthetic.main.routing_fragment.naviToEnd +import kotlinx.android.synthetic.main.routing_fragment.naviToStart +import kotlinx.android.synthetic.main.routing_fragment.noDataContainer +import kotlinx.android.synthetic.main.routing_fragment.startPoint +import kotlinx.android.synthetic.main.routing_fragment.startStationName +import kotlinx.android.synthetic.main.routing_fragment.taskTitleTv +import kotlinx.android.synthetic.main.routing_fragment.taskTripInfo +import kotlinx.coroutines.flow.map + +class TaxiRoutingFragment : BaseFragment(), ICommonNaviChangedCallback { + + companion object { + const val TAG = SceneConstant.M_TAXI + "TaxiRoutingFragment" + + fun newInstance(): TaxiRoutingFragment { + val args = Bundle() + val fragment = TaxiRoutingFragment() + fragment.arguments = args + return fragment + } + } + + private var mFeedbackDialog: TaxiRoutingFeedbackDialog? = null + + private val mViewModel: TaxiRoutingFragmentViewModel by lazy { + ViewModelProvider( + this, + ViewModelProvider.NewInstanceFactory() + )[TaxiRoutingFragmentViewModel::class.java] + } + + override fun getLayoutId(): Int { + return R.layout.routing_fragment + } + + override fun getTagName(): String { + return "TaxiRoutingFragment" + } + + override fun initViews() { + initEventBus() + initViewListener() + initViewModelObserver() + } + + private fun initEventBus() { + FlowBus.with(TaxiDriverEventConst.RoutingActivityEvent.EVENT_TYPE_GET_CHOSEN_LINE_TASK) + .register(this) { task -> + mViewModel.sendUiIntent(TaxiRoutingUiIntent.ShowRoutingTask(task)) + } + } + + private fun initViewListener() { + btnChooseTask.setOnClickListener { + mViewModel.sendUiIntent(TaxiRoutingUiIntent.StartChooseLineAction(System.currentTimeMillis())) + } + } + + private fun initViewModelObserver() { + lifecycleScope.launchWhenStarted { + mViewModel.uiStateFlow.map { it.routingUiState }.collect { routingUiState -> + CallerLogger.d( + TAG, + "uiStateFlow-initViewModelObserver: $routingUiState" + ) + when (routingUiState) { + is RoutingUIState.Init -> { + showChooseTaskView() + AmapNaviToDestinationModel.getInstance(context).destroyAmaNavi() + } + + is RoutingUIState.RoutingTask -> { + showCurrentLineTaskContentView(routingUiState) + } + + is RoutingUIState.ShowFinishTaskButton -> { + showFinishTaskView(routingUiState.routingTask) + } + + is RoutingUIState.ShowFeedbackDialog -> { + showFeedbackDialog(routingUiState.grayId) + } + + is RoutingUIState.DismissFeedbackDialog -> { + hideFeedbackDialog() + } + } + } + } + } + + private fun showChooseTaskView() { + noDataContainer.visibility = View.VISIBLE + mCurrentTaskLayout.visibility = View.GONE + headerTitleContainer.visibility = View.GONE + + btnChooseTask.visibility = View.VISIBLE + btnStartTask.visibility = View.GONE + finishSubmitIssueGroup.visibility = View.GONE + } + + private fun showCurrentLineTaskContentView(data: RoutingUIState.RoutingTask) { + noDataContainer.visibility = View.GONE + mCurrentTaskLayout.visibility = View.VISIBLE + + headerTitleContainer.visibility = View.VISIBLE + taskTitleTv.text = data.grayLineBean?.lineName + + btnChooseTask.visibility = View.GONE + btnStartTask.visibility = View.VISIBLE + btnStartTask.setOnClickListener { + mViewModel.sendUiIntent(TaxiRoutingUiIntent.StartTaskAction(data)) + } + finishSubmitIssueGroup.visibility = View.GONE + + naviToStart.visibility = View.VISIBLE + naviToEnd.visibility = View.INVISIBLE + updateStartAndEndStationPointByStatus(false) + updateCurrentTaskTripInfo(0,0) + + data.grayLineBean?.startSite?.also { + initStartNaviToStationParam( + false, + it.gcjLat, + it.gcjLon + ) + naviToStart.setOnClickListener { + showNaviToEndStationFragment(true) + } + } + + startStationName.text = data.grayLineBean?.startSite?.siteName + endStationName.text = data.grayLineBean?.endSite?.siteName + } + + private fun showFinishTaskView(routingTask: RoutingUIState.RoutingTask) { + btnChooseTask.visibility = View.GONE + btnStartTask.visibility = View.GONE + finishSubmitIssueGroup.visibility = View.VISIBLE + btnFinishTask.setOnClickListener { + mViewModel.sendUiIntent( + TaxiRoutingUiIntent.ShowFeedbackDialog( + routingTask.grayId ?: -1 + ) + ) + } + btnSummitIssue.setOnClickListener { + mViewModel.sendUiIntent( + TaxiRoutingUiIntent.SubmitGrayLineIssueLocation( + routingTask.grayId ?: -1L + ) + ) + } + + naviToStart.visibility = View.INVISIBLE + naviToEnd.visibility = View.VISIBLE + updateStartAndEndStationPointByStatus(true) + updateCurrentTaskTripInfo(0,0) + + routingTask.grayLineBean?.endSite?.also { + initStartNaviToStationParam( + false, + it.gcjLat, + it.gcjLon + ) + naviToEnd.setOnClickListener { + showNaviToEndStationFragment(true) + } + } + } + + private fun updateStartAndEndStationPointByStatus(isGoingToStation: Boolean) { + if (isGoingToStation) {// 即将到达的站点 + startPoint.setImageResource(R.drawable.taxi_driver_circle_blue_big) + endPoint.setImageResource(R.drawable.taxi_driver_circle_green_big) + } else {// 到达站点 或 已经经过的站点 + startPoint.setImageResource(R.drawable.taxi_driver_circle_green_big) + endPoint.setImageResource(R.drawable.taxi_driver_circle_blue_big) + } + } + + private fun showFeedbackDialog(grayId: Long) { + if (mFeedbackDialog == null) { + val builder: TaxiRoutingFeedbackDialog.Builder = TaxiRoutingFeedbackDialog.Builder() + builder.cancelStr( + MainMoGoApplication.getApp() + .getString(R.string.routing_feedback_result_btn_not_sure) + ).confirmStr( + MainMoGoApplication.getApp() + .getString(R.string.routing_feedback_result_btn_sure) + ).tips(MainMoGoApplication.getApp().getString(R.string.routing_feedback_result_hint)) + .clickListener(object : + TaxiRoutingFeedbackDialog.TaxiRoutingFeedBackDialogClickListener { + override fun confirm() { + mViewModel.sendUiIntent( + TaxiRoutingUiIntent.SubmitEndTask( + grayId, + EndGrayTaskFeedbackType.USABLE_YES + ) + ) + } + + override fun cancel() { + mViewModel.sendUiIntent( + TaxiRoutingUiIntent.SubmitEndTask( + grayId, + EndGrayTaskFeedbackType.USABLE_NO + ) + ) + } + }) + activity?.also { + mFeedbackDialog = builder.build(it) + mFeedbackDialog?.showDialog() + } + } else { + activity?.also { + mFeedbackDialog?.showDialog() + } + } + } + + private fun hideFeedbackDialog() { + mFeedbackDialog?.hideDialog() + } + + /** + * 显示/隐藏 前往任务目的地的导航 + * + * @param isShow + */ + private fun showNaviToEndStationFragment(isShow: Boolean) { +// FlowBus.with(TaxiDriverEventConst.TaxiFragmentEvent.EVENT_TYPE_START_NAVI_TO_END_STATION) +// .post(this.lifecycleScope, isShow) + TaxiRoutingModel.startNaviToEndStationByAMap(isShow) + } + + private fun initStartNaviToStationParam( + isVoicePlay: Boolean, + stationLat: Double, + stationLng: Double + ) { + AmapNaviToDestinationModel.getInstance(context).destroyAmaNavi() + val mCurLatitude = + CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02().latitude + val mCurLongitude = + CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02().longitude + CallerLogger.d( + TAG, + "currentLocation, lat=$mCurLatitude, lon=$mCurLongitude" + ) + val startNaviLatLng = NaviLatLng(mCurLatitude, mCurLongitude) + val endNaviLatLng = NaviLatLng(stationLat, stationLng) + AmapNaviToDestinationModel.getInstance(context).initAMapNavi(startNaviLatLng, endNaviLatLng) + AmapNaviToDestinationModel.getInstance(context).setVoiceIsMute(isVoicePlay) + AmapNaviToDestinationModel.getInstance(context).setTaxiNaviChangedCallback(this) + } + + override fun onCurrentNaviDistAndTimeChanged(meters: Int, timeInSecond: Long) { + updateCurrentTaskTripInfo(meters.toLong(), timeInSecond) + } + + override fun reInitNaviAmap(isPlay: Boolean, isRestart: Boolean) { + CallerLogger.d(TAG, "isPlay = $isPlay, isRestart=$isRestart") + if (!isRestart) { +// FlowBus.with(TaxiDriverEventConst.TaxiFragmentEvent.EVENT_TYPE_SHOW_AMAP_NAVI_TO_STATION_FRAGMENT) +// .post(this.lifecycleScope, false) + TaxiRoutingModel.startNaviToEndStationByAMap(false) + return + } + } + + /** + * 剩余里程和剩余时间 + * @param meters 米 + * @param timeInSecond 秒 + */ + private fun updateCurrentTaskTripInfo(meters: Long, timeInSecond: Long) { + UiThreadHandler.post { + CallerLogger.d( + TAG, + "updateCurrentTaskTripInfo, taskUtil, ${ + TaskUtils.getCurrentTaskTripHtml( + meters, + timeInSecond + ) + }" + ) + taskTripInfo.text = TaskUtils.getCurrentTaskTripHtml(meters, timeInSecond) + } + } + + override fun onDestroyView() { + AmapNaviToDestinationModel.getInstance(context).destroyAmaNavi() + super.onDestroyView() + } +} \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragmentViewModel.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragmentViewModel.kt new file mode 100644 index 0000000000..8afde1aa64 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragmentViewModel.kt @@ -0,0 +1,154 @@ +package com.mogo.och.taxi.ui.routing + +import android.content.Context +import android.content.Intent +import com.mogo.commons.AbsMogoApplication +import com.mogo.commons.module.status.MogoStatusManager +import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import com.mogo.eagle.core.utilcode.util.ToastUtils +import com.mogo.och.taxi.base.BaseViewModel +import com.mogo.och.taxi.base.IUiIntent +import com.mogo.och.taxi.bean.GrayLineBean +import com.mogo.och.taxi.bean.StartGrayAndQueryContrailRsp +import com.mogo.och.taxi.callback.ITaxiRoutingCallback +import com.mogo.och.taxi.ui.debug.DebugView + +class TaxiRoutingFragmentViewModel : BaseViewModel(), + ITaxiRoutingCallback { + + companion object { + const val TAG = SceneConstant.M_TAXI + "TaxiRoutingFragmentViewModel" + } + + init { + TaxiRoutingModel.addTaxiRoutingListener(TAG, this) + } + + private val mContext: Context + get() = AbsMogoApplication.getApp().applicationContext + + override fun initUiState(): TaxiRoutingUiState { + return TaxiRoutingUiState(RoutingUIState.Init) + } + + override fun handleIntent(intent: IUiIntent) { + when (intent) { + is TaxiRoutingUiIntent.StartChooseLineAction -> { + DebugView.printInfoMsg("[选择任务] 跳转到选择任务列表") + val intent = Intent(mContext, TaxiRoutingChooseLineActivity::class.java) + mContext?.startActivity(intent) + } + + is TaxiRoutingUiIntent.ShowRoutingTask -> { + DebugView.printInfoMsg("[选择任务] 展示当前选择任务,刷新UI") + val task = intent.routingTask + sendUiState { + copy( + routingUiState = RoutingUIState.RoutingTask( + task.grayLineBean, + task.contrailBean, + task.grayId + ) + ) + } + // 设置灰度路线任务执行状态,切换模式时判断使用 + MogoStatusManager.getInstance().setTaxiUnmanedDriverLineRoutingPerformTask(TAG, true) + } + + is TaxiRoutingUiIntent.StartTaskAction -> { + DebugView.printInfoMsg("[开始任务] 准备开始任务") + val grayLineBean = intent.routingTask.grayLineBean + val contrailBean = intent.routingTask.contrailBean + if (grayLineBean == null || contrailBean == null) { + ToastUtils.showShort("灰度线路或轨迹信息异常,请稍后再试") + DebugView.printErrorMsg("[开始任务] 灰度线路或轨迹信息异常,请稍后再试") + return + } + DebugView.printInfoMsg("[启自驾] 准备启动自驾") + TaxiRoutingModel.updateCurrentGrayLineAndContrail(grayLineBean, contrailBean) + TaxiRoutingModel.startAutoPilot(grayLineBean!!, contrailBean!!) + sendUiState { + copy( + routingUiState = RoutingUIState.ShowFinishTaskButton(intent.routingTask) + ) + } + } + + is TaxiRoutingUiIntent.SubmitGrayLineIssueLocation -> { + DebugView.printInfoMsg("[上报打点] 准备上报打点") + val grayId = intent.grayId + val currentLocation = + CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02() + TaxiRoutingModel.submitGrayLineIssueLocation( + grayId, + currentLocation.longitude, + currentLocation.latitude + ) + } + + is TaxiRoutingUiIntent.ShowFeedbackDialog -> { + DebugView.printInfoMsg("[结束任务] 展示结束任务弹框") + sendUiState { + copy( + routingUiState = RoutingUIState.ShowFeedbackDialog( + intent.grayId, + System.currentTimeMillis() + ) + ) + } + } + + is TaxiRoutingUiIntent.SubmitEndTask -> { + DebugView.printInfoMsg("[结束任务] 准备结束任务,grayId=${intent.grayId}, type=${intent.type.name}") + TaxiRoutingModel.endGrayTask(intent.grayId, intent.type) + } + } + } + + override fun onQueryRoutingGrayLineListSuccess(data: MutableList) { + } + + override fun onQueryRoutingGrayLineListFailed(errorStr: String) { + } + + override fun onStartGrayTaskAndQueryContrailSuccess(data: StartGrayAndQueryContrailRsp) { + } + + override fun onStartGrayTaskAndQueryContrailFailed(errorStr: String) { + } + + override fun onSubmitGrayLineIssueLocationSuccess() { + ToastUtils.showShort("问题记录成功") + } + + override fun onSubmitGrayLineIssueLocationFailed(errorStr: String) { + ToastUtils.showShort("问题记录失败:$errorStr") + } + + override fun onSubmitEndTaskSuccess() { + ToastUtils.showLong("结束任务成功") + sendUiState { + copy( + routingUiState = RoutingUIState.Init + ) + } + TaxiRoutingModel.updateCurrentGrayLineAndContrail(null, null) + // 设置灰度路线任务执行状态,切换模式时判断使用 + MogoStatusManager.getInstance().setTaxiUnmanedDriverLineRoutingPerformTask(TAG, false) + } + + override fun onSubmitEndTaskFailed(errorStr: String) { + ToastUtils.showLong("结束任务失败") + sendUiState { + copy( + routingUiState = RoutingUIState.DismissFeedbackDialog + ) + } + } + + override fun onCleared() { + TaxiRoutingModel.removeTaxiRoutingListener(TAG) + super.onCleared() + } +} \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingLoadingDialog.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingLoadingDialog.kt new file mode 100644 index 0000000000..2b7c726e84 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingLoadingDialog.kt @@ -0,0 +1,73 @@ +package com.mogo.och.taxi.ui.routing + +import android.animation.ObjectAnimator +import android.content.Context +import android.view.animation.LinearInterpolator +import androidx.lifecycle.LifecycleObserver +import com.mogo.eagle.core.function.hmi.dialog.BaseFloatDialog +import com.mogo.eagle.core.utilcode.util.ToastUtils +import com.mogo.och.taxi.R +import kotlinx.android.synthetic.main.dialog_routing_loading.dialog_loading_text +import kotlinx.android.synthetic.main.dialog_routing_loading.dialog_loading_view + +/** + * loading + */ +class TaxiRoutingLoadingDialog : BaseFloatDialog, LifecycleObserver { + private var objectAnimator: ObjectAnimator? = null + private val mLoadingView by lazy { dialog_loading_view } + private val mLoadingText by lazy { dialog_loading_text } + private var mRunnable:Runnable= Runnable { + ToastUtils.showLong("超时未响应,请求失败") + hideLoading() + } + + constructor(context: Context) : super(context) + + init { + setContentView(R.layout.dialog_routing_loading) + setCanceledOnTouchOutside(false) + } + + /** + * 开始旋转 + */ + private fun startRotation() { + objectAnimator = ObjectAnimator.ofFloat(mLoadingView, "rotation", -720f, 0f) + objectAnimator?.let { + it.duration = 3000 + it.repeatCount = -1 + it.interpolator = LinearInterpolator() + it.start() + } + } + + /** + * 停止旋转 + */ + private fun stopRotation() { + objectAnimator?.let { + if (it.isRunning) { + it.end() + objectAnimator = null + } + } + } + + /** + * 显示dialog + */ + fun showLoading() { + mLoadingText.text = "请求中,请稍后..." + startRotation() + show() + } + + /** + * 隐藏dialog + */ + fun hideLoading() { + stopRotation() + dismiss() + } +} \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingModel.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingModel.kt new file mode 100644 index 0000000000..e3eec1bbb3 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingModel.kt @@ -0,0 +1,409 @@ +package com.mogo.och.taxi.ui.routing + +import android.content.Context +import android.text.TextUtils +import com.mogo.cloud.passport.MoGoAiCloudClientConfig +import com.mogo.commons.AbsMogoApplication +import com.mogo.eagle.core.data.BaseData +import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters +import com.mogo.eagle.core.data.config.FunctionBuildConfig +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager +import com.mogo.eagle.core.network.utils.GsonUtil +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import com.mogo.eagle.core.utilcode.util.GsonUtils +import com.mogo.eagle.core.utilcode.util.NetworkUtils +import com.mogo.eagle.core.utilcode.util.ToastUtils +import com.mogo.och.common.module.biz.network.OchCommonServiceCallback +import com.mogo.och.common.module.manager.autopilotmanager.OCHAdasAbilityManager +import com.mogo.och.taxi.bean.ContrailBean +import com.mogo.och.taxi.bean.EndGrayContrailTaskReq +import com.mogo.och.taxi.bean.EndGrayTaskFeedbackType +import com.mogo.och.taxi.bean.GrayLineBean +import com.mogo.och.taxi.bean.QueryGrayContrailListRsp +import com.mogo.och.taxi.bean.StartGrayAndQueryContrailRsp +import com.mogo.och.taxi.bean.SubmitGrayLineIssueLocationReq +import com.mogo.och.taxi.callback.ITaxiControllerStatusCallback +import com.mogo.och.taxi.callback.ITaxiOrderStatusCallback +import com.mogo.och.taxi.callback.ITaxiRoutingCallback +import com.mogo.och.taxi.constant.TaxiUnmannedConst +import com.mogo.och.taxi.network.TaxiRoutingServiceManager +import com.mogo.och.taxi.ui.debug.DebugView +import java.util.concurrent.ConcurrentHashMap + +object TaxiRoutingModel { + private val TAG = SceneConstant.M_TAXI + TaxiRoutingModel::class.java.simpleName + + private val mContext: Context + get() = AbsMogoApplication.getApp().applicationContext + + private var currentGrayLineBean: GrayLineBean? = null + private var currentContrailBean: ContrailBean? = null + + private val mTaxiRoutingCallbackMap: ConcurrentHashMap = + ConcurrentHashMap() + + fun addTaxiRoutingListener(tag: String, listener: ITaxiRoutingCallback) { + if (mTaxiRoutingCallbackMap.containsKey(tag)) { + return + } + mTaxiRoutingCallbackMap[tag] = listener + } + + fun removeTaxiRoutingListener(tag: String) { + if (!mTaxiRoutingCallbackMap.containsKey(tag)) { + return + } + mTaxiRoutingCallbackMap.remove(tag) + } + + private var mControllerStatusCallback: ITaxiControllerStatusCallback? = null + + fun setControllerStatusCallback(callback: ITaxiControllerStatusCallback?) { + mControllerStatusCallback = callback + } + + private var mOrderStatusCallback: ITaxiOrderStatusCallback? = null + + fun setOrderStatusCallback(callback: ITaxiOrderStatusCallback?) { + mOrderStatusCallback = callback + } + + fun queryRoutingGrayLineList() { + DebugView.printInfoMsg("[查询灰度路线] 准备发送请求,sn=${MoGoAiCloudClientConfig.getInstance().sn}") + TaxiRoutingServiceManager.queryRoutingGrayLineList(mContext, + object : OchCommonServiceCallback { + override fun onSuccess(data: QueryGrayContrailListRsp) { + CallerLogger.d( + TAG, + "queryRoutingGrayLineList onSuccess: data=${GsonUtils.toJson(data)}" + ) + DebugView.printInfoMsg("[查询灰度路线] 请求success,dataSize=${data?.data?.size}") + val result = mutableListOf() + data.data?.also { + result.addAll(it) + } + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onQueryRoutingGrayLineListSuccess(result) + } + } + + override fun onFail(code: Int, msg: String?) { + CallerLogger.d( + TAG, + "queryRoutingGrayLineList onFail: code=$code, msg=$msg" + ) + DebugView.printErrorMsg("[查询灰度路线] 请求fail, code=$code, msg=$msg, sn=${MoGoAiCloudClientConfig.getInstance().sn}") + ToastUtils.showShort("查询灰度线路列表异常, 请稍后重试, code=$code") + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onQueryRoutingGrayLineListFailed( + msg ?: "查询灰度线路列表异常, 请稍后重试" + ) + } + } + + override fun onError() { + super.onError() + var hintStr = "" + if (!NetworkUtils.isConnected(mContext)) { + hintStr = "网络出现异常,请稍后重试" + } else { + hintStr = "查询灰度线路列表异常, 请稍后重试" + } + CallerLogger.d( + TAG, + "queryRoutingGrayLineList onError, msg=$hintStr, sn=${MoGoAiCloudClientConfig.getInstance().sn}" + ) + DebugView.printErrorMsg("[查询灰度路线] 请求error, msg=$hintStr") + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onQueryRoutingGrayLineListFailed(hintStr) + } + } + }) + } + + fun startGrayTaskAndQueryRoutingContrail(contrailId: Long, grayLineBean: GrayLineBean) { + DebugView.printInfoMsg("[开始灰度任务&查询轨迹详情] 准备发送请求,contrailId=${contrailId}, lineId=${grayLineBean.lineId}") + TaxiRoutingServiceManager.startGrayTaskAndQueryRoutingContrail( + mContext, + sn = MoGoAiCloudClientConfig.getInstance().sn, + contrailId = contrailId, + grayLineBean = grayLineBean, + object : OchCommonServiceCallback { + override fun onSuccess(data: StartGrayAndQueryContrailRsp) { + CallerLogger.d( + TAG, + "startGrayTaskAndQueryRoutingContrail onSuccess: data=${ + GsonUtils.toJson( + data + ) + }" + ) + DebugView.printInfoMsg("[开始灰度任务&查询轨迹详情] 请求success,taskId=${data.taskId}, contrailId=${contrailId}, lineId=${grayLineBean.lineId}") + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onStartGrayTaskAndQueryContrailSuccess(data) + } + } + + override fun onFail(code: Int, msg: String?) { + CallerLogger.d( + TAG, + "startGrayTaskAndQueryRoutingContrail onFail: code=$code, msg=$msg" + ) + DebugView.printErrorMsg("[开始灰度任务&查询轨迹详情] 请求fail, code=$code, msg=$msg, contrailId=${contrailId}, lineId=${grayLineBean.lineId}") + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onStartGrayTaskAndQueryContrailFailed( + msg ?: "startGrayTaskAndQueryRoutingContrail onFail" + ) + } + } + + override fun onError() { + super.onError() + var hintStr = "" + if (!NetworkUtils.isConnected(mContext)) { + hintStr = "网络出现异常,请稍后重试" + } else { + hintStr = "开始任务并查询轨迹详情异常, 请稍后重试" + } + CallerLogger.d( + TAG, + "startGrayTaskAndQueryRoutingContrail onError, msg=$hintStr, contrailId=${contrailId}, lineId=${grayLineBean.lineId}" + ) + DebugView.printErrorMsg("[开始灰度任务&查询轨迹详情] 请求error, msg=$hintStr") + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onStartGrayTaskAndQueryContrailFailed(hintStr) + } + } + } + ) + } + + fun submitGrayLineIssueLocation(grayId: Long, gcjLon: Double, gcjLat: Double) { + DebugView.printInfoMsg("[上报打点] 准备发送请求,grayId=$grayId, gcjLon=$gcjLon, gcjLat=$gcjLat") + val submit = SubmitGrayLineIssueLocationReq(grayId, gcjLon, gcjLat) + TaxiRoutingServiceManager.submitGrayLineIssueLocation( + mContext, + submit, + object : OchCommonServiceCallback { + override fun onSuccess(data: BaseData?) { + CallerLogger.d( + TAG, + "submitGrayLineIssueLocation onSuccess: data=${ + GsonUtils.toJson( + data + ) + }" + ) + DebugView.printInfoMsg("[上报打点] 准备success,grayId=$grayId, gcjLon=$gcjLon, gcjLat=$gcjLat") + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onSubmitGrayLineIssueLocationSuccess() + } + } + + override fun onFail(code: Int, msg: String?) { + CallerLogger.d( + TAG, + "submitGrayLineIssueLocation onFail: code=$code, msg=$msg" + ) + DebugView.printErrorMsg("[上报打点] 请求fail, code=$code, msg=$msg, grayId=$grayId") + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onSubmitGrayLineIssueLocationFailed( + msg ?: "submitGrayLineIssueLocation onFail" + ) + } + } + + override fun onError() { + super.onError() + var hintStr = "" + if (!NetworkUtils.isConnected(mContext)) { + hintStr = "网络出现异常,请稍后重试" + } else { + hintStr = "上报问题打点异常, 请稍后重试" + } + CallerLogger.d( + TAG, + "submitGrayLineIssueLocation onError, msg=$hintStr" + ) + DebugView.printErrorMsg("[上报打点] 请求error, msg=$hintStr, grayId=$grayId") + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onSubmitGrayLineIssueLocationFailed(hintStr) + } + } + } + ) + } + + fun endGrayTask(grayId: Long, type: EndGrayTaskFeedbackType) { + DebugView.printInfoMsg("[结束灰度任务] 准备发送请求,grayId=$grayId, type=${type.type}, typeName=${type.name}") + val submit = EndGrayContrailTaskReq(grayId, type.type) + TaxiRoutingServiceManager.endGrayTask( + mContext, + submit, + object : OchCommonServiceCallback { + override fun onSuccess(data: BaseData?) { + CallerLogger.d( + TAG, + "endGrayTask onSuccess: data=${ + GsonUtils.toJson( + data + ) + }" + ) + DebugView.printInfoMsg("[结束灰度任务] 请求success,grayId=$grayId, type=${type.type}, typeName=${type.name}") + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onSubmitEndTaskSuccess() + } + } + + override fun onFail(code: Int, msg: String?) { + CallerLogger.d( + TAG, + "endGrayTask onFail: code=$code, msg=$msg" + ) + DebugView.printErrorMsg("[结束灰度任务] 请求fail, code=$code, msg=$msg, grayId=$grayId, type=${type.type}, typeName=${type.name}") + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onSubmitEndTaskFailed( + msg ?: "endGrayTask onFail" + ) + } + } + + override fun onError() { + super.onError() + var hintStr = "" + if (!NetworkUtils.isConnected(mContext)) { + hintStr = "网络出现异常,请稍后重试" + } else { + hintStr = "上报结束任务异常, 请稍后重试" + } + CallerLogger.d( + TAG, + "endGrayTask onError, msg=$hintStr" + ) + DebugView.printErrorMsg("[结束灰度任务] 请求error, msg=$hintStr, grayId=$grayId, type=${type.type}, typeName=${type.name}") + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onSubmitEndTaskFailed(hintStr) + } + } + }) + } + + fun updateCurrentGrayLineAndContrail(grayLineBean: GrayLineBean?, contrailBean: ContrailBean?) { + currentGrayLineBean = grayLineBean + currentContrailBean = contrailBean + } + + fun startAutoPilotByClick() { + if (currentGrayLineBean == null || currentContrailBean == null) { + CallerLogger.e(TAG, "startAutoPilotByClick 异常,currentGrayLineBean == null || currentContrailBean == null") + DebugView.printErrorMsg("[启自驾] startAutoPilotByClick 异常,currentGrayLineBean == null || currentContrailBean == null") + return + } + startAutoPilot(currentGrayLineBean!!, currentContrailBean!!) + } + + fun startAutoPilot(grayLineBean: GrayLineBean, contrailBean: ContrailBean) { + if (grayLineBean.startSite == null || grayLineBean.endSite == null) { + CallerLogger.e(TAG, "start site or end site is null") + DebugView.printErrorMsg("[启自驾] 当前订单不存在或异常!") + ToastUtils.showShort("当前订单不存在或异常!") + return + } + //根据开关和后台是否发布轨迹启动自驾 + if (FunctionBuildConfig.isPassStartAutopilotCommand && TextUtils.isEmpty( + contrailBean.csvFileUrl + ) + ) { + ToastUtils.showLong("无发布轨迹, 请发布后重试") + DebugView.printErrorMsg("[启自驾] 无发布轨迹, 请发布后重试") + CallerLogger.e( + TAG, "isPassStartAutopilotCommand = " + + FunctionBuildConfig.isPassStartAutopilotCommand + + "busRoutesResult.csvFileUrl = " + contrailBean.csvFileUrl + ) + return + } + if (!FunctionBuildConfig.isDemoMode && !OCHAdasAbilityManager.getInstance().autopilotAbilityStatus) { + DebugView.printErrorMsg("[启自驾] ${OCHAdasAbilityManager.getInstance().autopilotUnAbilityReason}") + ToastUtils.showLong( + OCHAdasAbilityManager.getInstance().autopilotUnAbilityReason + + ", 请稍候重试" + ) + return + } + + val parameters = initAutopilotControlParameters(grayLineBean, contrailBean) + if (null == parameters) { + CallerLogger.e(TAG, "AutopilotControlParameters is empty.") + return + } + + CallerAutoPilotControlManager.startAutoPilot(parameters) + DebugView.printInfoMsg("[启自驾] 调用成功") + CallerLogger.d( + TAG, "start autopilot with parameter: %s", + GsonUtil.jsonFromObject(parameters) + ) + mControllerStatusCallback?.startOpenAutopilot() + } + + private fun initAutopilotControlParameters( + grayLineBean: GrayLineBean, + contrailBean: ContrailBean + ): AutopilotControlParameters? { + val parameters = AutopilotControlParameters() + val startWgsLon = grayLineBean.startSite!!.wgs84Lon + val startWgsLat = grayLineBean.startSite!!.wgs84Lat + val endWgsLon = grayLineBean.endSite!!.wgs84Lon + val endWgsLat = grayLineBean.endSite!!.wgs84Lat + parameters.vehicleType = TaxiUnmannedConst.BUSINESSTYPE + parameters.startName = + grayLineBean.startSite!!.siteName // 8.10 拼音首字母大写 改为直接传中文 + parameters.endName = + grayLineBean.endSite!!.siteName // 8.10 拼音首字母大写 改为直接传中文 + parameters.startLatLon = + AutopilotControlParameters.AutoPilotLonLat(startWgsLat, startWgsLon) + parameters.endLatLon = AutopilotControlParameters.AutoPilotLonLat(endWgsLat, endWgsLon) + if (parameters.autoPilotLine == null) { + parameters.autoPilotLine = AutopilotControlParameters.AutoPilotLine( + contrailBean.lineId, + contrailBean.lineName, + contrailBean.csvFileUrl, + contrailBean.csvFileMd5, + contrailBean.txtFileUrl, + contrailBean.txtFileMd5, + contrailBean.contrailSaveTime, + TaxiUnmannedConst.BUSINESSTYPE.toString(), + contrailBean.csvFileUrlDPQP, + contrailBean.csvFileMd5DPQP, + contrailBean.txtFileUrlDPQP, + contrailBean.txtFileMd5DPQP, + contrailBean.contrailSaveTimeDPQP + ) + } + return parameters + } + + /** + * 显示/隐藏 前往任务目的地的导航 + * + * @param isShow + */ + fun startNaviToEndStationByAMap(isShow: Boolean) { + mOrderStatusCallback?.onNaviToEnd(true, isShow) + } +} \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiIntent.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiIntent.kt new file mode 100644 index 0000000000..6a39b3f763 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiIntent.kt @@ -0,0 +1,34 @@ +package com.mogo.och.taxi.ui.routing + +import com.mogo.och.taxi.base.IUiIntent +import com.mogo.och.taxi.bean.EndGrayTaskFeedbackType +import com.mogo.och.taxi.bean.GrayLineBean + +sealed class TaxiRoutingUiIntent : IUiIntent { + + //打开选择路线页面 + data class StartChooseLineAction(val currentTimestamp: Long) : TaxiRoutingUiIntent() + + //查询灰度线路列表 + data class QueryRoutingGrayLineList(val currentTimestamp: Long) : TaxiRoutingUiIntent() + + //开始一个任务并查询此任务对应的轨迹详情 + data class StartTaskAndQueryContrail(val grayLineBean: GrayLineBean) : TaxiRoutingUiIntent() + + //展示Routing任务信息 + data class ShowRoutingTask(val routingTask: RoutingUIState.RoutingTask) : + TaxiRoutingUiIntent() + + //开始任务 + data class StartTaskAction(val routingTask: RoutingUIState.RoutingTask) : TaxiRoutingUiIntent() + + //问题打点 + data class SubmitGrayLineIssueLocation(val grayId: Long) : TaxiRoutingUiIntent() + + //展示结束任务反馈弹框 + data class ShowFeedbackDialog(val grayId: Long) : TaxiRoutingUiIntent() + + //结束任务 + data class SubmitEndTask(val grayId: Long, val type: EndGrayTaskFeedbackType) : + TaxiRoutingUiIntent() +} \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiState.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiState.kt new file mode 100644 index 0000000000..9aef55856b --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiState.kt @@ -0,0 +1,33 @@ +package com.mogo.och.taxi.ui.routing + +import com.mogo.och.taxi.base.IUiState +import com.mogo.och.taxi.bean.ContrailBean +import com.mogo.och.taxi.bean.GrayLineBean + +data class TaxiRoutingUiState(val routingUiState: RoutingUIState) : IUiState + +sealed class RoutingUIState { + object Init : RoutingUIState() + + data class ShowGrayLineList(var data: MutableList) : RoutingUIState() + + data class HideChooseLineLoading(var isCosePage: Boolean) : RoutingUIState() + + data class PostRoutingTaskResult( + val grayLineBean: GrayLineBean?, + val contrailBean: ContrailBean?, + val grayId: Long? + ) : RoutingUIState() + + data class RoutingTask( + val grayLineBean: GrayLineBean?, + val contrailBean: ContrailBean?, + val grayId: Long? + ) : RoutingUIState() + + data class ShowFinishTaskButton(val routingTask: RoutingTask) : RoutingUIState() + data class ShowFeedbackDialog(val grayId: Long, val currentTimestamp: Long) : RoutingUIState() + object DismissFeedbackDialog : RoutingUIState() +} + + diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/task/TaxiCurrentTaskViewModel.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/task/TaxiCurrentTaskViewModel.kt index 5ac0b87dee..e08f21d5a1 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/task/TaxiCurrentTaskViewModel.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/task/TaxiCurrentTaskViewModel.kt @@ -1,6 +1,7 @@ package com.mogo.och.taxi.ui.task import com.mogo.commons.AbsMogoApplication +import com.mogo.commons.module.status.MogoStatusManager import com.mogo.eagle.core.data.BaseData import com.mogo.eagle.core.data.config.FunctionBuildConfig import com.mogo.eagle.core.data.map.MogoLocation @@ -229,6 +230,12 @@ class TaxiCurrentTaskViewModel : BaseViewModel(), d(TAG, "onTaskWithOrderChanged = result = " + GsonUtil.jsonFromObject(result)) DebugView.printInfoMsg("[查询TaskWithOrder信息] 更新数据, 刷新UI") updateTaskAndOrderUi(result) + // 设置task执行相关状态,切换模式时判断使用 + if (result == null || result.taskType == TaskTypeEnum.None.code) { + MogoStatusManager.getInstance().setTaxiUnmanedDriverPerformTask(TAG, false) + } else { + MogoStatusManager.getInstance().setTaxiUnmanedDriverPerformTask(TAG, true) + } } override fun onTaskStarted(result: QueryCurrentTaskRespBean.Result?) { @@ -318,6 +325,8 @@ class TaxiCurrentTaskViewModel : BaseViewModel(), VoiceNotice.showNotice("已取消行程") //取消自驾,D档位会溜车 map3.6.0 修改 TaxiTaskModel.cancelAutopilot() + // 设置task执行相关状态,切换模式时判断使用 + MogoStatusManager.getInstance().setTaxiUnmanedDriverPerformTask(TAG, false) } override fun onOrderArriveAtEnd(orderNo: String) { @@ -339,6 +348,8 @@ class TaxiCurrentTaskViewModel : BaseViewModel(), TaxiTaskModel.startPrepareTaskDelay(CallerUnmannedListenerManager.getVirtualTaskPullTaskInterval() * 1000L, it.siteId) } + // 设置task执行相关状态,切换模式时判断使用 + MogoStatusManager.getInstance().setTaxiUnmanedDriverPerformTask(TAG, false) } override fun onStartAutopilot(postDelayTime: Long) { diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/task/TaxiTaskModel.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/task/TaxiTaskModel.kt index 863d163c87..3b98559aed 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/task/TaxiTaskModel.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/task/TaxiTaskModel.kt @@ -33,7 +33,11 @@ import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.e import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.i import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant -import com.mogo.eagle.core.utilcode.util.* +import com.mogo.eagle.core.utilcode.util.CoordinateUtils +import com.mogo.eagle.core.utilcode.util.DrivingDirectionUtils +import com.mogo.eagle.core.utilcode.util.NetworkUtils +import com.mogo.eagle.core.utilcode.util.ToastUtils +import com.mogo.eagle.core.utilcode.util.UiThreadHandler import com.mogo.och.common.module.biz.common.socketmessage.OCHSocketMessageManager import com.mogo.och.common.module.biz.common.socketmessage.data.OCHOperationalMessage import com.mogo.och.common.module.biz.constant.LoginStatusManager @@ -50,9 +54,22 @@ import com.mogo.och.common.module.manager.distancemamager.TrajectoryAndDistanceM import com.mogo.och.common.module.map.AmapNaviToDestinationModel import com.mogo.och.common.module.utils.CoordinateCalculateRouteUtil.coordinateConverterWgsToGcjLocations import com.mogo.och.common.module.voice.VoiceNotice -import com.mogo.och.taxi.bean.* -import com.mogo.och.taxi.callback.* -import com.mogo.och.taxi.constant.* +import com.mogo.och.taxi.bean.PrepareTaskRespBean +import com.mogo.och.taxi.bean.QueryCarOrderByNoRespBean +import com.mogo.och.taxi.bean.QueryCurrentTaskRespBean +import com.mogo.och.taxi.bean.StartServiceRespBean +import com.mogo.och.taxi.bean.TrajectoryListRespBean +import com.mogo.och.taxi.callback.IOCHTaxiAutopilotPlanningCallback +import com.mogo.och.taxi.callback.ITaxiADASStatusCallback +import com.mogo.och.taxi.callback.ITaxiCarServiceCallback +import com.mogo.och.taxi.callback.ITaxiControllerStatusCallback +import com.mogo.och.taxi.callback.ITaxiOrderStatusCallback +import com.mogo.och.taxi.callback.ITaxiTaskWithOrderCallback +import com.mogo.och.taxi.constant.TaskStatusEnum +import com.mogo.och.taxi.constant.TaskTypeEnum +import com.mogo.och.taxi.constant.TaxiCarServingStatusManager +import com.mogo.och.taxi.constant.TaxiOrderStatusEnum +import com.mogo.och.taxi.constant.TaxiUnmannedConst import com.mogo.och.taxi.constant.TaxiUnmannedConst.Companion.BUSINESSTYPE import com.mogo.och.taxi.network.TaxiTaskWithOrderServiceManager import com.mogo.och.taxi.ui.debug.DebugView @@ -1424,6 +1441,10 @@ object TaxiTaskModel { mCurrentTaskWithOrder = null mDriveToNearestStationTask = null DebugView.printInfoMsg("[登出] 退出登陆") + MogoStatusManager.getInstance().setTaxiUnmanedDriverPerformTask(TAG, false) + MogoStatusManager.getInstance().setTaxiUnmanedDriverTakingOrders(TAG, false) + MogoStatusManager.getInstance().setTaxiUnmanedDriverLineRoutingPerformTask(TAG, false) + MogoStatusManager.getInstance().setTaxiUnmanedDriverLineRoutingVerifyMode(TAG, false) } //导航去订单终点目的地 diff --git a/OCH/taxi/unmanned-driver/src/main/res/color/taxi_autopilot_text_color_selector.xml b/OCH/taxi/unmanned-driver/src/main/res/color/taxi_autopilot_text_color_selector.xml index 16cef94271..a5d1f74aec 100644 --- a/OCH/taxi/unmanned-driver/src/main/res/color/taxi_autopilot_text_color_selector.xml +++ b/OCH/taxi/unmanned-driver/src/main/res/color/taxi_autopilot_text_color_selector.xml @@ -1,4 +1,5 @@ - + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_btn_left_default.png b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_btn_left_default.png new file mode 100755 index 0000000000..bef6342f64 Binary files /dev/null and b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_btn_left_default.png differ diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_btn_left_pressed.png b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_btn_left_pressed.png new file mode 100755 index 0000000000..76efae02cf Binary files /dev/null and b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_btn_left_pressed.png differ diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_btn_right_default.png b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_btn_right_default.png new file mode 100755 index 0000000000..45af8b7997 Binary files /dev/null and b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_btn_right_default.png differ diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_btn_right_pressed.png b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_btn_right_pressed.png new file mode 100755 index 0000000000..f5bd232a66 Binary files /dev/null and b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_btn_right_pressed.png differ diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_line_task_arrow.png b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_line_task_arrow.png new file mode 100644 index 0000000000..b32f0693a6 Binary files /dev/null and b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_line_task_arrow.png differ diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_loading_nor.png b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_loading_nor.png new file mode 100644 index 0000000000..0ff5309fab Binary files /dev/null and b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/routing_loading_nor.png differ diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/taxi_out_btn_disable.png b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/taxi_out_btn_disable.png new file mode 100644 index 0000000000..779e39d482 Binary files /dev/null and b/OCH/taxi/unmanned-driver/src/main/res/drawable-xhdpi/taxi_out_btn_disable.png differ diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/bg_shape_dialog_no_title.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/bg_shape_dialog_no_title.xml new file mode 100644 index 0000000000..e6970921d5 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/bg_shape_dialog_no_title.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/bg_shape_left_bottom_round.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/bg_shape_left_bottom_round.xml new file mode 100644 index 0000000000..1188daedb2 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/bg_shape_left_bottom_round.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/bg_shape_left_right_bottom_round.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/bg_shape_left_right_bottom_round.xml new file mode 100644 index 0000000000..bd0ab9d1e1 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/bg_shape_left_right_bottom_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/bg_shape_right_bottom_round.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/bg_shape_right_bottom_round.xml new file mode 100644 index 0000000000..49c4e8d8f7 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/bg_shape_right_bottom_round.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_btn_bg_finish_task.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_btn_bg_finish_task.xml new file mode 100644 index 0000000000..485f92597d --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_btn_bg_finish_task.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_btn_bg_submit_issue.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_btn_bg_submit_issue.xml new file mode 100644 index 0000000000..c56f217b14 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_btn_bg_submit_issue.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_btn_submit_bg.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_btn_submit_bg.xml new file mode 100644 index 0000000000..0950aa4fb0 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_btn_submit_bg.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_btn_submit_bg_default.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_btn_submit_bg_default.xml new file mode 100644 index 0000000000..e94992d507 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_btn_submit_bg_default.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_btn_submit_bg_pressed.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_btn_submit_bg_pressed.xml new file mode 100644 index 0000000000..975ed9780c --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_btn_submit_bg_pressed.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_close.png b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_close.png new file mode 100644 index 0000000000..370b61de38 Binary files /dev/null and b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_close.png differ diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_shape_select_line_item_bg_normal.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_shape_select_line_item_bg_normal.xml new file mode 100644 index 0000000000..272e718cce --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_shape_select_line_item_bg_normal.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_shape_select_line_item_bg_selected.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_shape_select_line_item_bg_selected.xml new file mode 100644 index 0000000000..e5faafb27b --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_choose_line_shape_select_line_item_bg_selected.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_click_btn_bg.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_click_btn_bg.xml new file mode 100644 index 0000000000..ff04ae2b6d --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_click_btn_bg.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_click_btn_bg_default.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_click_btn_bg_default.xml new file mode 100644 index 0000000000..6c763666ea --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_click_btn_bg_default.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_click_btn_bg_pressed.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_click_btn_bg_pressed.xml new file mode 100644 index 0000000000..3abd919e23 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/routing_click_btn_bg_pressed.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/shape_size_operation_out_disable.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/shape_size_operation_out_disable.xml new file mode 100644 index 0000000000..13ce8bb87d --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/shape_size_operation_out_disable.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/taxi_operation_status_bg_disabled.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/taxi_operation_status_bg_disabled.xml new file mode 100644 index 0000000000..25386e2c3c --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/taxi_operation_status_bg_disabled.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/taxi_operation_status_bg_selector_new.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/taxi_operation_status_bg_selector_new.xml new file mode 100755 index 0000000000..8c100f97eb --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/taxi_operation_status_bg_selector_new.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/drawable/taxi_routing_bg.xml b/OCH/taxi/unmanned-driver/src/main/res/drawable/taxi_routing_bg.xml new file mode 100644 index 0000000000..f5efecaa11 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/drawable/taxi_routing_bg.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/layout/dialog_routing_feedback_result.xml b/OCH/taxi/unmanned-driver/src/main/res/layout/dialog_routing_feedback_result.xml new file mode 100644 index 0000000000..2acf507da3 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/layout/dialog_routing_feedback_result.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/layout/dialog_routing_loading.xml b/OCH/taxi/unmanned-driver/src/main/res/layout/dialog_routing_loading.xml new file mode 100644 index 0000000000..f019a97cfb --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/layout/dialog_routing_loading.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/layout/routing_choose_line_list_item.xml b/OCH/taxi/unmanned-driver/src/main/res/layout/routing_choose_line_list_item.xml new file mode 100644 index 0000000000..d7b1c6849a --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/layout/routing_choose_line_list_item.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/layout/routing_choose_task_activity.xml b/OCH/taxi/unmanned-driver/src/main/res/layout/routing_choose_task_activity.xml new file mode 100644 index 0000000000..95aa167e16 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/layout/routing_choose_task_activity.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/layout/routing_fragment.xml b/OCH/taxi/unmanned-driver/src/main/res/layout/routing_fragment.xml new file mode 100644 index 0000000000..fb9ef5ed94 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/layout/routing_fragment.xml @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OCH/taxi/unmanned-driver/src/main/res/layout/routing_no_data_common_view.xml b/OCH/taxi/unmanned-driver/src/main/res/layout/routing_no_data_common_view.xml new file mode 100644 index 0000000000..434d9ad890 --- /dev/null +++ b/OCH/taxi/unmanned-driver/src/main/res/layout/routing_no_data_common_view.xml @@ -0,0 +1,33 @@ + + + + + + + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/layout/taxi_base_fragment.xml b/OCH/taxi/unmanned-driver/src/main/res/layout/taxi_base_fragment.xml index d990f1b3fe..92d39f3331 100644 --- a/OCH/taxi/unmanned-driver/src/main/res/layout/taxi_base_fragment.xml +++ b/OCH/taxi/unmanned-driver/src/main/res/layout/taxi_base_fragment.xml @@ -232,7 +232,7 @@ android:layout_height="102dp" android:layout_marginLeft="48dp" android:layout_marginBottom="@dimen/module_mogo_och_margin_bottom" - android:background="@drawable/taxi_operation_status_bg" + android:background="@drawable/taxi_operation_status_bg_selector_new" android:drawableLeft="@drawable/shape_size_operation_out" android:drawablePadding="10dp" android:elevation="@dimen/dp_10" diff --git a/OCH/taxi/unmanned-driver/src/main/res/layout/taxi_debug_order.xml b/OCH/taxi/unmanned-driver/src/main/res/layout/taxi_debug_order.xml index 646b94ab4e..e56f833b6c 100644 --- a/OCH/taxi/unmanned-driver/src/main/res/layout/taxi_debug_order.xml +++ b/OCH/taxi/unmanned-driver/src/main/res/layout/taxi_debug_order.xml @@ -1,13 +1,23 @@ - + android:layout_height="wrap_content" + android:text="当前业务模式:" + android:textColor="@android:color/white" + android:textSize="@dimen/dp_24" /> + + #CAD6FF #00FFF8 #1D5EF3 - + #1D5EF3 + #801D5EF3 + #F7151D41 + #2966EC + #CCB9C3E9 + #4Dffffff \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/values/dimens.xml b/OCH/taxi/unmanned-driver/src/main/res/values/dimens.xml index 22d65210b4..2e8093ba90 100644 --- a/OCH/taxi/unmanned-driver/src/main/res/values/dimens.xml +++ b/OCH/taxi/unmanned-driver/src/main/res/values/dimens.xml @@ -117,6 +117,9 @@ 60dp 34dp - 1000dp + 934dp + 46dp + 50dp + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/values/strings.xml b/OCH/taxi/unmanned-driver/src/main/res/values/strings.xml index ce60468f17..0c01eb4938 100644 --- a/OCH/taxi/unmanned-driver/src/main/res/values/strings.xml +++ b/OCH/taxi/unmanned-driver/src/main/res/values/strings.xml @@ -60,5 +60,19 @@ 查看 + 选择任务 + 开始任务 + 任务列表 + 确认 + 暂无任务 + 选择时间 + 路线: + 起点: + 终点: + 往%1$s方向 + 线路可用 + 线路不可用 + 路线验证结束啦!点击下方按钮反馈验证结果吧 + \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/res/values/styles.xml b/OCH/taxi/unmanned-driver/src/main/res/values/styles.xml index 4dc523b396..f9764de193 100644 --- a/OCH/taxi/unmanned-driver/src/main/res/values/styles.xml +++ b/OCH/taxi/unmanned-driver/src/main/res/values/styles.xml @@ -23,4 +23,25 @@ + + \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/MoGoHmiProvider.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/MoGoHmiProvider.kt index acd2b757ae..754956167e 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/MoGoHmiProvider.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/MoGoHmiProvider.kt @@ -2,30 +2,32 @@ package com.mogo.eagle.core.function.hmi.ui import android.content.Context import android.text.TextUtils -import android.view.* +import android.view.Gravity +import android.view.ViewGroup import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.lifecycleScope import com.alibaba.android.arouter.facade.annotation.Route +import com.mogo.commons.module.status.MogoStatusManager import com.mogo.commons.voice.AIAssist -import com.mogo.eagle.core.data.deva.bindingcar.IPCUpgradeStateInfo +import com.mogo.eagle.core.data.biz.dispatch.DispatchAdasAutoPilotLocReceiverBean +import com.mogo.eagle.core.data.biz.notice.NoticeNormalData +import com.mogo.eagle.core.data.biz.notice.NoticeTrafficStylePushData import com.mogo.eagle.core.data.config.FunctionBuildConfig +import com.mogo.eagle.core.data.config.HmiBuildConfig import com.mogo.eagle.core.data.constants.MogoServicePaths.PATH_FRAGMENT_HMI +import com.mogo.eagle.core.data.deva.bindingcar.IPCUpgradeStateInfo import com.mogo.eagle.core.data.deva.bizconfig.FuncBizConfig.Companion.BIZ_RTS import com.mogo.eagle.core.data.deva.bizconfig.FuncBizConfig.Companion.V2I -import com.mogo.eagle.core.data.biz.dispatch.DispatchAdasAutoPilotLocReceiverBean import com.mogo.eagle.core.data.enums.EventTypeEnumNew import com.mogo.eagle.core.data.enums.WarningDirectionEnum import com.mogo.eagle.core.data.map.Infrastructure -import com.mogo.eagle.core.data.biz.notice.NoticeNormalData -import com.mogo.eagle.core.data.biz.notice.NoticeTrafficStylePushData -import com.mogo.eagle.core.data.config.HmiBuildConfig import com.mogo.eagle.core.function.api.hmi.warning.IMoGoHmiProvider import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWarningStatusListener -import com.mogo.eagle.core.function.call.hmi.* +import com.mogo.eagle.core.function.call.hmi.CallerHmiViewControlListenerManager import com.mogo.eagle.core.function.call.v2x.CallerTrafficLightListenerManager import com.mogo.eagle.core.function.call.v2x.CallerTurnLightListenerManager import com.mogo.eagle.core.function.hmi.ui.camera.RoadVideoDialog -import com.mogo.eagle.core.function.hmi.ui.lookaround.* +import com.mogo.eagle.core.function.hmi.ui.lookaround.M1LookAroundView import com.mogo.eagle.core.function.hmi.ui.notice.DispatchDialogManager import com.mogo.eagle.core.function.hmi.ui.notice.NoticeCheckDialog import com.mogo.eagle.core.function.hmi.ui.notice.traffic.NoticeTrafficDialog @@ -38,15 +40,18 @@ import com.mogo.eagle.core.function.hmi.ui.tools.ToBindingCarDialog import com.mogo.eagle.core.function.hmi.ui.tools.UpgradeAppDialog import com.mogo.eagle.core.function.hmi.ui.utils.HmiActionLog import com.mogo.eagle.core.function.hmi.ui.widget.StatusBarView -import com.mogo.eagle.core.utilcode.floating.* +import com.mogo.eagle.core.utilcode.floating.MoGoPopWindow import com.mogo.eagle.core.utilcode.kotlin.safeCancel import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_HMI -import com.mogo.eagle.core.utilcode.util.* +import com.mogo.eagle.core.utilcode.util.AppStateManager +import com.mogo.eagle.core.utilcode.util.ThreadUtils import com.mogo.tts.base.IMogoTTSCallback import com.zhjt.service_biz.BizConfig -import kotlinx.coroutines.* +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicReference @@ -352,4 +357,24 @@ class MoGoHmiProvider : IMoGoHmiProvider { CallerTurnLightListenerManager.invokeHideTurnLightView() } + override fun isTaxiUnmanedDriverPerformTask(): Boolean { + return MogoStatusManager.getInstance().isTaxiUnmanedDriverPerformTask + } + + override fun isTaxiUnmanedDriverTakingOrders(): Boolean { + return MogoStatusManager.getInstance().isTaxiUnmanedDriverTakingOrders + } + + override fun isTaxiUnmanedDriverLineRoutingPerformTask(): Boolean { + return MogoStatusManager.getInstance().isTaxiUnmanedDriverLineRoutingPerformTask + } + + override fun isTaxiUnmanedDriverLineRoutingVerifyMode(): Boolean { + return MogoStatusManager.getInstance().isTaxiUnmanedDriverLineRoutingVerifyMode + } + + override fun setTaxiUnmanedDriverLineRoutingVerifyMode(isMode: Boolean) { + MogoStatusManager.getInstance().setTaxiUnmanedDriverLineRoutingVerifyMode(TAG, isMode) + } + } \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/SOPSettingView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/SOPSettingView.kt index 2b78b8bcd7..b5931b6ad8 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/SOPSettingView.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/SOPSettingView.kt @@ -553,6 +553,41 @@ internal class SOPSettingView @JvmOverloads constructor( } } + // Taxi无人化司机端,自主算路验证模式 + scLineRoutingVerify?.also { + if (AppIdentityModeUtils.isTaxiDriver(FunctionBuildConfig.appIdentityMode)) { + it.isEnabled = true + it.visibility = View.VISIBLE + it.setOnCheckedChangeListener { buttonView, isChecked -> + if(!buttonView.isPressed) return@setOnCheckedChangeListener + if (isChecked) { + if (CallerHmiManager.isTaxiUnmanedDriverPerformTask()) { + ToastUtils.showLong("请先结束当前任务") + buttonView.isChecked = !isChecked + return@setOnCheckedChangeListener + } + if (CallerHmiManager.isTaxiUnmanedDriverTakingOrders()) { + ToastUtils.showLong("请先结束接单状态") + buttonView.isChecked = !isChecked + return@setOnCheckedChangeListener + } + CallerHmiManager.setTaxiUnmanedDriverLineRoutingVerifyMode(true) + } else { + if (CallerHmiManager.isTaxiUnmanedDriverLineRoutingPerformTask()) { + ToastUtils.showLong("请先结束当前任务") + buttonView.isChecked = !isChecked + return@setOnCheckedChangeListener + } + CallerHmiManager.setTaxiUnmanedDriverLineRoutingVerifyMode(false) + } + } + it.isChecked = CallerHmiManager.isTaxiUnmanedDriverLineRoutingVerifyMode() + } else { + it.isEnabled = false + it.visibility = View.GONE + } + } + //是否展示被动触发的录包弹窗(自动驾驶下出现问题触发的录包) scShowBagRecordWindow.isChecked = FunctionBuildConfig.isShowBagRecordWindow scShowBagRecordWindow.setOnCheckedChangeListener { _, isChecked -> diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_sop_setting.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_sop_setting.xml index 875a80344d..acca2f5390 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_sop_setting.xml +++ b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_sop_setting.xml @@ -548,6 +548,19 @@ app:layout_constraintRight_toRightOf="@id/otherGuideLine" app:layout_constraintTop_toBottomOf="@id/scIPCReport" /> + + + + app:layout_constraintTop_toBottomOf="@id/scLineRoutingVerify" />