diff --git a/OCH/mogo-och-common-module/src/main/java/com/mogo/och/common/module/biz/provider/LoginServiceImpl.kt b/OCH/mogo-och-common-module/src/main/java/com/mogo/och/common/module/biz/provider/LoginServiceImpl.kt
index f34d388d46..370bc3932b 100644
--- a/OCH/mogo-och-common-module/src/main/java/com/mogo/och/common/module/biz/provider/LoginServiceImpl.kt
+++ b/OCH/mogo-och-common-module/src/main/java/com/mogo/och/common/module/biz/provider/LoginServiceImpl.kt
@@ -60,6 +60,7 @@ class LoginServiceImpl : LoginService,ILoginViewCallback {
if(uiModel) {
fragment?.let {
CallerHmiManager.hideToolsView()
+ CallerHmiManager.hideSOPSettingView()
val parentFragmentManager = it.childFragmentManager
val fragmentByTag: Fragment? = parentFragmentManager.findFragmentByTag(TAG)
if (fragmentByTag is DialogFragment) {
diff --git a/OCH/mogo-och-common-module/src/main/java/com/mogo/och/common/module/map/AmapNaviToDestinationModel.java b/OCH/mogo-och-common-module/src/main/java/com/mogo/och/common/module/map/AmapNaviToDestinationModel.java
index d49a3f7a34..a5bea903ec 100644
--- a/OCH/mogo-och-common-module/src/main/java/com/mogo/och/common/module/map/AmapNaviToDestinationModel.java
+++ b/OCH/mogo-och-common-module/src/main/java/com/mogo/och/common/module/map/AmapNaviToDestinationModel.java
@@ -78,7 +78,7 @@ public class AmapNaviToDestinationModel implements AMapNaviListener {
public void setVoiceIsMute(boolean isPlay) {
ThreadUtils.getSinglePool().execute(() -> {
if (mAMapNavi == null) return;
- CallerLogger.i(TAG, "setVoiceIsMute()--"+isPlay);
+ CallerLogger.i(TAG, "setVoiceIsMute()--" + isPlay);
this.isPlay = isPlay;
if (isPlay) {
mAMapNavi.startSpeak();
@@ -108,6 +108,7 @@ public class AmapNaviToDestinationModel implements AMapNaviListener {
}
public void setTaxiNaviChangedCallback(ICommonNaviChangedCallback callback) {
+ CallerLogger.i(TAG, "setTaxiNaviChangedCallback()");
this.mNaviChangedCallback = callback;
}
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/TaxiDriverTaskWithOrderBean.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/bean/TaxiDriverTaskWithOrderBean.kt
index 019653c8b1..cb3277ee99 100644
--- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/bean/TaxiDriverTaskWithOrderBean.kt
+++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/bean/TaxiDriverTaskWithOrderBean.kt
@@ -100,6 +100,7 @@ data class QueryCurrentTaskRespBean(var data: Result?) : BaseData() {
if (startSite != other.startSite) return false
if (endSite != other.endSite) return false
if (order != other.order) return false
+ if (writeVersion != other.writeVersion) return false
return true
}
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..22fcb34e93
--- /dev/null
+++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/callback/ITaxiRoutingCallback.kt
@@ -0,0 +1,17 @@
+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)
+ fun onAutoPilotArriveAtEndStation(grayId: Long?)
+ fun onGDMapArriveAtEndStation(grayId: Long?)
+}
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/constant/TaxiUnmannedConst.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/constant/TaxiUnmannedConst.kt
index e759aef583..0e84fffa52 100644
--- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/constant/TaxiUnmannedConst.kt
+++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/constant/TaxiUnmannedConst.kt
@@ -42,6 +42,12 @@ class TaxiUnmannedConst {
//终点UUID
const val TAXI_END_MAP_MAKER = "taxi_end_map_maker"
+ //算路起点UUID
+ const val TAXI_ROUTING_VERIFY_START_SITE = "taxi_routing_verify_start_site"
+
+ //算路终点UUID
+ const val TAXI_ROUTING_VERIFY_END_SITE = "taxi_routing_verify_end_site"
+
//演示:V 测试:内测
const val DEMO_USER = "V"
const val TEST_USER = "内测"
@@ -78,6 +84,8 @@ class TaxiUnmannedConst {
*/
const val TYPE_MARKER_TAXI_ORDER = "TYPE_MARKER_TAXI_ORDER"
+ const val TYPE_MARKER_ROUTING_VERIFY = "TYPE_MARKER_TAXI_ROUTING_VERIFY"
+
const val TIMER_START_AUTOPILOT_INTERVAL = 20 * 1000L
const val TIMER_PREPARE_VIRTUAL_TASK_INTERVAL = 45 * 1000L //45s再次获取任务
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..4855ec3b86 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.isChecked = !isRoutingVerifyMode
+ val isBtnEnable = module_mogo_och_operation_status.isChecked
+ 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..25556b87a0 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.VISIBLE else View.INVISIBLE
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