diff --git a/OCH/bus/driver/src/main/java/com/mogo/och/bus/bean/WriteOffPassenger.java b/OCH/bus/driver/src/main/java/com/mogo/och/bus/bean/WriteOffPassenger.java index 11ac15e305..74f0d90ed0 100644 --- a/OCH/bus/driver/src/main/java/com/mogo/och/bus/bean/WriteOffPassenger.java +++ b/OCH/bus/driver/src/main/java/com/mogo/och/bus/bean/WriteOffPassenger.java @@ -11,4 +11,14 @@ public class WriteOffPassenger implements Serializable { public String orderNo; public int passengerSize; public long writeOffTime; + + @Override + public String toString() { + return "WriteOffPassenger{" + + "phone='" + phone + '\'' + + ", orderNo='" + orderNo + '\'' + + ", passengerSize=" + passengerSize + + ", writeOffTime=" + writeOffTime + + '}'; + } } diff --git a/OCH/bus/driver/src/main/java/com/mogo/och/bus/model/OrderModel.java b/OCH/bus/driver/src/main/java/com/mogo/och/bus/model/OrderModel.java index 0c1e4f6e40..dc18c66228 100644 --- a/OCH/bus/driver/src/main/java/com/mogo/och/bus/model/OrderModel.java +++ b/OCH/bus/driver/src/main/java/com/mogo/och/bus/model/OrderModel.java @@ -47,6 +47,7 @@ import com.mogo.och.bus.util.BusTrajectoryManager; import com.mogo.och.bus.util.BusVoiceManager; import com.mogo.och.common.module.manager.autopilot.autopilot.OchAutoPilotManager; import com.mogo.och.common.module.manager.autopilot.line.LineManager; +import com.mogo.och.common.module.manager.socket.cloud.IOchOnMessageListener; import com.mogo.och.common.module.manager.socket.lan.ILanMessageListener; import com.mogo.och.common.module.manager.socket.lan.LanSocketManager; import com.mogo.och.common.module.manager.socket.lan.bean.AppConnectMsg; @@ -278,8 +279,8 @@ public class OrderModel { GsonUtils.toJson(data)); } - private final IMogoOnMessageListener mMogoOnMessageListener = - new IMogoOnMessageListener() { + private final IOchOnMessageListener mMogoOnMessageListener = + new IOchOnMessageListener() { @Override public Class target() { return OCHOperationalMessage.class; @@ -297,8 +298,8 @@ public class OrderModel { } }; - private final IMogoOnMessageListener mWriteOffPassengerOnMessageListener = - new IMogoOnMessageListener() { + private final IOchOnMessageListener mWriteOffPassengerOnMessageListener = + new IOchOnMessageListener() { @Override public Class target() { return WriteOffPassenger.class; diff --git a/OCH/charter/driver/src/main/java/com/magic/mogo/och/charter/model/DriverM1Model.kt b/OCH/charter/driver/src/main/java/com/magic/mogo/och/charter/model/DriverM1Model.kt index 0323fc8f35..e457f38d63 100644 --- a/OCH/charter/driver/src/main/java/com/magic/mogo/och/charter/model/DriverM1Model.kt +++ b/OCH/charter/driver/src/main/java/com/magic/mogo/och/charter/model/DriverM1Model.kt @@ -52,6 +52,7 @@ import com.mogo.och.common.module.manager.device.LightAirconditionDoorStatusMana import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager import com.mogo.och.common.module.manager.socket.cloud.AbnormalFactorsLoopManager.startLoopAbnormalFactors import com.mogo.och.common.module.manager.socket.cloud.AbnormalFactorsLoopManager.stopLoopAbnormalFactors +import com.mogo.och.common.module.manager.socket.cloud.IOchOnMessageListener import com.mogo.och.common.module.manager.socket.cloud.OCHSocketMessageManager import com.mogo.och.common.module.manager.socket.cloud.OCHSocketMessageManager.pushAppOperationalMsgBox import com.mogo.och.common.module.manager.socket.cloud.OCHSocketMessageManager.registerSocketMessageListener @@ -251,7 +252,7 @@ class DriverM1Model { } private val mOnSystemMessageListener = - object : IMogoOnMessageListener { + object : IOchOnMessageListener { override fun onMsgReceived(obj: SystemMsg) { d(SceneConstant.M_CHARTER_D + TAG, "onMsgReceived = " + obj.context) @@ -273,7 +274,7 @@ class DriverM1Model { } private val mOnDoorMessageListener = - object : IMogoOnMessageListener { + object : IOchOnMessageListener { override fun onMsgReceived(obj: OperateDoorMsg) { d(SceneConstant.M_CHARTER_D + TAG, "onMsgReceived = " + obj.message) val doorStatus = LightAirconditionDoorStatusManager.doorStatus @@ -290,7 +291,7 @@ class DriverM1Model { } private val mOnOrderClosedMessageListener = - object : IMogoOnMessageListener { + object : IOchOnMessageListener { override fun onMsgReceived(obj: OrderCloseMsg) { //订单结束 pushOperationalToMsgBox(DateTimeUtil.getCurrentTimeStamp(), obj.message @@ -304,8 +305,8 @@ class DriverM1Model { } } - private val mWriteOffPassengerOnMessageListener: IMogoOnMessageListener = - object : IMogoOnMessageListener { + private val mWriteOffPassengerOnMessageListener = + object : IOchOnMessageListener { override fun target(): Class { return WriteOffPassenger::class.java } diff --git a/OCH/common/biz/src/main/java/com/mogo/och/biz/login/model/LoginModel.kt b/OCH/common/biz/src/main/java/com/mogo/och/biz/login/model/LoginModel.kt index f97a8f88c0..3e0df5e4c5 100644 --- a/OCH/common/biz/src/main/java/com/mogo/och/biz/login/model/LoginModel.kt +++ b/OCH/common/biz/src/main/java/com/mogo/och/biz/login/model/LoginModel.kt @@ -8,6 +8,9 @@ import com.mogo.commons.module.intent.IMogoIntentListener import com.mogo.commons.module.intent.IntentManager import com.mogo.commons.storage.SharedPrefsMgr import com.mogo.eagle.core.data.BaseData +import com.mogo.eagle.core.data.config.FunctionBuildConfig +import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager +import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02 import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant @@ -174,15 +177,17 @@ object LoginModel { LoginStatusManager.setBusinessType(data.data.businessType) iTaxiLoginCallback?.searchStatusSuccess() // 后台已登录 - if (valueOf(data.data.driverStatus) == LoginStatusEnum.Login) { - // 业务不支持 去退出登录 - if (!LoginStatusManager.checkBusiness(data.data.businessType)) { - LoginStatusManager.loginOut() - return + if(!FunctionBuildConfig.isOffLine){ + if (valueOf(data.data.driverStatus) == LoginStatusEnum.Login) { + // 业务不支持 去退出登录 + if (!LoginStatusManager.checkBusiness(data.data.businessType)) { + LoginStatusManager.loginOut() + return + } } + LoginStatusManager.setLoginStatus(data.data.driverStatus) } LoginStatusManager.setOpenOrderType(data.data.servingStatus) - LoginStatusManager.setLoginStatus(data.data.driverStatus) LoginStatusManager.setLoginInfo(data.data) d(SceneConstant.M_TAXI + TAG, "登录信息:$data") loginSuccess(data) @@ -218,6 +223,11 @@ object LoginModel { // 登出 fun logout() { val location4Login = TaxiLogoutReqBean.Location4Login() + if (FunctionBuildConfig.isOffLine) { + LoginStatusManager.setLoginStatus(LoginStatusEnum.Logout) + FunctionBuildConfig.isOffLine = false + return + } OchCommonServiceManager.logout( mContext!!, location4Login, object : OchCommonServiceCallback { @@ -271,4 +281,9 @@ object LoginModel { updateLoginLocalStatus(0) } + fun gotoOfflineMode() { + FunctionBuildConfig.isOffLine = true + LoginStatusManager.setLoginStatus(LoginStatusEnum.Login) + } + } \ No newline at end of file diff --git a/OCH/common/biz/src/main/java/com/mogo/och/biz/login/presenter/LoginPresenter.kt b/OCH/common/biz/src/main/java/com/mogo/och/biz/login/presenter/LoginPresenter.kt index 903224173b..8bc8461591 100644 --- a/OCH/common/biz/src/main/java/com/mogo/och/biz/login/presenter/LoginPresenter.kt +++ b/OCH/common/biz/src/main/java/com/mogo/och/biz/login/presenter/LoginPresenter.kt @@ -127,4 +127,8 @@ class LoginPresenter(view: LoginFragment?) : Presenter(view), IT this.code = null } + fun gotoOfflineMode() { + LoginModel.gotoOfflineMode() + } + } \ No newline at end of file diff --git a/OCH/common/biz/src/main/java/com/mogo/och/biz/login/ui/LoginFragment.kt b/OCH/common/biz/src/main/java/com/mogo/och/biz/login/ui/LoginFragment.kt index 1e576c5cf1..d42689f0eb 100644 --- a/OCH/common/biz/src/main/java/com/mogo/och/biz/login/ui/LoginFragment.kt +++ b/OCH/common/biz/src/main/java/com/mogo/och/biz/login/ui/LoginFragment.kt @@ -35,6 +35,7 @@ import kotlinx.android.synthetic.main.biz_login_view.biz_actv_welcome_login_titl import kotlinx.android.synthetic.main.biz_login_view.biz_cl_driver_main import kotlinx.android.synthetic.main.biz_login_view.bv_switch_business import kotlinx.android.synthetic.main.biz_login_view.eiv_Info +import kotlinx.android.synthetic.main.biz_login_view.iv_login_offline /** @@ -109,6 +110,9 @@ class LoginFragment : MvpFragment(), ILoginView biz_actv_login_get_code.onClick { mPresenter?.getPhoneCode(biz_ace_login_phone_value.text.toString()) } + iv_login_offline.setOnClickListener { + mPresenter?.gotoOfflineMode() + } biz_ace_login_phone_value.addTextChangedListener { it?.let { itEditable -> diff --git a/OCH/common/biz/src/main/res/drawable/baseline_link_off_24.xml b/OCH/common/biz/src/main/res/drawable/baseline_link_off_24.xml new file mode 100644 index 0000000000..2fbc2cfbfc --- /dev/null +++ b/OCH/common/biz/src/main/res/drawable/baseline_link_off_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/OCH/common/biz/src/main/res/layout/biz_login_view.xml b/OCH/common/biz/src/main/res/layout/biz_login_view.xml index 2822e391fe..c5dada8359 100644 --- a/OCH/common/biz/src/main/res/layout/biz_login_view.xml +++ b/OCH/common/biz/src/main/res/layout/biz_login_view.xml @@ -159,5 +159,16 @@ android:layout_width="wrap_content" android:layout_height="wrap_content"/> + + \ No newline at end of file diff --git a/OCH/common/common/src/main/java/com/mogo/och/common/module/biz/lansocket/LoginLanDriverSocket.kt b/OCH/common/common/src/main/java/com/mogo/och/common/module/biz/lansocket/LoginLanDriverSocket.kt index 05cbd27f3f..1875a03865 100644 --- a/OCH/common/common/src/main/java/com/mogo/och/common/module/biz/lansocket/LoginLanDriverSocket.kt +++ b/OCH/common/common/src/main/java/com/mogo/och/common/module/biz/lansocket/LoginLanDriverSocket.kt @@ -1,5 +1,6 @@ package com.mogo.och.common.module.biz.lansocket +import com.mogo.eagle.core.data.config.FunctionBuildConfig import com.mogo.och.common.module.BuildConfig import com.mogo.och.common.module.biz.login.ILoginCallback import com.mogo.och.common.module.biz.login.LoginStatusEnum diff --git a/OCH/common/common/src/main/java/com/mogo/och/common/module/biz/login/LoginStatusManager.kt b/OCH/common/common/src/main/java/com/mogo/och/common/module/biz/login/LoginStatusManager.kt index 8a6efe6128..de093bc8ee 100644 --- a/OCH/common/common/src/main/java/com/mogo/och/common/module/biz/login/LoginStatusManager.kt +++ b/OCH/common/common/src/main/java/com/mogo/och/common/module/biz/login/LoginStatusManager.kt @@ -3,6 +3,7 @@ package com.mogo.och.common.module.biz.login import androidx.fragment.app.Fragment import com.alibaba.android.arouter.launcher.ARouter +import com.mogo.eagle.core.data.config.FunctionBuildConfig import com.mogo.och.common.module.constant.OchCommonConst import com.mogo.och.common.module.manager.loop.BizLoopManager import com.mogo.och.common.module.manager.loop.LoopInfo @@ -119,10 +120,12 @@ object LoginStatusManager : CallerBase() { } fun invokeLoginStatusChange(currentStatus: LoginStatusEnum) { - if(currentStatus==LoginStatusEnum.Login){ - BizLoopManager.setLoopFunction(TAGLoopStatus, LoopInfo(60*2, ::queryLoginStatusByNet,immediately = true, scheduler = Schedulers.io())) - }else{ - BizLoopManager.removeLoopFunction(TAGLoopStatus) + if(!FunctionBuildConfig.isOffLine){ + if(currentStatus==LoginStatusEnum.Login){ + BizLoopManager.setLoopFunction(TAGLoopStatus, LoopInfo(60*2, ::queryLoginStatusByNet,immediately = true, scheduler = Schedulers.io())) + }else{ + BizLoopManager.removeLoopFunction(TAGLoopStatus) + } } M_LISTENERS.forEach { val listener = it.value diff --git a/OCH/common/common/src/main/java/com/mogo/och/common/module/constant/OchCommonConst.kt b/OCH/common/common/src/main/java/com/mogo/och/common/module/constant/OchCommonConst.kt index cae81e1970..fb092bcf23 100644 --- a/OCH/common/common/src/main/java/com/mogo/och/common/module/constant/OchCommonConst.kt +++ b/OCH/common/common/src/main/java/com/mogo/och/common/module/constant/OchCommonConst.kt @@ -47,6 +47,10 @@ class OchCommonConst { const val TAXI_UNMANNED_DRIVER = "/taxiunman/taxiunmandriver" const val TAXI_UNMANNED_PASSENGER = "/taxiunman/taxiunmanpassenger" + const val OFFLINE_DRIVER = "/offline/offlinedriver" + const val OFFLINE_PASSENGER = "/offline/offlinepassenger" + + const val BUSINESS_STRING = 100 // 自动驾驶自动规划的最大距离 diff --git a/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/logchainanalytic/OchChainLogManager.kt b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/logchainanalytic/OchChainLogManager.kt index b6456d7d02..c07b21a18e 100644 --- a/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/logchainanalytic/OchChainLogManager.kt +++ b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/logchainanalytic/OchChainLogManager.kt @@ -23,6 +23,8 @@ object OchChainLogManager { // 音乐播放日志 const val EVENT_KEY_INFE_WITH_MUSIC = "event_key_och_music_info" + const val EVENT_KEY_INFE_WITH_BUS = "event_key_och_bus_info" + // 需要举行观察的 const val EVENT_KEY_INFE_ERROR = "event_key_och_error" diff --git a/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/socket/cloud/IOchOnMessageListener.java b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/socket/cloud/IOchOnMessageListener.java new file mode 100644 index 0000000000..9182ccd564 --- /dev/null +++ b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/socket/cloud/IOchOnMessageListener.java @@ -0,0 +1,14 @@ +package com.mogo.och.common.module.manager.socket.cloud; + +/** + * @author congtaowang + * @since 2019-12-31 + *

+ * 消息回调 + */ +public interface IOchOnMessageListener< T > { + + Class< T > target(); + + void onMsgReceived( T obj ); +} diff --git a/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/socket/cloud/OCHSocketMessageManager.kt b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/socket/cloud/OCHSocketMessageManager.kt index 6b92440565..deed51c9a3 100644 --- a/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/socket/cloud/OCHSocketMessageManager.kt +++ b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/socket/cloud/OCHSocketMessageManager.kt @@ -7,6 +7,7 @@ import com.mogo.eagle.core.data.msgbox.MsgBoxBean import com.mogo.eagle.core.data.msgbox.MsgBoxType import com.mogo.eagle.core.data.msgbox.OperationMsg import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager +import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager /** * 统一管理业务长链消息推送 @@ -22,9 +23,18 @@ object OCHSocketMessageManager { const val OPERATION_ROAD_SIDE_TYPE: Int = 1 //靠边停车通知 fun registerSocketMessageListener(msgType:Int, - mogoOnMessageListener :IMogoOnMessageListener){ + mogoOnMessageListener :IOchOnMessageListener){ MogoAiCloudSocketManager.getInstance(AbsMogoApplication.getApp().applicationContext) - .registerOnMessageListener(msgType,mogoOnMessageListener) + .registerOnMessageListener(msgType,object :IMogoOnMessageListener{ + override fun target(): Class { + return mogoOnMessageListener.target() + } + + override fun onMsgReceived(obj: T) { + OchChainLogManager.writeChainLogLanSocket("收到服务端数据","obj:${obj}}","receive"); + mogoOnMessageListener.onMsgReceived(obj) + } + }) } fun releaseSocketMessageListener(msgType:Int){ diff --git a/OCH/common/common/src/main/java/com/mogo/och/common/module/network/interceptor/FRetryWithTime.kt b/OCH/common/common/src/main/java/com/mogo/och/common/module/network/interceptor/FRetryWithTime.kt index 9323b8cb1a..4c8aa34024 100644 --- a/OCH/common/common/src/main/java/com/mogo/och/common/module/network/interceptor/FRetryWithTime.kt +++ b/OCH/common/common/src/main/java/com/mogo/och/common/module/network/interceptor/FRetryWithTime.kt @@ -18,8 +18,10 @@ class FRetryWithTime : Function> { MoGoAiCloudClient.getInstance().refreshToken() return Observable.error(OchCommonRetryException()) }else if(it.code == 1003){ - if (AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)) { - LoginStatusManager.setLoginStatus(LoginStatusEnum.Logout) + if(!FunctionBuildConfig.isOffLine){ + if (AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)) { + LoginStatusManager.setLoginStatus(LoginStatusEnum.Logout) + } } } } diff --git a/OCH/common/data/src/main/java/com/mogo/och/data/bean/BusRoutesResult.java b/OCH/common/data/src/main/java/com/mogo/och/data/bean/BusRoutesResult.java index 3e9a4cffc5..e27df79500 100644 --- a/OCH/common/data/src/main/java/com/mogo/och/data/bean/BusRoutesResult.java +++ b/OCH/common/data/src/main/java/com/mogo/och/data/bean/BusRoutesResult.java @@ -44,6 +44,10 @@ public class BusRoutesResult { return lineId; } + public void setLineId(int lineId) { + this.lineId = lineId; + } + public int getTaskId() { return taskId; } @@ -52,6 +56,10 @@ public class BusRoutesResult { return name; } + public void setName(String name) { + this.name = name; + } + public List getSites() { return sites; } diff --git a/OCH/facade/script/och.gradle b/OCH/facade/script/och.gradle index f992990782..e8b94fefd1 100644 --- a/OCH/facade/script/och.gradle +++ b/OCH/facade/script/och.gradle @@ -4,6 +4,13 @@ project.dependencies { if (Boolean.valueOf(USE_MAVEN_PACKAGE)) { } else { + + if (isDriver()) { + implementation project.project(':OCH:offline:driver') + }else if(isPassenger){ + implementation project.project(':OCH:offline:passenger') + } + if (isCurrentDriver("C1")) { implementation project.project(':OCH:sweeper:driver') } else if (isCurrentDriver("B1")) { diff --git a/OCH/facade/src/main/java/com/mogo/och/facade/route/FacadeProvider.kt b/OCH/facade/src/main/java/com/mogo/och/facade/route/FacadeProvider.kt index 49a6ed1442..1bf12952a3 100644 --- a/OCH/facade/src/main/java/com/mogo/och/facade/route/FacadeProvider.kt +++ b/OCH/facade/src/main/java/com/mogo/och/facade/route/FacadeProvider.kt @@ -79,6 +79,13 @@ abstract class FacadeProvider : IMoGoFunctionProvider, ILoginCallback { } private fun getFragment(): Fragment { + if(FunctionBuildConfig.isOffLine){ + if(AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)){ + return getFragmentByServeName(OchCommonConst.OFFLINE_DRIVER) + }else if(AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)){ + return getFragmentByServeName(OchCommonConst.OFFLINE_PASSENGER) + } + } if(DeviceUtils.isEB5Model()&&AppIdentityModeUtils.isCharterPassenger(FunctionBuildConfig.appIdentityMode)){ val maxVolume = VolumeUtils.getMaxVolume(AudioManager.STREAM_MUSIC) val volume = VolumeUtils.getVolume(AudioManager.STREAM_MUSIC) diff --git a/OCH/offline/driver/.gitignore b/OCH/offline/driver/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/OCH/offline/driver/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/OCH/offline/driver/build.gradle b/OCH/offline/driver/build.gradle new file mode 100644 index 0000000000..72d90e458e --- /dev/null +++ b/OCH/offline/driver/build.gradle @@ -0,0 +1,69 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion rootProject.ext.android.compileSdkVersion + // buildToolsVersion rootProject.ext.android.buildToolsVersion + defaultConfig { + minSdkVersion rootProject.ext.android.minSdkVersion + targetSdkVersion rootProject.ext.android.targetSdkVersion + versionCode Integer.valueOf(VERSION_CODE) + versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION") + + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + + kapt { + useBuildCache = false + arguments { + arg("AROUTER_MODULE_NAME", "offline"+project.getName()) + } + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + lintOptions { + abortOnError false + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + debug { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation rootProject.ext.dependencies.kotlinstdlib + implementation rootProject.ext.dependencies.androidxappcompat + implementation rootProject.ext.dependencies.arouter + kapt rootProject.ext.dependencies.aroutercompiler + implementation rootProject.ext.dependencies.androidxconstraintlayout + implementation rootProject.ext.dependencies.amapnavi3dmap + + implementation rootProject.ext.dependencies.rxjava + implementation rootProject.ext.dependencies.rxandroid + implementation rootProject.ext.dependencies.androidxrecyclerview + compileOnly rootProject.ext.dependencies.recyclerviewadapterhelper + + implementation project(":OCH:common:common") + implementation project(":OCH:common:data") + compileOnly project(":libraries:mogo-map") + +} + +apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString() \ No newline at end of file diff --git a/OCH/offline/driver/consumer-rules.pro b/OCH/offline/driver/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/OCH/offline/driver/gradle.properties b/OCH/offline/driver/gradle.properties new file mode 100644 index 0000000000..dd5c44ee62 --- /dev/null +++ b/OCH/offline/driver/gradle.properties @@ -0,0 +1,3 @@ +GROUP=com.mogo.och +POM_ARTIFACT_ID=och-bus +VERSION_CODE=1 diff --git a/OCH/offline/driver/proguard-rules.pro b/OCH/offline/driver/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/OCH/offline/driver/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/OCH/offline/driver/src/main/AndroidManifest.xml b/OCH/offline/driver/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..9c5c97035f --- /dev/null +++ b/OCH/offline/driver/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/ShuttleDriverProvider.kt b/OCH/offline/driver/src/main/java/com/mogo/och/offline/ShuttleDriverProvider.kt new file mode 100644 index 0000000000..d835659952 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/ShuttleDriverProvider.kt @@ -0,0 +1,38 @@ +package com.mogo.och.offline + +import android.content.Context +import androidx.fragment.app.Fragment +import com.alibaba.android.arouter.facade.annotation.Route +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import com.mogo.och.offline.fragment.ShuttleFragment +import com.mogo.och.common.module.constant.OchCommonConst +import com.mogo.och.common.module.biz.provider.CommonServiceImpl + +/** + * 网约车小巴业务实现入口 + * + * @author tongchenfei + */ +@Route(path = OchCommonConst.OFFLINE_DRIVER) +class ShuttleDriverProvider : CommonServiceImpl() { + + private val TAG = ShuttleDriverProvider::class.java.simpleName + private var busFragment: ShuttleFragment?=null + + override fun init(context: Context) { + d(SceneConstant.M_TAXI + TAG, "init") + } + + override fun getFragment(): Fragment { + if(busFragment==null){ + busFragment = ShuttleFragment() + } + return busFragment!! + } + + override fun resetFragment() { + busFragment = null + } + +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/bean/BindLineListResponse.kt b/OCH/offline/driver/src/main/java/com/mogo/och/offline/bean/BindLineListResponse.kt new file mode 100644 index 0000000000..eb5b1d093f --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/bean/BindLineListResponse.kt @@ -0,0 +1,50 @@ +package com.mogo.och.offline.bean + +import com.mogo.eagle.core.data.BaseData +import com.mogo.och.data.bean.BusRoutesResult +import com.mogo.och.data.bean.BusStationBean +import java.util.* + +/** + * + */ +data class BindLineListResponse(val data: List?) : BaseData(){ + + data class Result( + var line: LineInfo?, + var siteList: List?,//站点名称 + val contrail: Contrail?,//站点名称 + ) + + data class LineInfo( + val lineId:Long?, + var lineName:String?, + ) + + data class Contrail( + val csvFileUrl:String?, + val csvFileMd5:String?, + val txtFileUrl:String?, + val txtFileMd5:String?, + val contrailSaveTime:Long?, + ) + companion object{ + @JvmStatic + fun getCommonLineInfo(dataItem:Result):BusRoutesResult?{ + val result = BusRoutesResult() + dataItem.siteList?.forEach { + it.drivingStatus = 3 + } + result.setSite(dataItem.siteList) + result.csvFileUrl = dataItem.contrail?.csvFileUrl + result.csvFileMd5 = dataItem.contrail?.csvFileMd5 + result.txtFileUrl = dataItem.contrail?.txtFileUrl + result.txtFileMd5 = dataItem.contrail?.txtFileMd5 + result.contrailSaveTime = dataItem.contrail?.contrailSaveTime?:0 + result.name = dataItem.line?.lineName?:"" + result.lineId = dataItem.line?.lineId?.toInt()?:0 + return result + } + } +} + diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/IBusADASStatusCallback.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/IBusADASStatusCallback.java new file mode 100644 index 0000000000..6a98e9e439 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/IBusADASStatusCallback.java @@ -0,0 +1,11 @@ +package com.mogo.och.offline.callback; + +/** + * Created on 2021/9/8 + * + * Model->Presenter回调:ADAS相关(自动驾驶状态回调,到达终点等等) + */ +public interface IBusADASStatusCallback { + //自驾返回失败 + void onStartAdasFailure(); +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/IBusControllerStatusCallback.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/IBusControllerStatusCallback.java new file mode 100644 index 0000000000..57b51f3ce9 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/IBusControllerStatusCallback.java @@ -0,0 +1,15 @@ +package com.mogo.och.offline.callback; + +import com.mogo.eagle.core.data.map.MogoLocation; + +/** + * Created on 2021/9/10 + * + * Model->Presenter回调:状态控制器监听(accOn、adas ui show、voice ui show、push ui show、v2x ui show等等) + */ +public interface IBusControllerStatusCallback { + // 自车定位 + void onCarLocationChanged(MogoLocation location); + //开始开启自动驾驶 + void startOpenAutopilot(); +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/IBusLinesCallback.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/IBusLinesCallback.java new file mode 100644 index 0000000000..52a93606d1 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/IBusLinesCallback.java @@ -0,0 +1,12 @@ +package com.mogo.och.offline.callback; + +import com.mogo.och.offline.bean.BindLineListResponse; + +/** + * @author: wangmingjun + * @date: 2022/2/9 + */ +public interface IBusLinesCallback { + void onBusLinesChange(BindLineListResponse lines); + void onChangeLineIdSuccess(BindLineListResponse.Result checkLineInfo); +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/IRefreshBusStationsCallback.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/IRefreshBusStationsCallback.java new file mode 100644 index 0000000000..ae121f7932 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/IRefreshBusStationsCallback.java @@ -0,0 +1,23 @@ +package com.mogo.och.offline.callback; + +import com.mogo.och.data.bean.BusStationBean; + +import java.util.List; + +/** + * @author: wangmingjun + * @date: 2021/10/22 + */ +public interface IRefreshBusStationsCallback { + void updateBusTaskStatus(String lineName,String lintTime, + List stationList, + int arrivingOrArrivedIndex, + boolean isArrived); + + /** + * 结束清理一遍、选择任务后清理一遍 + */ + void clearBusStationsMarkers(); + + void updateEmptyUi(); +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/ISlidePannelHideCallback.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/ISlidePannelHideCallback.java new file mode 100644 index 0000000000..1740015a4a --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/callback/ISlidePannelHideCallback.java @@ -0,0 +1,9 @@ +package com.mogo.och.offline.callback; + +/** + * @author: wangmingjun + * @date: 2021/10/22 + */ +public interface ISlidePannelHideCallback { + void hideSlidePanel(); +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/constant/BusConst.kt b/OCH/offline/driver/src/main/java/com/mogo/och/offline/constant/BusConst.kt new file mode 100644 index 0000000000..baae3bea08 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/constant/BusConst.kt @@ -0,0 +1,60 @@ +package com.mogo.och.offline.constant + +import com.mogo.commons.debug.DebugConfig + +/** + * Created on 2021/12/6 + */ +class BusConst { + companion object { + // OCH arouter 路由path + const val PATH = "/driver/api" + + // 测试用的广播 + const val BROADCAST_TEST_BUS_CONTROL_TYPE_EXTRA_KEY = "sceneType" + // 无状态 + const val STATION_STATUS_IDLE = 0 + // 已过站(历史站) + const val STATION_STATUS_LEAVING = 1 + // 到站(当前站) + const val STATION_STATUS_STOPPED = 2 + // 未到站(未到站) + const val STATION_STATUS_ARRIVING = 3 + + // 上报心跳轮询ms + const val LOOP_PERIOD_60S = 60 * 1000L + // 开始服务启动自动驾驶等待时间(埋点上传) + const val LOOP_PERIOD_15S = 15 * 1000L + const val LOOP_PERIOD_1S = 1 * 1000L + const val LOOP_DELAY = 100L + + // 下发给MEC轨迹信息间隔时间 10秒 + const val LOOP_PERIOD_10S = 10 * 1000L + // 尝试下发给MEC轨迹最多10次 + const val LOOP_SEND_TRAJ_TIMES = 10 + + //起点UUID + const val BUS_START_MAP_MAKER = "bus_start_map_maker"; + //终点UUID + const val BUS_END_MAP_MAKER = "bus_end_map_maker"; + + + /** + * 订单起终点Marker类型 + */ + const val TYPE_MARKER_BUS_ORDER = "TYPE_MARKER_BUS_ORDER" + + const val TIMER_START_AUTOPILOT_INTERVAL = 20 * 1000L + + //围栏到站 暂定10米 + const val ARRIVE_AT_END_STATION_DISTANCE = 10 + + // 轮询 + const val LOOP_PASSENGER_5S = 5 * 1000L + const val LOOP_PASSENGER_2S = 2 * 1000L + const val LOOP_PASSENGER_1S = 1 * 1000L + const val LOOP_DELAY_500 = 500L + + const val DELAY_10S = 10 * 1000L + } +} \ No newline at end of file diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/fragment/BaseShuttleTabFragment.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/fragment/BaseShuttleTabFragment.java new file mode 100644 index 0000000000..61e86e3838 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/fragment/BaseShuttleTabFragment.java @@ -0,0 +1,558 @@ +package com.mogo.och.offline.fragment; + +import static com.mogo.och.offline.constant.BusConst.TIMER_START_AUTOPILOT_INTERVAL; + +import android.animation.ObjectAnimator; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.LinearInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.constraintlayout.widget.Group; +import androidx.core.content.ContextCompat; + +import com.mogo.commons.AbsMogoApplication; +import com.mogo.commons.mvp.IView; +import com.mogo.commons.mvp.MvpFragment; +import com.mogo.commons.mvp.Presenter; +import com.mogo.eagle.core.data.config.FunctionBuildConfig; +import com.mogo.eagle.core.data.config.HdMapBuildConfig; +import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager; +import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotRecordListenerManager; +import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager; +import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager; +import com.mogo.eagle.core.function.hmi.ui.msgbox.DriverMsgBoxBubbleView; +import com.mogo.eagle.core.function.hmi.ui.msgbox.DriverMsgBoxButtonView; +import com.mogo.eagle.core.function.hmi.ui.msgbox.DriverMsgBoxListView; +import com.mogo.eagle.core.function.smp.view.SmallMapView; +import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils; +import com.mogo.eagle.core.utilcode.mogo.view.OnPreventFastClickListener; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; +import com.mogo.map.MogoMap; +import com.mogo.map.uicontroller.IMogoMapUIController; +import com.mogo.och.common.module.utils.ResourcesUtils; +import com.mogo.och.offline.R; +import com.mogo.och.offline.model.OrderModel; +import com.mogo.och.offline.view.BizMapView; +import com.mogo.och.data.bean.BusRoutesResult; +import com.mogo.och.offline.view.SlidePanelView; +import com.mogo.och.common.module.utils.SoundPoolHelper; + +import org.greenrobot.eventbus.EventBus; +/** + * 网约车基础Fragment,主要负责布局通用界面,处理站点面板和通话面板互斥情况 + *

+ * 部分业务放在了此处处理 + * + * @author tongchenfei + */ +public abstract class BaseShuttleTabFragment> extends MvpFragment { + + private static final String TAG = "BaseBusTabFragment"; + + protected SlidePanelView slidePanelView; + private RelativeLayout ctvAutopilotStatus; + private ImageView ctvAutopilotStatusIv; + private TextView ctvAutopilotStatusTv; + protected TextView tvArrived; + private FrameLayout flStationPanelContainer; + private BizMapView mapBizView; + private Group groupTestPanel; + + protected SmallMapView smallMapView; + + //消息盒子 + private DriverMsgBoxButtonView viewDriverMsgBoxButton; + private DriverMsgBoxListView viewDriverMsgBoxList; + private DriverMsgBoxBubbleView viewDriverMsgBoxBubble; + + private ObjectAnimator autopilotLoadingAnimator; + + public boolean isAnimateRunning = false; + + /** + * 滑动按钮触发的事件 + */ + private final SlidePanelView.OnSlidePanelMoveToEndListener onSlideToEndListener = () -> { + // 此处做一个代理,处理一下共有情况 + if (getSlidePanelOnEndListener() != null) { + getSlidePanelOnEndListener().moveToEnd(); + } + }; + + @Override + protected int getLayoutId() { + return R.layout.offline_base_fragment; + } + + @Override + protected void initViews() { + mapBizView = findViewById(R.id.mapBizView); + groupTestPanel = findViewById(R.id.groupTestPanel); + slidePanelView = findViewById(R.id.module_mogo_och_slide_panel); + ctvAutopilotStatus = findViewById(R.id.module_mogo_och_autopilot_status); + ctvAutopilotStatusIv = findViewById(R.id.bus_autopilot_btn_iv); + ctvAutopilotStatusTv = findViewById(R.id.bus_autopolot_btn_tv); + flStationPanelContainer = findViewById(R.id.module_mogo_och_station_panel_container); + + tvArrived = findViewById(R.id.module_mogo_och_arrived_tv); + + FrameLayout flSpeed = findViewById(R.id.fl_speed); + if (flSpeed != null) { + CallerDevaToolsManager.INSTANCE.attachAutopilotBeforeLaunchView(flSpeed.getContext(), flSpeed); + } + + LayoutInflater.from(getContext()).inflate(getStationPanelViewId(), flStationPanelContainer); + slidePanelView.setOnSlidePanelMoveToEndListener(onSlideToEndListener); + + updateSwitchMapIcon(); + + initListener(); + setAutopilotBtnStatus(CallerAutoPilotStatusListenerManager.INSTANCE.getState(), + CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false, 0)); + ctvAutopilotStatus.setOnClickListener(new OnPreventFastClickListener() { + + @Override + public void onClickImpl(View v) { + restartAutopilot(); + } + }); + + // 模拟 不可自动驾驶,目前场景是刚开机,adas还未和工控机连接 + findViewById(R.id.btnAutopilotDisable).setOnClickListener(view -> + debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE) + ); + + // 模拟 可自动驾驶,工控机连接正常,且处于人工干预状态 + findViewById(R.id.btnAutopilotEnable).setOnClickListener(view -> + debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE) + ); + + // 模拟 自动驾驶能力,自动驾驶中,可能是停车,可能是行进,但是是机器在处理车的前进后退,不是人 + findViewById(R.id.btnAutopilotRunning).setOnClickListener(view -> + debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) + ); + + findViewById(R.id.btnAutopilotPingxing).setOnClickListener(view -> + debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING) + ); + + // 模拟 自动驾驶网约车回调数据 + findViewById(R.id.btnAutopilotArrive).setOnClickListener(view -> + debugArrivedStation() + ); + + tvArrived.setOnClickListener(view -> { + onArriveStation(); + }); + + //消息盒子 + viewDriverMsgBoxButton = findViewById(R.id.viewDriverMsgBoxButton); + viewDriverMsgBoxList = findViewById(R.id.viewDriverMsgBoxList); + viewDriverMsgBoxBubble = findViewById(R.id.viewDriverMsgBoxBubble); + viewDriverMsgBoxButton.setClickListener(show -> { + if(show){ + viewDriverMsgBoxList.setVisibility(View.VISIBLE); + viewDriverMsgBoxList.notifyData(); + viewDriverMsgBoxBubble.setVisibility(View.GONE); + viewDriverMsgBoxBubble.isShowData(false); + }else{ + viewDriverMsgBoxList.setVisibility(View.GONE); + viewDriverMsgBoxBubble.setVisibility(View.VISIBLE); + viewDriverMsgBoxBubble.isShowData(true); + } + }); + + smallMapView = findViewById(R.id.smallMapView); + } + + @Override + protected void initViews(Bundle savedInstanceState) { + super.initViews(savedInstanceState); + mapBizView.onCreate(savedInstanceState); + smallMapView.onCreateView(savedInstanceState); + } + + @Override + public void onResume() { + super.onResume(); + mapBizView.onResume(); + smallMapView.onResume(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container + , @Nullable Bundle savedInstanceState) { + EventBus.getDefault().register(this); + return super.onCreateView(inflater, container, savedInstanceState); + } + + protected abstract void onArriveStation(); + + private void updateSwitchMapIcon() { + + IMogoMapUIController mapUIController = CallerMapUIServiceManager.INSTANCE.getMapUIController(MogoMap.DEFAULT); + if(mapUIController!=null){ + if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) { + mapUIController.changeCurrentIcon(R.raw.m2); + HdMapBuildConfig.currentCarVrIconRes = R.raw.m2; + }else if (AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode)) { + mapUIController.changeCurrentIcon(R.raw.xiaoba); + HdMapBuildConfig.currentCarVrIconRes = R.raw.xiaoba; + } + } + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + mapBizView.onSaveInstanceState(outState); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapBizView.onLowMemory(); + } + + @Override + public void onPause() { + super.onPause(); + mapBizView.onPause(); + smallMapView.onPause(); + } + + @Override + public void onDestroyView() { + mapBizView.onDestroy(); + if(smallMapView != null){ + smallMapView.onDestroy(); + } + super.onDestroyView(); + CallerAutopilotRecordListenerManager.INSTANCE.removeListener(TAG); + EventBus.getDefault().unregister(this); + } + + /** + * 测试到站 + */ + protected abstract void debugArrivedStation(); + + private void initListener() { + + } + + /** + * 展示滑动按钮 + * + * @param text 指定的文字 + */ + public void showSlidePanel(String text) { + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + slidePanelView.setText(text); + slidePanelView.setVisibility(View.VISIBLE); + } + }, UiThreadHandler.MODE.QUEUE); + setArrivedClikable(false); + } + + /** + * 设置进站按钮状态 + * + * @param isClickable + */ + public void setArrivedClikable(boolean isClickable) { + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + tvArrived.setEnabled(isClickable); + if (isClickable) { + tvArrived.setTextColor(ContextCompat.getColor(AbsMogoApplication.getApp(),R.color.bus_white)); + } else { + tvArrived.setTextColor(ContextCompat.getColor(AbsMogoApplication.getApp(),R.color.bus_arrived_btn_un_clickable_color)); + } + } + }, UiThreadHandler.MODE.QUEUE); + } + + /** + * 隐藏滑动按钮 + */ + public void hideSlidePanel() { + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + slidePanelView.setVisibility(View.GONE); + } + }, UiThreadHandler.MODE.QUEUE); + } + + public void playDI() { + SoundPoolHelper.getSoundPoolHelper().playSoundWithRedId(getContext(), R.raw.bus_di); + } + + /** + * 改变自动驾驶状态 + * + * @param autopilotStatus 0:不可用 1:可用状态 2:自动驾驶中 + */ + public void onAutopilotStatusChanged(int autopilotStatus,boolean canStartAuto) { + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + changeAutopilotBtnView(autopilotStatus, isAnimateRunning,canStartAuto); + } + }, UiThreadHandler.MODE.QUEUE); + } + + public void setAutopilotBtnStatus(int autopilotStatus,boolean canStartAuto) { + if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE == autopilotStatus) {//0不可用 + ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_disable)); + ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_runnig_tv)); + ctvAutopilotStatusIv.setImageResource(R.drawable.bus_disable_autopilot_icon); + ctvAutopilotStatus.setClickable(true); + ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_start_fail); + } else { + ctvAutopilotStatusTv.setTextColor(AbsMogoApplication.getApp().getColor(R.color.bus_autopilot_text_color_normal)); + ctvAutopilotStatusIv.setImageResource(R.drawable.bus_ic_autopilot); + if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE == autopilotStatus) { //1可用 + ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_runnig_tv)); + if(canStartAuto){ + ctvAutopilotStatus.setClickable(true); + ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_press); + }else { + ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_disable)); + ctvAutopilotStatusIv.setImageResource(R.drawable.bus_disable_autopilot_icon); + ctvAutopilotStatus.setClickable(true); + ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_start_fail); + } + } else if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING == autopilotStatus) { + ctvAutopilotStatusTv.setText(R.string.bus_loading_autopilot_runnig_tv); + ctvAutopilotStatus.setClickable(true); + ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_in_autopilot); + } else if (IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING + == autopilotStatus){ + ctvAutopilotStatusTv.setText(R.string.bus_pingxing_driver); + ctvAutopilotStatus.setClickable(false); + ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_pxjs); + } + } + } + + public void updateAutopilotStatus(int autopilotStatus) { + if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING + == autopilotStatus) {//2 running + ctvAutopilotStatusIv.setImageResource(R.drawable.bus_right_autopilot_icon); + ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_normal)); + ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_success_tv)); +// ctvAutopilotStatus.setSelected(false); + ctvAutopilotStatus.setClickable(false); + } else { + ctvAutopilotStatusIv.setImageResource(R.drawable.bus_wrong_autopilot_icon); + ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_normal)); + ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_failure_tv)); + ctvAutopilotStatus.setClickable(false); +// ctvAutopilotStatus.setSelected(false); + } + UiThreadHandler.postDelayed(new Runnable() { + @Override + public void run() { + setAutopilotBtnStatus(autopilotStatus,CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false, 0)); + } + }, 1000); + } + + private void changeAutopilotBtnView(int autopilotStatus, boolean isAnimateRunning,boolean canStartAuto) { + if (isAnimateRunning && IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING + != autopilotStatus) { + // 主动开启自动驾驶中,不为2(为0、1)则继续loading + return; + } + if (isAnimateRunning) { + stopAnimAndUpdateBtnStatus(); + } else { + setAutopilotBtnStatus(autopilotStatus,canStartAuto); + } + + } + + public void stopAnimAndUpdateBtnStatus() { + stopAutopilotAnimation(); + updateAutopilotStatus(CallerAutoPilotStatusListenerManager.INSTANCE.getState()); + } + + /** + * 隐藏【自动驾驶】按钮 + */ + public void hideAutopilotBiz() { + } + + /** + * 展示【自动驾驶】按钮 + */ + public void showAutopilotBiz() { + } + + public SlidePanelView.OnSlidePanelMoveToEndListener getSlidePanelOnEndListener() { + return null; + } + + /** + * 获取站点面板view,在{@link #initViews()}时候添加到container中 + * + * @return 站点面板view + */ + public abstract int getStationPanelViewId(); + + /** + * 重新开启自动驾驶 + */ + public abstract void restartAutopilot(); + + /** + * 模拟自动驾驶返回状态 + * + * @param status + */ + public abstract void debugAutoPilotStatus(int status); + + /** + * 开启自动驾驶中间动画 + */ + public void startAutopilotAnimation() { + isAnimateRunning = true; + ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_tv)); + ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_normal)); + ctvAutopilotStatus.setClickable(true); + ctvAutopilotStatusIv.setImageResource(R.drawable.bus_loading_autopilot_icon); + if (autopilotLoadingAnimator == null) { + autopilotLoadingAnimator = ObjectAnimator.ofFloat(ctvAutopilotStatusIv, "rotation", 0f, 360f); + autopilotLoadingAnimator.setInterpolator(new LinearInterpolator()); + autopilotLoadingAnimator.setRepeatCount(-1);//无限循环 + autopilotLoadingAnimator.setDuration(1000);//设置持续时间 + } + autopilotLoadingAnimator.start();//动画开始 + + startingAutoApilotCountDown(); + + } + + private void startingAutoApilotCountDown() { + //10s 若自动驾驶没有开启,则结束动画 + UiThreadHandler.postDelayed(new Runnable() { + @Override + public void run() { //未启动成功做处理 + if (isAnimateRunning) {// 只判断动画是否在进行,根据自动驾驶当前状态去设置自动驾驶状态 + stopAutopilotAnimation(); + updateAutopilotStatus(CallerAutoPilotStatusListenerManager.INSTANCE.getState()); + } + } + }, TIMER_START_AUTOPILOT_INTERVAL); + + } + + /** + * 停止自动驾驶中间动画 + */ + protected void stopAutopilotAnimation() { + if (autopilotLoadingAnimator != null) { + autopilotLoadingAnimator.end(); + ctvAutopilotStatusIv.clearAnimation(); + autopilotLoadingAnimator = null; + isAnimateRunning = false; + } + } + +// /** +// * 迈速表实时更新 +// * +// * @param newSpeed +// */ +// public void updateSpeedView(float newSpeed) { +// int speed = (int) (Math.abs(newSpeed) * 3.6F); // 倒车时工控机反馈定位信息中speed为负值 +// if (mTrafficDataView != null) { +// mTrafficDataView.updateSpeedWithValue(speed); +// } +// } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + /** + * bus调试面板打开关闭 + */ + public void debugTestBar() { + if (groupTestPanel.getVisibility() == View.VISIBLE) { + groupTestPanel.setVisibility(View.GONE); + } else { + groupTestPanel.setVisibility(View.VISIBLE); + } + } + + /** + * Bus调试信息:线路、轨迹等信息 + *

+ * START + */ + private View busTestBar; + private TextView lineIdTV; + private TextView lineNameTV; + private TextView trajMd5TV; + private TextView stopMd5TV; + private TextView trajMd5DPQPTV; + private TextView stopMd5DPQPTV; + + public void showHideTestBar() { + if (busTestBar == null) { + busTestBar = findViewById(R.id.module_mogo_och_bus_test_bar); + lineIdTV = findViewById(R.id.bus_test_bar_current_line_id); + lineNameTV = findViewById(R.id.bus_test_bar_current_line_name); + trajMd5TV = findViewById(R.id.bus_test_bar_current_traj_md5); + stopMd5TV = findViewById(R.id.bus_test_bar_current_stop_md5); + trajMd5DPQPTV = findViewById(R.id.bus_test_bar_current_traj_md5_dpqp); + stopMd5DPQPTV = findViewById(R.id.bus_test_bar_current_stop_md5_dpqp); + } + + if (busTestBar.getVisibility() == View.VISIBLE) { + busTestBar.setVisibility(View.GONE); + } else { + BusRoutesResult routesResult = OrderModel.getInstance().getBusRoutesResult(); + lineIdTV.setText("lineId:" + (routesResult == null ? "" : String.valueOf(routesResult.getLineId()))); + lineNameTV.setText("lineName:" + (routesResult == null ? "" : routesResult.getName())); + trajMd5TV.setText("TMd5:" + (routesResult == null ? "" : routesResult.csvFileMd5)); + stopMd5TV.setText("SMd5:" + (routesResult == null ? "" : routesResult.txtFileMd5)); + trajMd5DPQPTV.setText("TMd5DPQP:" + (routesResult == null ? "" : routesResult.csvFileMd5DPQP)); + stopMd5DPQPTV.setText("SMd5DPQP:" + (routesResult == null ? "" : routesResult.txtFileMd5DPQP)); + busTestBar.setVisibility(View.VISIBLE); + } + } + + public void updateBusTestBarInfo() { + if (busTestBar != null && busTestBar.getVisibility() == View.VISIBLE) { + BusRoutesResult routesResult = OrderModel.getInstance().getBusRoutesResult(); + lineIdTV.setText("lineId:" + (routesResult == null ? "" : String.valueOf(routesResult.getLineId()))); + lineNameTV.setText("lineName:" + (routesResult == null ? "" : routesResult.getName())); + trajMd5TV.setText("TMd5:" + (routesResult == null ? "" : routesResult.csvFileMd5)); + stopMd5TV.setText("SMd5:" + (routesResult == null ? "" : routesResult.txtFileMd5)); + trajMd5DPQPTV.setText("TMd5DPQP:" + (routesResult == null ? "" : routesResult.csvFileMd5DPQP)); + stopMd5DPQPTV.setText("SMd5DPQP:" + (routesResult == null ? "" : routesResult.txtFileMd5DPQP)); + } + } + /** + * END + */ +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/fragment/ShuttleFragment.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/fragment/ShuttleFragment.java new file mode 100644 index 0000000000..bb0f5adfa7 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/fragment/ShuttleFragment.java @@ -0,0 +1,551 @@ +package com.mogo.och.offline.fragment; + +import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS; +import static com.mogo.map.MogoMap.DEFAULT; + +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.view.View; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.constraintlayout.widget.Group; +import androidx.annotation.Nullable; + +import com.mogo.commons.storage.SharedPrefsMgr; +import com.mogo.eagle.core.data.config.FunctionBuildConfig; +import com.mogo.eagle.core.data.temp.EventLogout; +import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager; +import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager; +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.ActivityUtils; +import com.mogo.eagle.core.utilcode.util.ToastUtils; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; +import com.mogo.map.overlay.IMoGoOverlayManager; +import com.mogo.map.overlay.core.Level; +import com.mogo.map.overlay.point.Point; +import com.mogo.och.common.module.utils.ResourcesUtils; +import com.mogo.och.offline.R; +import com.mogo.och.offline.presenter.BusPresenter; +import com.mogo.och.offline.ui.BusStationCommonItem; +import com.mogo.och.offline.ui.BusSwitchLineActivity; +import com.mogo.och.data.bean.BusStationBean; +import com.mogo.och.offline.constant.BusConst; +import com.mogo.och.offline.view.SlidePanelView; +import com.mogo.och.common.module.utils.BlinkAnimationUtil; +import com.mogo.och.common.module.utils.OCHThreadPoolManager; +import com.mogo.och.common.module.utils.QRUtilsKt; +import com.mogo.och.common.module.wigets.BindQRCodeDialog; +import com.mogo.och.common.module.wigets.MarqueeTextView; +import com.mogo.och.common.module.wigets.OCHCommitDialog; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.List; +import java.util.Objects; + +import me.jessyan.autosize.utils.AutoSizeUtils; + + +/** + * 网约车小巴界面 + * + * @author tongchenfei + */ +public class ShuttleFragment extends BaseShuttleTabFragment + implements SlidePanelView.OnSlidePanelMoveToEndListener, View.OnClickListener { + public static final String TAG = "BusFragment"; + + private TextView mSwitchLine; //切换路线 + private MarqueeTextView mLineName; + private TextView mTaskTime; + private Group groupStationsPanel; + private ConstraintLayout noDataView; + + private BusStationBean startStation = null; + private BusStationBean endStation = null; + private BusStationCommonItem firstStationItem; + private BusStationCommonItem secondStationItem; + private BusStationCommonItem thirdStationItem; + + + @Override + public String getTagName() { + return "BusFragment"; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + } + @Override + public void onDestroyView() { + if (mPresenter != null) { + mPresenter.onDestroy(this); + } + IMoGoOverlayManager overlayManager = CallerMapUIServiceManager.INSTANCE.getOverlayManager(); + if(overlayManager!=null) { + overlayManager.removeAllLines(); + overlayManager.removeAllPoints(); + } + super.onDestroyView(); + } + + @Override + protected void initViews() { + super.initViews(); + + mSwitchLine = findViewById(R.id.switch_line_btn); + mSwitchLine.setTag(0); + mLineName = findViewById(R.id.module_och_bus_line_name); + + firstStationItem = findViewById(R.id.bus_panel_first_station); + secondStationItem = findViewById(R.id.bus_panel_second_station); + thirdStationItem = findViewById(R.id.bus_panel_third_station); + mTaskTime = findViewById(R.id.bus_task_time_tv); + groupStationsPanel = findViewById(R.id.group_stations_panel); + noDataView = findViewById(R.id.no_line_data_view); + + CallerLogger.d(M_BUS + TAG, "initView: " + CallerAutoPilotStatusListenerManager.INSTANCE.getState()); + // 初始化的时候设置 UI 按钮状态 + showAutopilotBiz(); + + mSwitchLine.setOnClickListener(this); + + mLineName.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + showHideTestBar(); + return false; + } + }); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void changeOverview(EventLogout eventLogout){ + if (eventLogout.getMessgae() == EventLogout.LOGOUT_TYPE){ + CallerLogger.d(M_BUS + TAG,"changeOverview Event消息去登出"); + mPresenter.logout(); + }else if (eventLogout.getMessgae() == EventLogout.SHOW_QR_TYPE){ //显示二维码 + CallerLogger.d(M_BUS + TAG,"changeOverview Event qrcode,sn = " + + SharedPrefsMgr.getInstance().getSn()); + String qrUrl = String.format(FunctionBuildConfig.urlJson.getBindDriverQRUrl(), + SharedPrefsMgr.getInstance().getSn()); + Bitmap bmQr = QRUtilsKt.createQRCodeWithPicture( + BitmapFactory.decodeResource(getResources(), R.drawable.icon_qr_center_logo) + ,qrUrl, AutoSizeUtils.dp2px(getContext(),340f), + AutoSizeUtils.dp2px(getContext(),340f),true); + if (bmQr != null){ + BindQRCodeDialog.Builder builder = new BindQRCodeDialog.Builder(); + builder.title(getString(R.string.bind_driver_qr_title)) + .cancelStr(getString(R.string.qr_cancel)) + .qrBm(bmQr).build(getContext()).show(); + }else { + CallerLogger.d(M_BUS + TAG,"bmQr = null "); + } + } + } + + @Override + protected void onArriveStation() { + mPresenter.onAutopilotArriveAtStation(null); + mPresenter.arriveStation(null,"点击进站触发进站操作"); + } + + @Override + protected void debugArrivedStation() { + mPresenter.onAutopilotArriveAtStation(null); + mPresenter.arriveStation(null,"点击debug进站按钮触发进站操作"); + } + + @NonNull + @Override + protected BusPresenter createPresenter() { + return new BusPresenter(this); + } + + @Override + public void onResume() { + super.onResume(); + } + + public void hideStationsPanel(){ + groupStationsPanel.setVisibility(View.GONE); + noDataView.setVisibility(View.VISIBLE); + } + + public void showStationsPanel(){ + groupStationsPanel.setVisibility(View.VISIBLE); + noDataView.setVisibility(View.GONE); + } + + public void updateLineEmptyUI(){ + setArrivedClikable(false); + showOrHideSwitchLineBtn(true); + hideStationsPanel(); + hideSlidePanel(); + resetStationBlinkAnim(); + } + + private void resetStationBlinkAnim() { + BlinkAnimationUtil.clearAnimation(firstStationItem.getCircleImageView()); + BlinkAnimationUtil.clearAnimation(secondStationItem.getCircleImageView()); + BlinkAnimationUtil.clearAnimation(thirdStationItem.getCircleImageView()); + } + + public void updateBusTaskStatus(String lineName, String lineTime, + List stationList, + int arrivingOrArrivedIndex, + boolean isArrived){ + + if (getActivity() == null) { + return; + } + + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + if (stationList == null) { + // 获取小巴数据失败 + return; + } + + showStationsPanel(); + showOrHideSwitchLineBtn(false); + + mLineName.setText(lineName); + mTaskTime.setText(getString(R.string.bus_line_time_tag)+ lineTime); + // 渲染小巴路线数据 + updateBusStationStatus(stationList,arrivingOrArrivedIndex,isArrived); + } + },UiThreadHandler.MODE.QUEUE); + } + + private void updateBusStationStatus(List stationList, + int arrivingOrArrivedIndex, + boolean isArrived) { + + startStation = stationList.get(0); + endStation = stationList.get(stationList.size() - 1); + + if (arrivingOrArrivedIndex == stationList.size() - 1 && isArrived){ + //切换路线和结束路线按钮切换 + showSlidePanel("单程结束"); + + setOrRemoveMapMaker(false, BusConst.BUS_END_MAP_MAKER, endStation.getLat() + , endStation.getLon(),R.raw.end_marker); + }else if (arrivingOrArrivedIndex == 0 && isArrived){ + + showSlidePanel("滑动出发"); + + setOrRemoveMapMaker(true, BusConst.BUS_START_MAP_MAKER, + startStation.getLat(), startStation.getLon(),R.raw.star_marker); + setOrRemoveMapMaker(true, BusConst.BUS_END_MAP_MAKER, + endStation.getLat(), endStation.getLon(),R.raw.end_marker); + }else{ + if (isArrived){ + // 重置滑动按钮文字 + showSlidePanel("滑动出发"); + } + + setOrRemoveMapMaker(false, BusConst.BUS_START_MAP_MAKER, startStation.getLat() + , startStation.getLon(),R.raw.star_marker); + setOrRemoveMapMaker(true, BusConst.BUS_END_MAP_MAKER, endStation.getLat() + , endStation.getLon(),R.raw.end_marker); + } + + if (stationList.size() > 2){ //只有两个站点 + updateMoreThanTwoStationsUI(stationList,arrivingOrArrivedIndex,isArrived); + }else { + updateTwoStationsUI(stationList,arrivingOrArrivedIndex,isArrived); + } + + updateBusTestBarInfo(); + } + + /** + * 有两个以上站点的路线 + * @param stationList + * @param arrivingOrArrivedIndex + * @param isArrived + */ + private void updateMoreThanTwoStationsUI(List stationList, + int arrivingOrArrivedIndex, + boolean isArrived) { + secondStationItem.setStationTag(""); + secondStationItem.showOrHideStationArrowBg(true); + thirdStationItem.setStationTag(""); + secondStationItem.setVisibility(View.VISIBLE); + thirdStationItem.showOrHideStationArrowBg(false); + + if (arrivingOrArrivedIndex == 0 || arrivingOrArrivedIndex -1 == 0 + || (arrivingOrArrivedIndex -2 == 0 && stationList.size() == 3)){ + firstStationItem.setStationTag(ResourcesUtils.getString(R.string.bus_station_txt_tag_start)); + }else { + firstStationItem.setStationTag(""); + } + + if (arrivingOrArrivedIndex + 1 == stationList.size() - 1 || arrivingOrArrivedIndex == stationList.size() - 1 + || (arrivingOrArrivedIndex == 0 && arrivingOrArrivedIndex + 2 == stationList.size() - 1)){ //确认是否显示 "终" + thirdStationItem.setStationTag(ResourcesUtils.getString(R.string.bus_station_txt_tag_end)); + }else { + thirdStationItem.setStationTag(""); + } + + //圆点: 0:灰色 过站 1:绿色 到站或者即将到站 2:蓝色:未到站 + if (arrivingOrArrivedIndex == 0 && isArrived){ + firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected)); + secondStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_arrived_station_name_text_color)); + thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_arrived_station_name_text_color)); + + firstStationItem.setStationName(stationList.get(0).getName()); + secondStationItem.setStationName(stationList.get(1).getName()); + thirdStationItem.setStationName(stationList.get(2).getName()); + + firstStationItem.setStationPointBg(1); + secondStationItem.setStationPointBg(2); + thirdStationItem.setStationPointBg(2); + + firstStationItem.setStationArrowBg(2); + secondStationItem.setStationArrowBg(2); + + }else if (arrivingOrArrivedIndex == stationList.size() - 1){ + firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_station_tag_txt_un_color)); + secondStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_station_tag_txt_un_color)); + thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected)); + + firstStationItem.setStationName(stationList.get(arrivingOrArrivedIndex -2).getName()); + secondStationItem.setStationName(stationList.get(arrivingOrArrivedIndex -1).getName()); + thirdStationItem.setStationName(stationList.get(arrivingOrArrivedIndex).getName()); + + firstStationItem.setStationPointBg(0); + secondStationItem.setStationPointBg(0); + thirdStationItem.setStationPointBg(1); + + firstStationItem.setStationArrowBg(0); + if (isArrived){ + secondStationItem.setStationArrowBg(0); + }else { + secondStationItem.setStationArrowBg(1); + } + + }else { + firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_station_tag_txt_un_color)); + secondStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected)); + thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_arrived_station_name_text_color)); + + firstStationItem.setStationName(stationList.get(arrivingOrArrivedIndex -1).getName()); + secondStationItem.setStationName(stationList.get(arrivingOrArrivedIndex).getName()); + thirdStationItem.setStationName(stationList.get(arrivingOrArrivedIndex + 1).getName()); + + firstStationItem.setStationPointBg(0); + secondStationItem.setStationPointBg(1); + thirdStationItem.setStationPointBg(2); + + secondStationItem.setStationArrowBg(2); + if (isArrived){ + firstStationItem.setStationArrowBg(0); + }else { + firstStationItem.setStationArrowBg(1); + } + } + + } + + /** + * 只有两个站点的路线 + * @param stationList + * @param arrivingOrArrivedIndex + * @param isArrived + */ + private void updateTwoStationsUI(List stationList, + int arrivingOrArrivedIndex, + boolean isArrived) { + + secondStationItem.setVisibility(View.GONE); + secondStationItem.showOrHideStationArrowBg(false); + thirdStationItem.showOrHideStationArrowBg(false); + + firstStationItem.setStationTag(ResourcesUtils.getString(R.string.bus_station_txt_tag_start)); + thirdStationItem.setStationTag(ResourcesUtils.getString(R.string.bus_station_txt_tag_end)); + + firstStationItem.setStationName(stationList.get(0).getName()); + thirdStationItem.setStationName(stationList.get(1).getName()); + + //圆点: 0:灰色 过站 1:绿色 到站或者即将到站 2:蓝色:未到站 + if (arrivingOrArrivedIndex == 0 && isArrived){//到站 + firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected)); + thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_arrived_station_name_text_color)); + firstStationItem.setStationPointBg(1); + firstStationItem.setStationArrowBg(2); + thirdStationItem.setStationPointBg(0); + + }else { + firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_station_tag_txt_un_color)); + thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected)); + if (isArrived){ //到终点 + firstStationItem.setStationPointBg(0); + firstStationItem.setStationArrowBg(0); + thirdStationItem.setStationPointBg(1); + + }else { //到终点途中 + firstStationItem.setStationPointBg(0); + firstStationItem.setStationArrowBg(1); + thirdStationItem.setStationPointBg(1); + } + } + } + + private void showOrHideSwitchLineBtn(boolean isShow) { + if (isShow){//显示切换路线 + mSwitchLine.setTag(0); + mSwitchLine.setText(ResourcesUtils.getString(R.string.bus_switch_line_btn)); + }else {//显示结束路线 + mSwitchLine.setTag(1); + mSwitchLine.setText(ResourcesUtils.getString(R.string.bus_close_line_btn)); + } + } + + public void hideOchBus() { +// tvNotice.setVisibility(View.GONE); + } + + @Override + public int getStationPanelViewId() { + return R.layout.offline_fragment_och; + } + + @Override + public void restartAutopilot() { + if (!isAnimateRunning) { + mPresenter.restartAutopilot(); + } + } + + @Override + public SlidePanelView.OnSlidePanelMoveToEndListener getSlidePanelOnEndListener() { + return this; + } + + @Override + public void moveToEnd() { + // 开启自动驾驶到下一站 + if (isAnimateRunning){ + stopAutopilotAnimation(); + } + mPresenter.autoDriveToNextStation(); + } + + /** + * 设置自动驾驶可用状态 + */ + public void onAutopilotEnableChange(boolean isEnable) { + if (isEnable) { + showAutopilotBiz(); + } else { + hideAutopilotBiz(); + } + } + + public void clearBusStationsMarkers(){ + CallerLogger.d(M_BUS + TAG,"clearBusStationsMarkers()"); + if (null != startStation) { + setOrRemoveMapMaker(false, BusConst.BUS_START_MAP_MAKER, startStation.getLat() + , startStation.getLon(),R.raw.star_marker); + } + if (null != endStation) { + setOrRemoveMapMaker(false, BusConst.BUS_END_MAP_MAKER, endStation.getLat() + , endStation.getLon(),R.raw.end_marker); + } + + //清除鹰眼右下角小地图轨迹 + CallerLogger.d(SceneConstant.M_BUS, "clearBusStationsMarkers --------->"); + smallMapView.clearPolyline(); + } + + /** + * 绘制地图起点终点 + * + * @param isAdd + * @param uuid + */ + private void setOrRemoveMapMaker(boolean isAdd, String uuid, double lat, double longi,int resourceId) { + if (isAdd) { + Runnable setMapMarkerRunnable = () -> { + CallerLogger.d(M_BUS + "setMapMaker= "+Thread.currentThread().getName(), + uuid + "=latitude=" + lat + ",longitude=" + longi); + + Point.Options.Builder builder = new Point.Options.Builder(BusConst.TYPE_MARKER_BUS_ORDER, Level.MAP_MARKER) + .setId(uuid) + .anchor(0.5f, 0.5f) + .set3DMode(true) + .isUseGps(true) + .controlAngle(false) + .icon3DRes(resourceId) + .latitude(lat) + .longitude(longi); + IMoGoOverlayManager overlayManager = CallerMapUIServiceManager.INSTANCE.getOverlayManager(); + if (overlayManager != null) { + overlayManager.showOrUpdatePoint(builder.build(),DEFAULT); + } + }; + + OCHThreadPoolManager.getsInstance().execute(setMapMarkerRunnable); + + }else { + Runnable removeMapMarkerRunnable = () -> { + CallerLogger.d(M_BUS + "RemoveMapMaker="+Thread.currentThread().getName(), + uuid+"=latitude="+lat+",longitude="+longi); + Objects.requireNonNull(CallerMapUIServiceManager.INSTANCE.getOverlayManager()).removePoint(uuid); + }; + OCHThreadPoolManager.getsInstance().execute(removeMapMarkerRunnable); + } + } + + @Override + public void debugAutoPilotStatus(int status) { + mPresenter.debugAutoPilotStatus(status); + } + + @Override + public void onClick(View v) { + if (v.getId() == R.id.switch_line_btn) {//切换路线条件: 自动驾驶过程中,点击则toast提示:自动驾驶中,不可切换路线 + //本次行程未结束,不支持切换路线。点击则toast提示:当前行程未完成,不可切换路线 + if (CallerAutoPilotStatusListenerManager.INSTANCE.getState() + == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) { + ToastUtils.showLong(ResourcesUtils.getString(R.string.bus_switch_line_btn_warning1)); + return; + } + if ((int)mSwitchLine.getTag() == 0){//切换路线 + Intent intent = new Intent(getContext(), BusSwitchLineActivity.class); + ActivityUtils.startActivity(intent); + }else {//结束任务 + OCHCommitDialog.Builder builder = new OCHCommitDialog.Builder(); + OCHCommitDialog closeLineConfirmDialog = builder + .title(getString(R.string.bus_dialog_title)) + .tips(getString(R.string.bus_dialog_tips)) + .confirmStr(getString(R.string.bus_dialog_confirm)) + .cancelStr(getString(R.string.bus_dialog_cancel)) + .build(getContext()); + closeLineConfirmDialog.setClickListener(new OCHCommitDialog.ClickListener() { + @Override + public void confirm() { + mPresenter.abortTask(); + } + + @Override + public void cancel() { + closeLineConfirmDialog.dismiss(); + } + }); + closeLineConfirmDialog.show(); + } + } + } +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/model/BusLineModel.kt b/OCH/offline/driver/src/main/java/com/mogo/och/offline/model/BusLineModel.kt new file mode 100644 index 0000000000..adf135aca1 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/model/BusLineModel.kt @@ -0,0 +1,105 @@ +package com.mogo.och.offline.model + +import com.mogo.commons.storage.SharedPrefsMgr +import com.mogo.eagle.core.utilcode.util.GsonUtils +import com.mogo.och.common.module.manager.loop.BizLoopManager +import com.mogo.och.common.module.manager.loop.LoopInfo +import com.mogo.och.common.module.network.OchCommonServiceCallback +import com.mogo.och.offline.bean.BindLineListResponse +import com.mogo.och.offline.callback.IBusLinesCallback +import com.mogo.och.offline.net.OrderServiceManager +import io.reactivex.schedulers.Schedulers + +/** + * @author: wangmingjun + * @date: 2022/2/9 + */ +object BusLineModel { + private var mBusLinesCallback: IBusLinesCallback? = null + + private const val Catche4AllLines = "Catche4AllLines" + private const val TAG = "BusLineModel" + + private var lastAllLinesJson = "" + + @JvmStatic + fun setBusLinesCallback(callback: IBusLinesCallback?) { + mBusLinesCallback = callback + } + + @JvmStatic + fun queryBusLines() { + val catche4AllLines = SharedPrefsMgr.getInstance().getString(Catche4AllLines) + val bindLineListResponse = + GsonUtils.fromJson(catche4AllLines, BindLineListResponse::class.java) + if (bindLineListResponse != null && mBusLinesCallback != null) { + mBusLinesCallback!!.onBusLinesChange(bindLineListResponse) + } + lastAllLinesJson = catche4AllLines + OrderServiceManager.queryBindLineListBySn(object : OchCommonServiceCallback { + override fun onSuccess(data: BindLineListResponse) { + if (null == data && mBusLinesCallback != null) { + mBusLinesCallback?.onBusLinesChange(null) + return + } + mBusLinesCallback?.onBusLinesChange(data) + val toJson = GsonUtils.toJson(data) + if(lastAllLinesJson==toJson){ + return + }else{ + lastAllLinesJson = toJson + SharedPrefsMgr.getInstance().putString(Catche4AllLines, toJson) + } + } + + override fun onError() { + } + + override fun onFail(code: Int, failMsg: String) { + } + }) + + } + @JvmStatic + fun queryBusLinesByIo() { + OrderServiceManager.queryBindLineListBySn(object : OchCommonServiceCallback { + override fun onSuccess(data: BindLineListResponse) { + if (null == data) { + return + } + + val toJson = GsonUtils.toJson(data) + if(lastAllLinesJson==toJson){ + return + }else{ + lastAllLinesJson = toJson + SharedPrefsMgr.getInstance().putString(Catche4AllLines, toJson) + } + } + + override fun onError() { + } + + override fun onFail(code: Int, failMsg: String) { + } + }) + } + + + @JvmStatic + fun commitSwitchLineId(checkLineInfo: BindLineListResponse.Result?) { + if (mBusLinesCallback != null) { + mBusLinesCallback!!.onChangeLineIdSuccess(checkLineInfo) + } + } + @JvmStatic + fun startLoopAllLine() { + BizLoopManager.setLoopFunction(TAG, LoopInfo(60,::queryBusLinesByIo, scheduler = Schedulers.io())) + } + @JvmStatic + fun stopLoopAllLine() { + BizLoopManager.removeLoopFunction(TAG) + } + + +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/model/OrderModel.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/model/OrderModel.java new file mode 100644 index 0000000000..e6e513cc32 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/model/OrderModel.java @@ -0,0 +1,1126 @@ +package com.mogo.och.offline.model; + +import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS; +import static com.mogo.och.offline.constant.BusConst.DELAY_10S; +import static com.mogo.och.offline.constant.BusConst.STATION_STATUS_ARRIVING; +import static com.mogo.och.offline.constant.BusConst.STATION_STATUS_STOPPED; + +import android.content.Context; +import android.text.TextUtils; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.elegant.network.utils.GsonUtil; +import com.mogo.aicloud.services.socket.IMogoOnMessageListener; +import com.mogo.eagle.core.function.api.telematic.IReceivedMsgListener; +import com.mogo.eagle.core.function.call.telematic.CallerTelematicListenerManager; +import com.mogo.eagle.core.utilcode.util.CoordinateUtils; +import com.mogo.commons.AbsMogoApplication; +import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters; +import com.mogo.eagle.core.data.config.FunctionBuildConfig; +import com.mogo.eagle.core.data.map.MogoLocation; +import com.mogo.eagle.core.utilcode.util.StringUtils; +import com.mogo.och.common.module.manager.autopilot.autopilot.OchAutoPilotManager; +import com.mogo.och.common.module.manager.distance.TrajectoryAndDistanceManager; +import com.mogo.och.common.module.manager.socket.cloud.IOchOnMessageListener; +import com.mogo.och.common.module.manager.socket.lan.LanSocketManager; +import com.mogo.och.common.module.manager.socket.lan.bean.BusinessType; +import com.mogo.och.common.module.voice.VoiceNotice; +import com.mogo.och.offline.R; +import com.mogo.och.offline.callback.IBusADASStatusCallback; +import com.mogo.och.offline.util.ShuttleVoiceManager; +import com.mogo.och.common.module.manager.socket.lan.bean.AppConnectMsg; +import com.mogo.och.common.module.manager.socket.lan.bean.BaseDPMsg; +import com.mogo.och.common.module.manager.socket.lan.bean.DPMsgType; +import com.mogo.och.common.module.manager.socket.lan.bean.TaskDetailsMsg; +import com.mogo.och.common.module.biz.login.LoginStatusManager; +import com.mogo.och.common.module.manager.autopilot.autopilot.ArrivedStation; +import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager; +import com.mogo.och.common.module.utils.MultiRequestLimitChecker; +import com.mogo.och.common.module.utils.OCHThreadPoolManager; +import com.mogo.och.data.bean.BusStationBean; +import com.mogo.och.common.module.manager.socket.cloud.data.SystemMsg; +import com.mogo.och.common.module.constant.OchCommonConst; +import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; +import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager; +import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager; +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; +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.eagle.core.utilcode.util.UiThreadHandler; +import com.mogo.och.data.bean.BusRoutesResult; +import com.mogo.och.offline.callback.IBusControllerStatusCallback; +import com.mogo.och.offline.callback.IRefreshBusStationsCallback; +import com.mogo.och.offline.callback.ISlidePannelHideCallback; +import com.mogo.och.offline.constant.BusConst; +import com.mogo.och.offline.util.BusAnalyticsManager; +import com.mogo.och.offline.util.BusSendTripInfoManager; +import com.mogo.och.offline.util.BusTrajectoryManager; +import com.mogo.och.common.module.manager.socket.cloud.OCHSocketMessageManager; +import com.mogo.och.common.module.callback.OchAdasStartFailureCallback; +import com.mogo.och.common.module.manager.socket.cloud.AbnormalFactorsLoopManager; +import com.mogo.och.common.module.manager.autopilot.OCHAdasAbilityManager; +import com.mogo.och.common.module.utils.DateTimeUtil; +import com.mogo.och.common.module.utils.NumberFormatUtil; +import com.mogo.och.common.module.utils.PinYinUtil; +import com.mogo.och.common.module.manager.socket.lan.bean.BusCacheKey; +import com.mogo.och.data.bean.BusTransferData; +import com.mogo.och.data.manager.cache.CacheDataManager; + +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.exceptions.UndeliverableException; +import io.reactivex.functions.Consumer; +import io.reactivex.plugins.RxJavaPlugins; + +/** + * @author congtaowang + * @since 2021/3/23 + *

+ * 小巴订单管理 + */ +public class OrderModel { + private final String TAG = OrderModel.class.getSimpleName(); + private int backgroundCurrentStationIndex = 0;//A->B 此处值是A站点索引 + private static volatile OrderModel sInstance; + private Context mContext; + private final List stationList = new ArrayList<>(); + private BusRoutesResult busRoutesResult = null; + /** + * 用来表示是否正在开往下一站 + */ + private boolean isGoingToNextStation = false; + // 运营类型 + private static final int VEHICLE_TYPE = 10; + + private IRefreshBusStationsCallback refreshBusStationsCallback; + private ISlidePannelHideCallback slidePanelHideCallback; + private IBusControllerStatusCallback mControllerStatusCallback; //Model->Presenter:VR mode等 + private IBusADASStatusCallback mADASStatusCallback; + + private volatile boolean isArrivedStation = false; + + //0: 代表没有启动过 1代表是启动第一次,当>=1 代表是重试 每次到站/路线结束清空置为0 + private volatile int firstStartAutopilot = 0; + + public static OrderModel getInstance() { + if (sInstance == null) { + synchronized (OrderModel.class) { + if (sInstance == null) { + sInstance = new OrderModel(); + } + } + } + return sInstance; + } + + private OrderModel() { + + } + + public void init() { + mContext = AbsMogoApplication.getApp(); + // 定位监听 + CallerChassisLocationGCJ02ListenerManager.INSTANCE.addListener(TAG, 5, mMapLocationListener); + + //开启自驾后 异常信息返回 + OCHAdasAbilityManager.getInstance().setAdasStartFailureCallback(mAdasStartFailureListener); + + OCHSocketMessageManager.INSTANCE.registerSocketMessageListener(//监听运营消息 + OCHSocketMessageManager.msgMonitorType, + mMogoOnMessageListener); + + AbnormalFactorsLoopManager.INSTANCE.startLoopAbnormalFactors(mContext); + + //监听乘客屏发来的消息 + CallerTelematicListenerManager.INSTANCE.addListener(TAG, mReceivedMsgListener); + + //2022.1.28 + // 调用Disposable.dispose() 时候会出现InterruptedException 导致出现崩溃 + // The exception could not be delivered to the consumer because it has already canceled/disposed + // the flow or the excTeption has nowhere to go to begin with + RxJavaPlugins.setErrorHandler(new Consumer() { + @Override + public void accept(Throwable e) { + if (e instanceof UndeliverableException) { + e = e.getCause(); + CallerLogger.d(M_BUS + TAG, "UndeliverableException"); + } + if ((e instanceof IOException)) {// + // fine, irrelevant network problem or API that throws on cancellation + CallerLogger.d(M_BUS + TAG, "IOException"); + return; + } + if (e instanceof InterruptedException) { + // fine, some blocking code was interrupted by a dispose call + CallerLogger.d(M_BUS + TAG, "InterruptedException"); + return; + } + if ((e instanceof NullPointerException) || (e instanceof IllegalArgumentException)) { + // that's likely a bug in the application + CallerLogger.d(M_BUS + TAG, "NullPointerException or IllegalArgumentException"); + Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e); + return; + } + if (e instanceof IllegalStateException) { + // that's a bug in RxJava or in a custom operator + CallerLogger.d(M_BUS + TAG, "IllegalStateException"); + Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e); + return; + } + CallerLogger.d(M_BUS + TAG, "Undeliverable exception"); + } + }); + } + + private final IReceivedMsgListener mReceivedMsgListener = + new IReceivedMsgListener() { + @Override + public void onDemoMode(boolean isDemoMode) { + + } + + @Override + public void onReceivedServerSn(@Nullable String sn) { + + } + + @Override + public void onReceivedMsg(int type, @NonNull byte[] byteArray) { + if (OchCommonConst.BUSINESS_STRING == type) { + CallerLogger.d(M_BUS + BaseDPMsg.TAG, new String(byteArray)); + BaseDPMsg msg = GsonUtils.fromJson(new String(byteArray), BaseDPMsg.class); + if (msg != null) { + if (msg.getType() == DPMsgType.TYPE_TASK_DETAILS.getType()) { + sendTaskDetailsToClients(); + } + } + } + } + }; + + private final IOchOnMessageListener mMogoOnMessageListener = + new IOchOnMessageListener() { + @Override + public Class target() { + return SystemMsg.class; + } + + @Override + public void onMsgReceived(SystemMsg obj) { + if (obj == null) { + CallerLogger.d(M_BUS + TAG, "onMsgReceived = null"); + return; + } + CallerLogger.i(M_BUS + TAG, "onMsgReceived = " + obj.getContext()); + List list = obj.getScreenList(); + CallerLogger.i(M_BUS + TAG, "onMsgReceived = " + GsonUtils.toJson(list)); + + if (list != null && list.contains(1)) { // 1司机端 + OCHSocketMessageManager.INSTANCE.pushAppOperationalMsgBox(DateTimeUtil.getCurrentTimeStamp(), + obj.getContext(), OCHSocketMessageManager.OPERATION_SYSTEM); + } + + if (list != null && list.contains(2)) { //乘客屏 + AppConnectMsg msg = new AppConnectMsg(true, false, obj.getContext(), -1); + LanSocketManager.sendMsgToClient(msg); + } + + } + }; + + public void setAdasStatusCallback(IBusADASStatusCallback callback) { + this.mADASStatusCallback = callback; + } + + public void setRefreshBusStationsCallback(IRefreshBusStationsCallback callback) { + this.refreshBusStationsCallback = callback; + } + + public void setSlidePanelHideCallback(ISlidePannelHideCallback callback) { + this.slidePanelHideCallback = callback; + } + + public void setControllerStatusCallback(IBusControllerStatusCallback callback) { + this.mControllerStatusCallback = callback; + } + + public void release() { + + // 注销定位监听 + CallerChassisLocationGCJ02ListenerManager.INSTANCE.removeListener(TAG); + + OCHAdasAbilityManager.getInstance().setAdasStartFailureCallback(null); + + OCHSocketMessageManager.INSTANCE.releaseSocketMessageListener( + OCHSocketMessageManager.msgMonitorType); + OCHSocketMessageManager.INSTANCE.releaseSocketMessageListener( + OCHSocketMessageManager.msgWriteOffPassengerType); + + AbnormalFactorsLoopManager.INSTANCE.stopLoopAbnormalFactors(); + //监听乘客屏发来的消息 + CallerTelematicListenerManager.INSTANCE.removeListener(TAG); + } + + private Object readResolve() { + // 阻止反序列化,必须实现 Serializable 接口 + return sInstance; + } + + private final OchAdasStartFailureCallback mAdasStartFailureListener = new OchAdasStartFailureCallback() { + @Override + public void brakeStatusChanged(boolean isBrakeAvailable) { + + } + + @Override + public void onStartAutopilotFailure(@NotNull String startFailedCode, @NonNull String startFailedMessage) { + BusAnalyticsManager.getInstance().triggerStartAutopilotFailureEventByAdas(startFailedCode, startFailedMessage, System.currentTimeMillis()); + if (mADASStatusCallback != null && !FunctionBuildConfig.isDemoMode) { + CallerLogger.e(M_BUS + TAG, "mAdasStartFailureListener = " + startFailedMessage); + mADASStatusCallback.onStartAdasFailure(); + } + } + }; + + // 自车定位 + private final IMoGoChassisLocationGCJ02Listener mMapLocationListener = new IMoGoChassisLocationGCJ02Listener() { + + @Override + public void onChassisLocationGCJ02(@Nullable MogoLocation mogoLocation) { + if (null == mogoLocation) return; + if (mControllerStatusCallback != null) { + mControllerStatusCallback.onCarLocationChanged(mogoLocation); + } + + //是否到站的围栏判断 离站状态并且自动驾驶还未触发到站 + if (isGoingToNextStation && !isArrivedStation) { + OCHThreadPoolManager.getsInstance().locationExecute(new Runnable() { + @Override + public void run() { + judgeArrivedStation(mogoLocation); + } + }); + } + } + }; + + //根据围栏判断,是否到达站点 + private void judgeArrivedStation(MogoLocation location) { + + if (backgroundCurrentStationIndex + 1 > stationList.size() - 1) { + CallerLogger.e(M_BUS + TAG, "到站数组越界"); + return; + } + BusStationBean upcomingStation = stationList.get(backgroundCurrentStationIndex + 1); + + double startLon = upcomingStation.getGcjLon(); + double startLat = upcomingStation.getGcjLat(); + double distance = CoordinateUtils.calculateLineDistance( + startLon, startLat, + location.getLongitude(), location.getLatitude()); + + if (distance <= BusConst.ARRIVE_AT_END_STATION_DISTANCE) { + CallerLogger.d(M_BUS + TAG, "行程日志-judgeArrivedStation() distance = " + distance + + " to " + upcomingStation.getName()); + onArriveAt(null, "兜底:根据定位计算到站"); + } + } + + public void queryBusCacheRoutes() { + String cacheData = CacheDataManager.Companion.getInstance().getCacheData(mContext, + BusCacheKey.BUS_LINE_CACHE); + + if (!StringUtils.isEmpty(cacheData)) { + BusTransferData data = GsonUtils.fromJson(cacheData, BusTransferData.class); + getCacheRouteSuccess(data.getRoutesResult()); + }else { + if (refreshBusStationsCallback != null) { + refreshBusStationsCallback.updateEmptyUi(); + } + clearAutopilotControlParameters(); + closeBeautificationMode(); + clearStartAutopilotTag(); + removeTipRunnables(); + CacheDataManager.Companion.getInstance().clearCacheData(mContext, BusCacheKey.BUS_LINE_CACHE); + } + } + + private void getCacheRouteSuccess(BusRoutesResult data) { + if (data == null || data.getSites() == null + || data.getSites().isEmpty()) { + //当为空时,显示无绑定路线图 + CacheDataManager.Companion.getInstance().clearCacheData(mContext, BusCacheKey.BUS_LINE_CACHE); + return; + } + CallerLogger.d(M_BUS + TAG, "获取到小巴路线数据: " + GsonUtils.toJson(data)); + updateBusStatus(data); + } + + /** + * 查询小巴路线 + */ + public void queryBusRoutes() { + queryBusCacheRoutes(); + } + + /** + * 更新正在运行的任务UI + * + * @param stations + */ + private void updateBusTaskStatus(List stations) { + + int arrivingOrArrivedStationIndex = 0;//已经到站或者即将到站的索引呢 + + for (int i = 0; i < stations.size(); i++) { + BusStationBean station = stations.get(i); + + if (i == 0) { // 首发站 显示在最上面 + if (station.getDrivingStatus() == STATION_STATUS_STOPPED + && !station.isLeaving()) { //到达第一站 + arrivingOrArrivedStationIndex = i; + break; + } + } else { + BusStationBean preStation = stations.get(i - 1); + if ((station.getDrivingStatus() == STATION_STATUS_STOPPED && !station.isLeaving()) + || (station.getDrivingStatus() == STATION_STATUS_ARRIVING + && preStation.isLeaving())) { + //到站未离开 | 即将到站 显示在最中间 + arrivingOrArrivedStationIndex = i; + break; + } + } + } + + BusStationBean arrivingOrArrivedStation = stations.get(arrivingOrArrivedStationIndex); + + String lineTime = DateTimeUtil.formatLongToString( + busRoutesResult.getTaskTime(), + DateTimeUtil.HH_mm); + + if (arrivingOrArrivedStationIndex == 0 || + arrivingOrArrivedStation.getDrivingStatus() == STATION_STATUS_STOPPED + && !arrivingOrArrivedStation.isLeaving()) { + if (refreshBusStationsCallback != null) { + refreshBusStationsCallback.updateBusTaskStatus(busRoutesResult.getName(), lineTime, + stationList, arrivingOrArrivedStationIndex, true); + } + clearAutopilotControlParameters(); + } else { + if (refreshBusStationsCallback != null) { + refreshBusStationsCallback.updateBusTaskStatus(busRoutesResult.getName(), lineTime, + stationList, arrivingOrArrivedStationIndex, false); + } + updateAutopilotControlParameters(); + } + } + + /** + * 重置路线站点状态--结束路线,当前路线恢复到始发站 + */ + public void abortTask() { + CallerLogger.d(M_BUS + TAG, "结束当前路线abortTask"); + if (busRoutesResult == null) { + ToastUtils.showLong("数据异常、请稍后再试"); + return; + } + endOrAbortTaskSuccess(); + clearBusStationDatas(); + queryBusRoutes(); + removeTipRunnables(); + // 取消自驾 + CallerAutoPilotControlManager.INSTANCE.cancelAutoPilot(); + setTrajectoryStation(null, null, -1L); + } + + /** + * 中断或者正常结束任务后的处理 + */ + private void endOrAbortTaskSuccess() { + + isGoingToNextStation = false; + backgroundCurrentStationIndex = 0; + + if (busRoutesResult != null) { + BusSendTripInfoManager.INSTANCE.sendBusTripInfo(BusSendTripInfoManager.END_TRIP + , busRoutesResult.getName() + , "" + , "" + , false); + } + + CacheDataManager.Companion.getInstance().clearCacheData(mContext, BusCacheKey.BUS_LINE_CACHE); + busRoutesResult = null; + + sendTaskDetailsToClients(); + } + + /** + * 离站上报成功后渲染站点 + * 服务端返回的OchBusRoutesResult逻辑, 离开站为当前站, 到达下一站后才会将下一站置为当前站, + * 车机端展示是离开当前站,下一站设置为当前站, 所以服务端数据回来要做处理,不能直接渲染 + */ + private void leaveStationSuccess(int leaveIndex, String leaveStation, + String nextStation, String nextStationKr) { + + onStartAutopilot(leaveIndex); + + leaveTTSTips(nextStation, nextStationKr); + + sendStartStationToClient(nextStation); + + if (busRoutesResult != null) { + boolean isLastStop = false; + if (leaveIndex + 1 == stationList.size() - 1) { + isLastStop = true; + } + //给bus外屏发送 + BusSendTripInfoManager.INSTANCE.sendBusTripInfo(BusSendTripInfoManager.LEAVE_STATION + , busRoutesResult.getName() + , leaveStation + , nextStation + , isLastStop); + } + + reBuildCacheRouteData(leaveIndex, BusConst.STATION_STATUS_STOPPED, true); + } + + private void reBuildCacheRouteData(int currentIndex, int currentDrivingStatus, boolean isLeaving) { + if (busRoutesResult != null) { + List sites = busRoutesResult.getSites(); + BusStationBean bean = sites.get(currentIndex); + bean.setDrivingStatus(currentDrivingStatus); + bean.setLeaving(isLeaving); + sites.set(currentIndex, bean); + if (currentDrivingStatus == STATION_STATUS_STOPPED && !isLeaving) { + BusStationBean beanPre = sites.get(currentIndex - 1); + beanPre.setDrivingStatus(BusConst.STATION_STATUS_LEAVING); + beanPre.setLeaving(false); + sites.set(currentIndex - 1, beanPre); + } + //busRoutesResult.setSite(sites); + + pushCacheTransferData(busRoutesResult); + + updateBusStatus(busRoutesResult); + } + } + + private void onStartAutopilot(int leaveIndex) { + //开启自动驾驶 2.10.0: 如果自动驾驶状态下开启, 非自动驾驶状态下不开启,需手动点击自动驾驶按钮开启 + isGoingToNextStation = true; + if (CallerAutoPilotStatusListenerManager.INSTANCE.getState() + == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) { + startAutopilot(false, leaveIndex); + } else { + firstStartAutopilot = 0; + } + } + + /** + * 开启自动驾驶 + * + * @param isRestart + */ + private void startAutopilot(boolean isRestart, int leaveIndex) { + BusAnalyticsManager.getInstance().triggerClickStartAutopilotTime(System.currentTimeMillis()); + + //1、判断轨迹url是否可用 + if (busRoutesResult != null) { + //根据开关和后台是否发布轨迹启动自驾 + if (FunctionBuildConfig.isPassStartAutopilotCommand + && TextUtils.isEmpty(busRoutesResult.csvFileUrl) + && TextUtils.isEmpty(busRoutesResult.csvFileUrlDPQP) + ) { + ToastUtils.showLong("无发布轨迹, 请发布后重试"); + CallerLogger.e( + TAG, "isPassStartAutopilotCommand = " + + FunctionBuildConfig.isPassStartAutopilotCommand + + "busRoutesResult.csvFileUrl = " + busRoutesResult.csvFileUrl + ); + return; + } + } + //2、6个条件判断 + if (!CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(true, 0)) { + return; + } + // 3、距离轨迹15m计算 + //3、距离轨迹15m计算 + String resion = TrajectoryAndDistanceManager.INSTANCE.canStartAutopilot((long) busRoutesResult.getLineId()); + if (TrajectoryAndDistanceManager.errorTypeNoneLineId.equals(resion)) { + MogoLocation nextStationPoint = new MogoLocation(); + if (backgroundCurrentStationIndex < stationList.size() - 1) { + BusStationBean nextStation = stationList.get(backgroundCurrentStationIndex + 1); + nextStationPoint.setLongitude(nextStation.getGcjLon()); + nextStationPoint.setLatitude(nextStation.getGcjLat()); + } + BusStationBean busStationBean = stationList.get(backgroundCurrentStationIndex); + MogoLocation currentStationPoint = new MogoLocation(); + currentStationPoint.setLongitude(busStationBean.getGcjLon()); + currentStationPoint.setLatitude(busStationBean.getGcjLat()); + setTrajectoryStation(currentStationPoint, nextStationPoint, (long) busRoutesResult.getLineId()); + resion = TrajectoryAndDistanceManager.INSTANCE.canStartAutopilot((long) busRoutesResult.getLineId()); + } + if (!StringUtils.isEmpty(resion)) { + ToastUtils.showShort(resion); + VoiceNotice.showNotice(resion); + return; + } + //4、ssm 给出数据 + if (!FunctionBuildConfig.isDemoMode && !OCHAdasAbilityManager.getInstance().getAutopilotAbilityStatus()) { + ToastUtils.showLong(OCHAdasAbilityManager.getInstance().getAutopilotUnAbilityReason() + + ", 请稍候重试"); + triggerUnableStartAPReasonEvent(); + return; + } + + firstStartAutopilot++; + + triggerStartServiceEvent(isRestart, false); + + AutopilotControlParameters parameters = initAutopilotControlParameters(leaveIndex); + if (null == parameters) { + CallerLogger.e(M_BUS + TAG, "行程日志-AutopilotControlParameters is empty."); + return; + } + + OchAutoPilotManager.startAutoPilot(parameters); + + CallerLogger.d(M_BUS + TAG, "行程日志-开启自动驾驶====" + GsonUtil.jsonFromObject(parameters) + + " startLatLon=" + parameters.startName + ",endLatLon=" + parameters.endName + + "isRestart = " + isRestart); + + if (mControllerStatusCallback != null) { + mControllerStatusCallback.startOpenAutopilot(); + } + } + + /** + * 到站后重置站点状态 + */ + private void arriveSiteStation(String changeInfo) { + OchChainLogManager.writeChainLog("触发进站", changeInfo, + true, OchChainLogManager.EVENT_KEY_INFE_WITH_BUS); + if (backgroundCurrentStationIndex + 1 > stationList.size() - 1) { //到站短时间内调用多次 + CallerLogger.e(M_BUS + TAG, "数组越界"); + return; + } + int arrivedStationIndex = backgroundCurrentStationIndex + 1; + String arriveStation = stationList.get(arrivedStationIndex).getName(); + String arriveStationKr = stationList.get(arrivedStationIndex).getNameKr(); + String departureStopName = stationList.get(backgroundCurrentStationIndex).getName(); + CallerLogger.d(M_BUS + TAG, "arriveSiteStation-currentStationIndex = " + arrivedStationIndex); + + isArrivedStation = true; + isGoingToNextStation = false; + + arriveStationSuccess(arrivedStationIndex, departureStopName, + arriveStation, arriveStationKr); + } + + private void arriveStationSuccess(int arrivedStationIndex, String departureStopName, + String arriveStation, String arriveStationKr) { + if (busRoutesResult != null) { + boolean isLastStop = false; + if (arrivedStationIndex == busRoutesResult.getSites().size() - 1) { + isLastStop = true; + } + //给bus外屏发送 + BusSendTripInfoManager.INSTANCE.sendBusTripInfo(BusSendTripInfoManager.ARRIVE_STATION + , busRoutesResult.getName() + , departureStopName + , arriveStation + , isLastStop); + } + + ShuttleVoiceManager.INSTANCE.arrivedStationBus(arriveStation, arriveStationKr); + + sendArrivedStationToClient(arriveStation); + + reBuildCacheRouteData(arrivedStationIndex, BusConst.STATION_STATUS_STOPPED, false); + } + + private void sendTaskDetailsToClients() { + + BusTransferData data = new BusTransferData(LoginStatusManager.isLogin() ? 1 : 0, busRoutesResult); + TaskDetailsMsg msg = new TaskDetailsMsg(GsonUtils.toJson(data), BusinessType.shuttle); + CallerLogger.d(M_BUS + TAG, "sendTaskDetailsToClients = " + GsonUtils.toJson(msg)); + LanSocketManager.sendMsgToClient(msg); + } + + public void pushCacheTransferData(BusRoutesResult result) { + BusTransferData data = new BusTransferData(LoginStatusManager.isLogin() ? 1 : 0, result); + CallerLogger.d(M_BUS + TAG, "pushCacheTransferData = " + GsonUtils.toJson(data)); + CacheDataManager.Companion.getInstance().putCacheData(mContext, + BusCacheKey.BUS_LINE_CACHE, + GsonUtils.toJson(data)); + } + + private void sendArrivedStationToClient(String arriveStation) { + AppConnectMsg arrivedMsg = new AppConnectMsg(false, true, String.format(mContext + .getString(R.string.bus_arrived_station_tip), + arriveStation), -1); + LanSocketManager.sendMsgToClient(arrivedMsg); + } + + private void sendStartStationToClient(String nextStation) { + AppConnectMsg startMsg = new AppConnectMsg(false, true, String.format(mContext + .getString(R.string.bus_leave_station_tip), + nextStation), -1); + + UiThreadHandler.postDelayed(() -> LanSocketManager.sendMsgToClient(startMsg), DELAY_10S); + } + + private void sendEndTaskToClient() { + AppConnectMsg endMsg = new AppConnectMsg(false, true, mContext + .getString(R.string.bus_end_task_tip), -1); + LanSocketManager.sendMsgToClient(endMsg); + } + + public void sendWriteOffNumToClient(String msg) { + AppConnectMsg passengerMsg = new AppConnectMsg(false, true, msg, -1); + LanSocketManager.sendMsgToClient(passengerMsg); + } + + /** + * 离站上报 + */ + public void leaveStation() { + CallerLogger.d(M_BUS + TAG, "leaveStation-backgroundCurrentStationIndex = " + backgroundCurrentStationIndex); + if (busRoutesResult == null) { + ToastUtils.showLong("数据异常、请稍后再试"); + return; + } + String nextStationName = ""; + String nextStationNameKr = ""; + MogoLocation nextStationPoint = new MogoLocation(); + if (backgroundCurrentStationIndex < stationList.size() - 1) { + BusStationBean nextStation = stationList.get(backgroundCurrentStationIndex + 1); + nextStationName = nextStation.getName(); + nextStationNameKr = nextStation.getNameKr(); + nextStationPoint.setLongitude(nextStation.getGcjLon()); + nextStationPoint.setLatitude(nextStation.getGcjLat()); + } + final String currentStationName = stationList.get(backgroundCurrentStationIndex).getName(); + String finalNextStationName = nextStationName; + String finalNextStationNameKr = nextStationNameKr; + + isArrivedStation = false; + CallerLogger.d(M_BUS + TAG, "行程日志-离站成功开往下一站===="); + + leaveStationSuccess(backgroundCurrentStationIndex, currentStationName, + finalNextStationName, finalNextStationNameKr); + + BusStationBean busStationBean = stationList.get(backgroundCurrentStationIndex); + MogoLocation currentStationPoint = new MogoLocation(); + currentStationPoint.setLongitude(busStationBean.getGcjLon()); + currentStationPoint.setLatitude(busStationBean.getGcjLat()); + setTrajectoryStation(currentStationPoint, nextStationPoint, (long) busRoutesResult.getLineId()); + + String changeInfo = "taskId:" + busRoutesResult.getTaskId() + "--lineId:" + busRoutesResult.getLineId() + + "--currentStationName:" + currentStationName + "--finalNextStationName:" + finalNextStationName; + OchChainLogManager.writeChainLog("滑动出发", changeInfo, + true, OchChainLogManager.EVENT_KEY_INFE_WITH_BUS); + } + + //车站10s后播报 + private void leaveTTSTips(String nextStation, String nextStationKr) { + UiThreadHandler.postDelayed(new Runnable() { + @Override + public void run() {//延迟10s播报 + ShuttleVoiceManager.INSTANCE.leaveStationBus(nextStation, nextStationKr); + } + }, DELAY_10S); + + } + + /** + * 关闭美化模式 + */ + public void closeBeautificationMode() { + if (FunctionBuildConfig.isDemoMode) {//收车结束美化 + FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData = false; //是否强制绘制引导线 + CallerAutoPilotControlManager.INSTANCE.setIgnoreConditionDraw(false);// 同步给乘客屏 + CallerAutoPilotControlManager.INSTANCE.setIPCDemoMode(false);//是否自动启动自驾 + CallerLogger.d(M_BUS + TAG, "美化模式-ignore:置为false"); + } + } + + /** + * 开启自动驾驶到下一站 + */ + public void autoDriveToNextStation() { + if (backgroundCurrentStationIndex >= stationList.size() - 1) { + // 当前站是最后一站,结束当前行程 + travelOver(); + return; + } + leaveStation(); + } + + /** + * 渲染站点信息 + * 服务端返回的OchBusRoutesResult逻辑, 离开站为当前站, 到达下一站后才会将下一站置为当前站, + * 车机端展示 三站: 中间为即将到到达或者刚到达的站 + * + * @param result + */ + private void updateBusStatus(BusRoutesResult result) { + if (result == null) return; + busRoutesResult = result; + stationList.clear(); + stationList.addAll(result.getSites()); + for (int i = 0; i < stationList.size(); i++) { + BusStationBean s = stationList.get(i); + + CallerLogger.d(M_BUS + "updateBusStationsStatus--", + "Index=" + i + " ,name = " + s.getName() + " ," + s.isLeaving() + "," + s.getDrivingStatus()); + + // 是否正在开往下一站 + if (s.isLeaving()) { + isGoingToNextStation = true; + } + // 当前站点信息 + if (s.getDrivingStatus() == STATION_STATUS_STOPPED) { + backgroundCurrentStationIndex = i; + break; + } + } + + if (backgroundCurrentStationIndex == 0 && + stationList.get(0).getDrivingStatus() == STATION_STATUS_STOPPED + && !stationList.get(0).isLeaving()) { //默认是第一站到站查询 + if (busRoutesResult != null) { // 第一站到站也是行程开始的时候 + BusSendTripInfoManager.INSTANCE.sendBusTripInfo(BusSendTripInfoManager.START_TRIP + , busRoutesResult.getName(), "", "", false); + } + + //任务选择后首发前给司机提示任务 + if (busRoutesResult != null) { + beforeTaskTips(); + } + } else { + removeTipRunnables(); + } + + BusStationBean currentStation = stationList.get(backgroundCurrentStationIndex); + + CallerLogger.d(M_BUS + TAG, + "行程日志-STATION_STATUS_STOPPED-backgroundCurrentStationIndex=" + + backgroundCurrentStationIndex + + " isLeaving()=" + currentStation.isLeaving()); + + // 美化是否开始 + if (FunctionBuildConfig.isDemoMode && (backgroundCurrentStationIndex >= 0 + && backgroundCurrentStationIndex <= stationList.size() - 1)) {//行驶过程中设置美化 + if (stationList.get(backgroundCurrentStationIndex).isLeaving()) { + startBeautificationMode(); + CallerLogger.d(M_BUS + TAG, "美化模式-ignore:置为true(每次滑动出发)"); + } else if (backgroundCurrentStationIndex > 0 && backgroundCurrentStationIndex < stationList.size() - 1) { + //美化模式下 中间站点到站 引导线要一直绘制,所以此处不出强制绘制不传false + CallerAutoPilotControlManager.INSTANCE.setIPCDemoMode(false); + CallerLogger.d(M_BUS + TAG, "美化模式-ignore:false(到达中间站)"); + clearStartAutopilotTag(); + } else { + closeBeautificationMode(); + clearStartAutopilotTag(); + } + } + + + if (currentStation.isLeaving() && slidePanelHideCallback != null) { + slidePanelHideCallback.hideSlidePanel(); + } + + sendTaskDetailsToClients(); + + //更新bus路线面板 + updateBusTaskStatus(stationList); + + //需放在currentStationIndex赋值之后 + BusTrajectoryManager.getInstance().syncTrajectoryInfo(); + } + + private void beforeTaskTips() { + if (busRoutesResult == null) return; + + removeTipRunnables(); + + long taskTime = busRoutesResult.getTaskTime(); + long tip3Time = taskTime - 3 * 60 * 1000 - DateTimeUtil.getCurrentTimeStamp(); // 首站离开前3分钟提示 + long tip1Time = taskTime - 60 * 1000 - DateTimeUtil.getCurrentTimeStamp(); // 首站离开前1分钟提示 + + if (tip3Time > 0) { + UiThreadHandler.postDelayed(tip3Runnable, tip3Time); + } + + if (tip1Time > 0) { + UiThreadHandler.postDelayed(tip1Runnable, tip1Time); + } + } + + Runnable tip3Runnable = new Runnable() { + @Override + public void run() { + + if (backgroundCurrentStationIndex == 0 && stationList.get(0).getDrivingStatus() == STATION_STATUS_STOPPED + && !stationList.get(0).isLeaving()) { + tipStartTask("3"); + } else { + removeTipRunnables(); + } + } + }; + + private void tipStartTask(String s) { + String tips = String.format(mContext + .getString(R.string.bus_before_tips_s), s); + //展示在运营消息 + OCHSocketMessageManager.INSTANCE.pushAppOperationalMsgBox( + DateTimeUtil.getCurrentTimeStamp(), + tips, OCHSocketMessageManager.OPERATION_SYSTEM); + ShuttleVoiceManager.INSTANCE.showLeafTime(tips); + } + + Runnable tip1Runnable = new Runnable() { + @Override + public void run() { + if (backgroundCurrentStationIndex == 0 && stationList != null && + stationList.get(0).getDrivingStatus() == STATION_STATUS_STOPPED + && !stationList.get(0).isLeaving()) { + tipStartTask("1"); + } else { + removeTipRunnables(); + } + } + }; + + public void removeTipRunnables() { + if (tip3Runnable != null) { + UiThreadHandler.removeCallbacks(tip3Runnable); + } + if (tip1Runnable != null) { + UiThreadHandler.removeCallbacks(tip1Runnable); + } + } + + private void clearStartAutopilotTag() { + firstStartAutopilot = 0; + } + + private void startBeautificationMode() { + FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData = true; + CallerAutoPilotControlManager.INSTANCE.setIgnoreConditionDraw(true); + CallerAutoPilotControlManager.INSTANCE.setIPCDemoMode(true); + } + + public void clearBusStationDatas() { + if (refreshBusStationsCallback != null) { + refreshBusStationsCallback.clearBusStationsMarkers(); + } + } + + /** + * 在踩刹车、控制方向盘等操作后,会停止自动驾驶,重启自动驾驶的话相当于重新设置自动驾驶目的地 + */ + public void restartAutopilot() { + CallerLogger.d(M_BUS + TAG, "行程日志-重启自动驾驶===" + isGoingToNextStation); + //只去启动自动驾驶,不再去上报离站 + startAutopilot(firstStartAutopilot >= 1, -1); + } + + public boolean isRestartAutopilot() { + return firstStartAutopilot > 1; + } + + /** + * 行程结束 + */ + private void travelOver() { + + if (backgroundCurrentStationIndex >= stationList.size()) { + CallerLogger.e(M_BUS + TAG, "travel over index out of station list"); + return; + } + CallerLogger.d(M_BUS + TAG, "单程结束===="); + CallerAutoPilotControlManager.INSTANCE.cancelAutoPilot(); + setTrajectoryStation(null, null, -1L); + endTask(); + } + + /** + * task正常结束 + */ + private void endTask() { + CallerLogger.d(M_BUS + TAG, "任务正常走完endTask()"); + endOrAbortTaskSuccess(); + clearBusStationDatas(); + queryBusRoutes();// 重新获取任务 + removeTipRunnables(); + ShuttleVoiceManager.INSTANCE.endOrderBus(); + sendEndTaskToClient(); + } + + /** + * 到站 + * + * @param data + */ + public void onArriveAt(ArrivedStation data, String type) { + if (backgroundCurrentStationIndex + 1 > stationList.size() - 1) { + CallerLogger.e(M_BUS + TAG, "行程日志-到站异常,取消后续操作结束"); + return; + } + + //MAP 280 每隔100ms左右返回一次到站, 导致在到达中间站后再次滑动出发后会有时间差,收到一次到站,出现问题 + //此处比对 自驾告诉的到站站点坐标和本地应到站站点坐标, 一致时才能到站 + if (data != null && data.getEndLocation() != null) { + + String latitude = NumberFormatUtil.cutOutNumber(data.getEndLocation().getLatitude(), 5); //wgs + String longitude = NumberFormatUtil.cutOutNumber(data.getEndLocation().getLongitude(), 5); + + int arrivedStationIndex = backgroundCurrentStationIndex + 1; + BusStationBean arriveStation = stationList.get(arrivedStationIndex); + String arriveLat = NumberFormatUtil.cutOutNumber(arriveStation.getLat(), 5); + String arriveLon = NumberFormatUtil.cutOutNumber(arriveStation.getLon(), 5); + + if (!latitude.equals(arriveLat) || !longitude.equals(arriveLon)) { + CallerLogger.e(M_BUS + TAG, "行程日志-到站拦截,到站坐标不一致"); + return; + } + } + + if (isArrivedStation) return; + + CallerLogger.d(M_BUS + TAG, "行程日志-当前==backgroundCurrentStationIndex=" + + backgroundCurrentStationIndex); + + arriveSiteStation(type); + } + + public boolean isGoingToNextStation() { + return isGoingToNextStation; + } + + // 登出 + public void logout() { + MogoLocation gcj02 = CallerChassisLocationGCJ02ListenerManager.INSTANCE.getChassisLocationGCJ02(); + LoginStatusManager.loginOut(); + } + + public void triggerStartServiceEvent(boolean isRestart, boolean send) { + if (stationList == null || backgroundCurrentStationIndex >= stationList.size() - 1) { + return; + } + BusStationBean currentStation = stationList.get(backgroundCurrentStationIndex); + BusStationBean nextStation = stationList.get(backgroundCurrentStationIndex + 1); + BusAnalyticsManager.getInstance().triggerStartAutopilotEvent(isRestart, send, + currentStation.getName(), nextStation.getName(), busRoutesResult.getLineId(), "", System.currentTimeMillis()); + } + + public void triggerUnableStartAPReasonEvent() { + if (stationList == null || backgroundCurrentStationIndex >= stationList.size() - 1) { + return; + } + BusStationBean currentStation = stationList.get(backgroundCurrentStationIndex); + BusStationBean nextStation = stationList.get(backgroundCurrentStationIndex + 1); + BusAnalyticsManager.getInstance().triggerUnableStartAPReasonEvent( + currentStation.getName(), nextStation.getName(), String.valueOf(busRoutesResult.getLineId()), "", + OCHAdasAbilityManager.getInstance().getAutopilotUnAbilityReason()); + } + + public BusRoutesResult getBusRoutesResult() { + return busRoutesResult; + } + + public BusStationBean getBusNextStation() { + // A->B 的过程中A站点的信息 + if (stationList == null || backgroundCurrentStationIndex >= stationList.size() - 1) { + return null; + } + return stationList.get(backgroundCurrentStationIndex); + } + + public int getCurrentStationIndex() { + return backgroundCurrentStationIndex; + } + + /** + * 将业务订单信息保存,鹰眼可取用 + */ + private void updateAutopilotControlParameters() { + + AutopilotControlParameters parameters = initAutopilotControlParameters(-1); + if (null == parameters) { + CallerLogger.e(M_BUS + TAG, "AutopilotControlParameters is empty."); + return; + } + CallerLogger.d(M_BUS + TAG, "AutopilotControlParameters is update."); + CallerAutoPilotStatusListenerManager.INSTANCE.updateAutopilotControlParameters(parameters); + } + + private void clearAutopilotControlParameters() { + CallerLogger.d(M_BUS + TAG, "AutopilotControlParameters is clear."); + CallerAutoPilotStatusListenerManager.INSTANCE.updateAutopilotControlParameters(null); + } + + private AutopilotControlParameters initAutopilotControlParameters(int leaveIndex) { + BusStationBean currentStation = null; + BusStationBean nextStation = null; + + if (leaveIndex < 0) { + if (backgroundCurrentStationIndex + 1 > stationList.size() - 1 || !isGoingToNextStation) { + CallerLogger.e(M_BUS + TAG, "行程日志-mismatch condition1."); + return null; + } + currentStation = stationList.get(backgroundCurrentStationIndex); + nextStation = stationList.get(backgroundCurrentStationIndex + 1); + } else { + if (leaveIndex + 1 > stationList.size() - 1 || !isGoingToNextStation) { + CallerLogger.e(M_BUS + TAG, "行程日志-mismatch condition2."); + return null; + } + currentStation = stationList.get(leaveIndex); + nextStation = stationList.get(leaveIndex + 1); + } + + AutopilotControlParameters parameters = new AutopilotControlParameters(); + parameters.routeID = busRoutesResult.getLineId(); + parameters.routeName = busRoutesResult.getName(); + parameters.startName = PinYinUtil.getPinYinHeadChar(currentStation.getName()); + parameters.endName = PinYinUtil.getPinYinHeadChar(nextStation.getName()); + parameters.startLatLon = new AutopilotControlParameters + .AutoPilotLonLat(currentStation.getLat(), currentStation.getLon()); + parameters.endLatLon = new AutopilotControlParameters + .AutoPilotLonLat(nextStation.getLat(), nextStation.getLon()); + parameters.vehicleType = VEHICLE_TYPE; + if (parameters.autoPilotLine == null) { + parameters.autoPilotLine = new AutopilotControlParameters.AutoPilotLine( + busRoutesResult.getLineId(), busRoutesResult.getName(), + busRoutesResult.csvFileUrl, busRoutesResult.csvFileMd5, + busRoutesResult.txtFileUrl, busRoutesResult.txtFileMd5, + busRoutesResult.contrailSaveTime, busRoutesResult.carModel, + busRoutesResult.csvFileUrlDPQP, busRoutesResult.csvFileMd5DPQP, + busRoutesResult.txtFileUrlDPQP, busRoutesResult.txtFileMd5DPQP, + busRoutesResult.contrailSaveTimeDPQP); + } + + return parameters; + } + + public void setTrajectoryStation(MogoLocation startStation, MogoLocation endStation, Long lineId) { + TrajectoryAndDistanceManager.INSTANCE.setStationPoint(startStation, endStation, lineId); + } + +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/net/IBascApiService.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/net/IBascApiService.java new file mode 100644 index 0000000000..a395e2916e --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/net/IBascApiService.java @@ -0,0 +1,29 @@ +package com.mogo.och.offline.net; +import com.mogo.och.offline.bean.BindLineListResponse; + +import io.reactivex.Observable; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Query; + +/** + * 小巴车相关接口 + * + * @author tongchenfei + *

+ * wiki: http://wiki.zhidaohulian.com/pages/viewpage.action?pageId=48970072 + */ +public interface IBascApiService { + + /** + * 查询车辆配置的所有路线 + * @param appId + * @param ticket + * @param sn + * @return + */ + @GET("/och-vehicle/public/car/queryBindLineListBySn") + Observable queryBindLineListBySn(@Header ("appId") String appId, @Header("ticket") String ticket, @Query("sn") String sn); + +} + diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/net/OrderServiceManager.kt b/OCH/offline/driver/src/main/java/com/mogo/och/offline/net/OrderServiceManager.kt new file mode 100644 index 0000000000..748da2798d --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/net/OrderServiceManager.kt @@ -0,0 +1,35 @@ +package com.mogo.och.offline.net + +import com.mogo.cloud.passport.MoGoAiCloudClientConfig +import com.mogo.commons.AbsMogoApplication +import com.mogo.eagle.core.network.MoGoRetrofitFactory +import com.mogo.commons.storage.SharedPrefsMgr +import com.mogo.och.common.module.constant.OchCommonConst +import com.mogo.och.common.module.network.OchCommonServiceCallback +import com.mogo.och.common.module.network.OchCommonSubscribeImpl +import com.mogo.och.common.module.network.interceptor.transformIoTry +import com.mogo.och.offline.bean.BindLineListResponse + +/** + * @author: wangmingjun + * @date: 2021/10/20 + */ +object OrderServiceManager { + + private val mService: IBascApiService = MoGoRetrofitFactory.getInstance(OchCommonConst.getShuttleUrl()).create( + IBascApiService::class.java + ) + + @JvmStatic + fun queryBindLineListBySn( + callback: OchCommonServiceCallback? + ) { + mService.queryBindLineListBySn( + MoGoAiCloudClientConfig.getInstance().serviceAppId, + SharedPrefsMgr.getInstance().token, + SharedPrefsMgr.getInstance().sn + ) + .transformIoTry() + .subscribe(OchCommonSubscribeImpl(AbsMogoApplication.getApp(), callback, "queryBindLineListBySn")) + } +} \ No newline at end of file diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/presenter/BusLinePresenter.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/presenter/BusLinePresenter.java new file mode 100644 index 0000000000..efa414e901 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/presenter/BusLinePresenter.java @@ -0,0 +1,83 @@ +package com.mogo.och.offline.presenter; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LifecycleOwner; + +import com.mogo.commons.mvp.Presenter; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; +import com.mogo.och.offline.bean.BindLineListResponse; +import com.mogo.och.offline.ui.BusSwitchLineView; +import com.mogo.och.offline.callback.IBusLinesCallback; +import com.mogo.och.offline.model.BusLineModel; +import com.mogo.och.offline.model.OrderModel; + +/** + * @author: wangmingjun + * @date: 2022/2/9 + */ +public class BusLinePresenter extends Presenter implements IBusLinesCallback { + + public BusLinePresenter(BusSwitchLineView view) { + super(view); + OrderModel.getInstance().init(); + } + + @Override + public void onCreate(@NonNull LifecycleOwner owner) { + super.onCreate(owner); + initListener(); + } + + private void initListener() { + BusLineModel.setBusLinesCallback(this); + } + + @Override + public void onBusLinesChange(BindLineListResponse lines) { + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + if(mView!=null) { + mView.onBusLinesChange(lines); + } + } + }, UiThreadHandler.MODE.QUEUE); + } + + @Override + public void onChangeLineIdSuccess(BindLineListResponse.Result checkLineInfo) { + OrderModel.getInstance().pushCacheTransferData(BindLineListResponse.getCommonLineInfo(checkLineInfo)); + OrderModel.getInstance().clearBusStationDatas(); + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + if(mView!=null) { + mView.onChangeLineIdSuccess(); + } + } + }, UiThreadHandler.MODE.QUEUE); + } + + public void queryBusLines(){ + BusLineModel.queryBusLines(); + } + + public void commitSwitchLineId(BindLineListResponse.Result checkLineInfo){ + BusLineModel.commitSwitchLineId(checkLineInfo); + } + + public void removeListener(){ + BusLineModel.setBusLinesCallback(null); + } + + public void queryBusRoutes(){ + OrderModel.getInstance().queryBusRoutes(); + } + + @Override + public void onDestroy(@NonNull LifecycleOwner owner) { + super.onDestroy(owner); + + } + +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/presenter/BusPresenter.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/presenter/BusPresenter.java new file mode 100644 index 0000000000..c7cafccc66 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/presenter/BusPresenter.java @@ -0,0 +1,328 @@ +package com.mogo.och.offline.presenter; + +import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS; + +import android.os.Looper; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LifecycleOwner; + +import com.mogo.commons.AbsMogoApplication; +import com.mogo.commons.mvp.Presenter; +import com.mogo.eagle.core.data.config.FunctionBuildConfig; +import com.mogo.eagle.core.data.map.MogoLocation; +import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager; +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; +import com.mogo.och.common.module.biz.login.LoginStatusEnum; +import com.mogo.och.common.module.manager.autopilot.autopilot.ArrivedStation; +import com.mogo.och.common.module.manager.autopilot.autopilot.IOchAutopilotStatusListener; +import com.mogo.och.common.module.manager.autopilot.autopilot.OchAutoPilotStatusListenerManager; +import com.mogo.och.data.bean.BusStationBean; +import com.mogo.och.offline.callback.IBusADASStatusCallback; +import com.mogo.och.offline.callback.IBusControllerStatusCallback; +import com.mogo.och.offline.callback.IRefreshBusStationsCallback; +import com.mogo.och.offline.callback.ISlidePannelHideCallback; +import com.mogo.och.offline.fragment.ShuttleFragment; +import com.mogo.och.offline.model.BusLineModel; +import com.mogo.och.offline.model.OrderModel; +import com.mogo.och.offline.util.BusTrajectoryManager; +import com.mogo.och.common.module.biz.login.ILoginCallback; +import com.mogo.och.common.module.biz.login.LoginStatusManager; +import com.mogo.och.common.module.manager.autopilot.OCHAdasAbilityManager; + + +import java.util.ArrayList; +import java.util.List; + +import mogo_msg.MogoReportMsg; + +/** + * 网约车小巴 + * + * @author tongchenfei + */ +public class BusPresenter extends Presenter + implements IRefreshBusStationsCallback, ISlidePannelHideCallback + , IOchAutopilotStatusListener, IBusControllerStatusCallback, ILoginCallback, IBusADASStatusCallback { + + private static final String TAG = "BusPresenter"; + + private final List mStationList = new ArrayList<>(); + private int mCurrentStation = 0; + + public BusPresenter(ShuttleFragment view) { + super(view); + //2021.11.1 鹰眼架构整合,由IMoGoAutopilotStatusListener逐步替代IMogoAdasOCHCallback接口 + OrderModel.getInstance().init(); + OCHAdasAbilityManager.getInstance().init(AbsMogoApplication.getApp()); + + } + + @Override + public void onCreate(@NonNull LifecycleOwner owner) { + super.onCreate(owner); + initModelListener(); + + OrderModel.getInstance().queryBusCacheRoutes(); + } + + @Override + public void onDestroy(@NonNull LifecycleOwner owner) { + super.onDestroy(owner); + OrderModel.getInstance().release(); + releaseListener(); + } + + public void initModelListener() { + OrderModel.getInstance().setRefreshBusStationsCallback(this); + OrderModel.getInstance().setSlidePanelHideCallback(this); + OrderModel.getInstance().setControllerStatusCallback(this); + OrderModel.getInstance().setAdasStatusCallback(this); + OchAutoPilotStatusListenerManager.INSTANCE.addListener(TAG,this); + LoginStatusManager.INSTANCE.addListener(TAG,this); + } + + public void releaseListener() { + OrderModel.getInstance().setRefreshBusStationsCallback(null); + OrderModel.getInstance().setSlidePanelHideCallback(null); + OrderModel.getInstance().setControllerStatusCallback(null); + OrderModel.getInstance().setAdasStatusCallback(null); + OCHAdasAbilityManager.getInstance().release(); + OchAutoPilotStatusListenerManager.INSTANCE.removeListener(TAG); + LoginStatusManager.INSTANCE.removeListener(TAG); + } + + public void abortTask() { + OrderModel.getInstance().abortTask(); + } + + public void autoDriveToNextStation() { + OrderModel.getInstance().autoDriveToNextStation(); + } + + public void restartAutopilot() { + if (OrderModel.getInstance().isGoingToNextStation()){ + OrderModel.getInstance().restartAutopilot(); + } + } + + // 登出 + public void logout() { + OrderModel.getInstance().logout(); + } + + @Override + public void updateBusTaskStatus(String lineName,String lineTime, + List stationList, + int arrivingOrArrivedIndex, + boolean isArrived) { + mStationList.clear(); + mStationList.addAll(stationList); + if (arrivingOrArrivedIndex == 0 || isArrived){ + mCurrentStation = arrivingOrArrivedIndex; + }else { + mCurrentStation = arrivingOrArrivedIndex -1; + } + CallerLogger.d(M_BUS + "BusOrderModel =", " mCurrentStation =" + mCurrentStation); + + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + if(mView!=null) { + mView.updateBusTaskStatus(lineName,lineTime, + stationList, arrivingOrArrivedIndex, isArrived); + } + } + }, UiThreadHandler.MODE.QUEUE); + } + + @Override + public void updateEmptyUi() { + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + if(mView!=null) { + mView.updateLineEmptyUI(); + } + } + }, UiThreadHandler.MODE.QUEUE); + } + + @Override + public void clearBusStationsMarkers() { + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + if(mView!=null) { + mView.clearBusStationsMarkers(); + } + } + }, UiThreadHandler.MODE.QUEUE); + } + + @Override + public void hideSlidePanel() { + if (mView != null) { + mView.hideSlidePanel(); + mView.setArrivedClikable(true); + } + } + + @Override + public void onAutopilotArriveAtStation(ArrivedStation arrivedStation) { + CallerLogger.e( M_BUS + TAG, "行程日志-onAutopilotArriveAtStation arrive"); + arriveStation(arrivedStation,"底盘触发进站"); + } + + public void arriveStation(ArrivedStation arrivedStation,String type){ + OrderModel.getInstance().onArriveAt(arrivedStation,type); + } + + @Override + public void onAutopilotStatusResponse(int state) { + switch (state) { + case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE: + case IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING: + case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE: + if (FunctionBuildConfig.isDemoMode + && ( + (mCurrentStation >= 0 && mCurrentStation <= mStationList.size() - 1) + && OrderModel.getInstance().isGoingToNextStation() + ) + ) { + CallerLogger.d(M_BUS + "BusOrderModel=", "有美化功能"); + return; + } + // 改变UI自动驾驶状态 + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + if(mView!=null) { + mView.onAutopilotStatusChanged(state, CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false,0)); + } + } + }, UiThreadHandler.MODE.QUEUE); + break; + case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING: + OrderModel.getInstance().triggerStartServiceEvent( + OrderModel.getInstance().isRestartAutopilot(), true); + // 改变UI自动驾驶状态 + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + if(mView!=null) { + mView.onAutopilotStatusChanged(state, CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false,0)); + } + } + }, UiThreadHandler.MODE.QUEUE); + break; + default: + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + if(mView!=null) { + mView.onAutopilotEnableChange(false); + } + } + }, UiThreadHandler.MODE.QUEUE); + break; + } + } + + @Override + public void onCarLocationChanged(MogoLocation location) { +// if (null != location) { +// runOnUIThread(() -> mView.updateSpeedView(location.getGnssSpeed())); +// } + } + + @Override + public void startOpenAutopilot() { + //非美化模式下启动动画 + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + if(mView!=null) { + mView.startAutopilotAnimation(); + } + } + }, UiThreadHandler.MODE.QUEUE); + + //中间站点再次开启自驾时, 自动驾驶状态是2未改变, 此次鹰眼底层不再返给业务,需优化按钮动画显示 + if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING + == CallerAutoPilotStatusListenerManager.INSTANCE.getState()&&mView!=null){ + mView.onAutopilotStatusChanged(CallerAutoPilotStatusListenerManager.INSTANCE.getState(), + CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false,0)); + } + } + + private void runOnUIThread(Runnable executor) { + if (executor == null) { + return; + } + if (Looper.myLooper() != Looper.getMainLooper()) { + UiThreadHandler.post(executor); + } else { + executor.run(); + } + } + + /** + * 测试使用 + */ + public void debugAutoPilotStatus(int status) { + onAutopilotStatusResponse(status); + } + + + @Override + public void onAutopilotGuardian(MogoReportMsg.MogoReportMessage guardianInfo, long lineId) { + BusTrajectoryManager.getInstance().onAutopilotGuardian(guardianInfo,lineId); + } + + @Override + public void onStatusChange(LoginStatusEnum currentStatus) { + CallerLogger.d(M_BUS + TAG, " loginStatus =" + LoginStatusManager.isLogin()); + if(LoginStatusManager.isLogin()){ +// OrderModel.getInstance().queryBusRoutes(); + OrderModel.getInstance().queryBusCacheRoutes(); + BusLineModel.startLoopAllLine(); + }else { + BusLineModel.stopLoopAllLine(); + BusTrajectoryManager.getInstance().stopTrajReqLoop(); + BusTrajectoryManager.getInstance().stopTrajReqLoop(); + clearBusStationsMarkers(); + if(mView!=null) { + mView.hideSlidePanel(); + } + OrderModel.getInstance().closeBeautificationMode(); + } + } + + @Override + public void onStartAdasFailure() { + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + if(mView!=null) { + mView.stopAnimAndUpdateBtnStatus(); + } + } + }, UiThreadHandler.MODE.QUEUE); + } + + @Override + public void canStartAutopilot(boolean canStart) { + UiThreadHandler.post(new Runnable() { + @Override + public void run() { + if(mView!=null) { + mView.onAutopilotStatusChanged(CallerAutoPilotStatusListenerManager.INSTANCE.getState(),canStart); + } + } + }, UiThreadHandler.MODE.QUEUE); + } +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/BusStationCommonItem.kt b/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/BusStationCommonItem.kt new file mode 100644 index 0000000000..88a7b65a85 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/BusStationCommonItem.kt @@ -0,0 +1,99 @@ +package com.mogo.och.offline.ui + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.core.content.ContextCompat +import com.mogo.och.common.module.utils.BlinkAnimationUtil +import com.mogo.och.offline.R +import kotlinx.android.synthetic.main.offline_stations_common_item.view.* + +/** + * @author: wangmingjun + * @date: 2022/9/15 + */ +class BusStationCommonItem @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr){ + + init { + LayoutInflater.from(context).inflate(R.layout.offline_stations_common_item,this,true) + } + + fun setStationName(name: String){ + busStationNameTv.text = name + } + + fun setStationNameColor(color: Int){ + busStationNameTv.setTextColor(color) + } + + fun setStationPointBg(type: Int) { // 0:灰色 过站 1:绿色 到站或者即将到站 2:蓝色:未到站 + BlinkAnimationUtil.clearAnimation(busCircleIv) + when (type) { + 0 -> { + busCircleIvBg.visibility = GONE + busCircleIv.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.icon_point_grey_bus + ) + ) + } + 1 -> { + busCircleIvBg.visibility = VISIBLE + busCircleIv.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.icon_point_green_bus + ) + ) + BlinkAnimationUtil.setAnimation(busCircleIv) + } + 2 -> { + busCircleIvBg.visibility = GONE + busCircleIv.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.icon_point_blue_bus + ) + ) + } + + } + } + + fun getCircleImageView() : ImageView{ + return busCircleIv + } + + fun setStationArrowBg(type: Int){// 0:灰色 过站 1:绿色 前往下一站 2:蓝色 未到站 + when(type){ + 0 -> busArrowBg.setImageResource(R.drawable.icon_arrow_grey_bus) + 1 -> busArrowBg.setImageResource(R.drawable.icon_arrow_green_bus) + 2 -> busArrowBg.setImageResource(R.drawable.icon_arrow_blue_bus) + } + + } + + fun setStationTag(tag: String){ // 0:起 1:终 + if (tag.isNullOrEmpty()){ + busTagTxt.visibility = GONE + }else{ + busTagTxt.text = tag + busTagTxt.visibility = VISIBLE + } + } + + fun showOrHideStationArrowBg(isShow:Boolean){ + if (isShow){ + busArrowBg.visibility = VISIBLE + }else{ + busArrowBg.visibility = GONE + } + } +} \ No newline at end of file diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/BusSwitchLineActivity.kt b/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/BusSwitchLineActivity.kt new file mode 100644 index 0000000000..93b9cc2f45 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/BusSwitchLineActivity.kt @@ -0,0 +1,181 @@ +package com.mogo.och.offline.ui + +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 android.widget.ImageView +import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.mogo.commons.mvp.MvpActivity +import com.mogo.commons.storage.SharedPrefsMgr +import com.mogo.och.offline.presenter.BusLinePresenter +import com.mogo.och.offline.ui.adapter.SwitchLineAdapter +import com.mogo.och.offline.ui.adapter.OpenItemAnimator +import com.mogo.eagle.core.utilcode.mogo.view.SpacesItemDecoration +import com.mogo.eagle.core.utilcode.util.ToastUtils +import com.mogo.och.offline.R +import com.mogo.och.offline.bean.BindLineListResponse +import java.util.ArrayList + +/** + * @author: wangmingjun + * @date: 2022/2/8 + */ +class BusSwitchLineActivity : MvpActivity(), + View.OnClickListener, BusSwitchLineView { + + companion object{ + const val LASTCOMMITLINEID = "lastcommitlineid" + } + + private lateinit var mClose: ImageView + private lateinit var mNoDatasView: ConstraintLayout + private lateinit var mLinesListView: RecyclerView + private lateinit var mLineCommitBtn: TextView + private lateinit var mAdapter: SwitchLineAdapter + private lateinit var linearLayoutManager:LinearLayoutManager + private val mData: MutableList = ArrayList() + private var checkLineInfo:BindLineListResponse.Result? = null + override fun getLayoutId(): Int { + return R.layout.offline_switch_line + } + + override fun createPresenter(): BusLinePresenter { + return BusLinePresenter(this) + } + + override fun initViews() { + initWH() + initView() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + } + + override fun onResume() { + super.onResume() + initDatas() + } + + /** + * 初始化view + */ + private fun initView() { + mClose = findViewById(R.id.switch_line_close) + mClose.setOnClickListener(this) + mNoDatasView = findViewById(R.id.no_order_data_view) + mLineCommitBtn = findViewById(R.id.switch_line_btn_commit) + mLineCommitBtn.setOnClickListener(this) + mLinesListView = findViewById(R.id.switch_line_rv) + linearLayoutManager = LinearLayoutManager(this) + mLinesListView.setLayoutManager(linearLayoutManager) + mLinesListView.setItemAnimator(OpenItemAnimator()) + mAdapter = SwitchLineAdapter(applicationContext, mData) + mLinesListView.addItemDecoration( + SpacesItemDecoration( + 4 + ) + ) + mLinesListView.setAdapter(mAdapter) + //设置item 点击事件 + mAdapter.setOnLineItemClickListener(object : SwitchLineAdapter.LineItemClickListener{ + override fun onItemClick(lineInfo: BindLineListResponse.Result) { + // 选中的线路 + checkLineInfo = lineInfo + } + }) + } + + /** + * 设置布局宽高 + */ + private fun initWH() { + 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 initDatas() { + mPresenter?.queryBusLines() + } + + /** + * 查询返回绑定路线集合 + * @param data + */ + override fun onBusLinesChange(data: BindLineListResponse?) { + if (null == data) { + showNoData(true) + return + } + if (data.data != null && data.data.size > 0) { + showNoData(false) + mData.clear() + mData.addAll(data.data) + mAdapter.notifyDataSetChanged() + } else { + showNoData(true) + } + } + + override fun onChangeLineIdSuccess() { + ToastUtils.showLong(resources.getString(R.string.bus_change_line_commit_tip_s)) + mPresenter?.queryBusRoutes() + mAdapter.setOnLineItemClickListener(null) + mPresenter?.removeListener() + finish() + } + + /** + * 有无数据UI显示 + * @param b + */ + private fun showNoData(b: Boolean) { + if (b) { + mLinesListView.visibility = View.GONE + mLineCommitBtn.visibility = View.GONE + mNoDatasView.visibility = View.VISIBLE + } else { + mLinesListView.visibility = View.VISIBLE + mLineCommitBtn.visibility = View.VISIBLE + mNoDatasView.visibility = View.GONE + } + } + + override fun onClick(v: View) { + //关闭dialog + if (v.id == R.id.switch_line_close) { + finish() + return + } + //切换路线提交 + if (v.id == R.id.switch_line_btn_commit) { + if (checkLineInfo==null) { + ToastUtils.showLong("请选择任务") + }else{ + mPresenter?.commitSwitchLineId(checkLineInfo) + } + } + } + + override fun onDestroy() { + mPresenter!!.removeListener() + super.onDestroy() + } +} \ No newline at end of file diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/BusSwitchLineView.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/BusSwitchLineView.java new file mode 100644 index 0000000000..e49d76f67e --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/BusSwitchLineView.java @@ -0,0 +1,16 @@ +package com.mogo.och.offline.ui; + +import com.mogo.commons.mvp.IView; +import com.mogo.och.offline.bean.BindLineListResponse; + +/** + * @author: wangmingjun + * @date: 2022/2/10 + */ +public interface BusSwitchLineView extends IView { + + void onBusLinesChange(BindLineListResponse data); + void onChangeLineIdSuccess(); + +} + diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/adapter/OpenItemAnimator.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/adapter/OpenItemAnimator.java new file mode 100644 index 0000000000..fc7beebd9c --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/adapter/OpenItemAnimator.java @@ -0,0 +1,643 @@ +package com.mogo.och.offline.ui.adapter; + +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 androidx.recyclerview.widget.SimpleItemAnimator; + +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 OpenItemAnimator 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<>(); + + ArrayList> mAdditionsList = new ArrayList<>(); + ArrayList> mMovesList = new ArrayList<>(); + ArrayList> mChangesList = new ArrayList<>(); + + ArrayList mAddAnimations = new ArrayList<>(); + ArrayList mMoveAnimations = new ArrayList<>(); + ArrayList mRemoveAnimations = new ArrayList<>(); + 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 PointlessBooleanExpression,ConstantConditions + if (mRemoveAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mRemoveAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mAddAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mAddAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mChangeAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mChangeAnimations list"); + } + + //noinspection PointlessBooleanExpression,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/offline/driver/src/main/java/com/mogo/och/offline/ui/adapter/SwitchLineAdapter.kt b/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/adapter/SwitchLineAdapter.kt new file mode 100644 index 0000000000..cdd6fa06db --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/ui/adapter/SwitchLineAdapter.kt @@ -0,0 +1,107 @@ +package com.mogo.och.offline.ui.adapter + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.appcompat.widget.AppCompatTextView +import androidx.recyclerview.widget.RecyclerView +import com.mogo.och.offline.R +import com.mogo.och.offline.bean.BindLineListResponse +import com.mogo.och.offline.ui.adapter.SwitchLineAdapter.SwitchLineViewHolder +import kotlin.text.StringBuilder + +/** + * 路线列表adapter + */ +class SwitchLineAdapter( + private val mContext: Context, + private val mData: List +) : RecyclerView.Adapter() { + companion object{ + const val TAG = "SwitchLineAdapter" + } + // RecyclerView设置点击事件 + private var mItemClickListener: LineItemClickListener? = null + private var checkInfo:BindLineListResponse.Result? = null + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): SwitchLineViewHolder { + val view = LayoutInflater.from(mContext).inflate( + R.layout.offline_switch_line_list_item, parent, false + ) + return SwitchLineViewHolder(view) + } + + override fun onBindViewHolder(holder: SwitchLineViewHolder, position: Int) { + val currentPosition = holder.bindingAdapterPosition + val lineInfo = mData[currentPosition] + + if (lineInfo==checkInfo) { + holder.itemView.setBackgroundResource(R.drawable.bus_shape_select_line_item_bg_normal) + } else { + holder.itemView.setBackgroundColor(Color.parseColor("#162761")) + } + + lineInfo.line?.let {line-> + line.lineName?.let { + if(it.length>10){ + holder.linelineName.text = it.substring(0,10)+"…" + }else{ + holder.linelineName.text = lineInfo.line?.lineName + } + } + + } + + lineInfo.siteList?.let { + val last = it.last() + last.name?.let {siteName-> + val sb = StringBuilder() + if (siteName.length>10) { + sb.append(siteName.substring(0,5)) + sb.append("…") + sb.append(siteName.substring(siteName.length-5,siteName.length)) + }else{ + sb.append(siteName) + } + val string = mContext.getString(R.string.bus_line_goto_end, sb.toString()) + holder.lineEndlineName.text = string + } + } + + //设置item点击事件 + holder.itemView.setOnClickListener { + val oldPosition = mData.indexOf(checkInfo) + checkInfo = lineInfo + notifyItemChanged(oldPosition) + notifyItemChanged(currentPosition) + mItemClickListener?.onItemClick(lineInfo) + } + } + + override fun getItemCount(): Int { + return mData.size + } + + fun setOnLineItemClickListener(itemClickListener: LineItemClickListener?) { + mItemClickListener = itemClickListener + } + + class SwitchLineViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val linelineName: AppCompatTextView//线路名称 + val lineEndlineName: AppCompatTextView //终点 + + init { + linelineName = itemView.findViewById(R.id.switch_line_name) + lineEndlineName = itemView.findViewById(R.id.switch_line_end_station) + } + } + + interface LineItemClickListener { + fun onItemClick(lineInfo: BindLineListResponse.Result) + } +} \ No newline at end of file diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/util/BusAnalyticsManager.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/util/BusAnalyticsManager.java new file mode 100644 index 0000000000..7bb6544564 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/util/BusAnalyticsManager.java @@ -0,0 +1,56 @@ +package com.mogo.och.offline.util; + + +import androidx.annotation.NonNull; + +import com.mogo.och.common.module.manager.autopilot.autopilot.OchAutopilotAnalytics; + +/** + * OCH Bus埋点工具 + *

+ * Created on 2022/3/24 + */ +public class BusAnalyticsManager extends OchAutopilotAnalytics { + + // 埋点key:开启自动驾驶前已识别的异常,会导致无法开启自驾 + private static final String EVENT_KEY_AP_UNABLE_START_REASON = "event_key_och_bus_ap_unable_start_reason"; + // 埋点key:接管后点击'自动驾驶'按钮启动 + private static final String EVENT_KEY_RESTART_AUTOPILOT = "event_key_och_bus_restart_autopilot"; + // 埋点key:开始服务开启自动驾驶(成功/失败) + private static final String EVENT_KEY_START_SERVICE = "event_key_och_bus_start_service"; + // 埋点key:点击启动自驾 + private static final String EVENT_KEY_CLICK_START_AUTOPILOT = "event_key_och_shuttle_click_start_autopilot"; + + private static final class SingletonHolder { + private static final BusAnalyticsManager INSTANCE = new BusAnalyticsManager(); + } + + public static BusAnalyticsManager getInstance() { + return BusAnalyticsManager.SingletonHolder.INSTANCE; + } + + @NonNull + @Override + public String getEventKeyStartService() { + return EVENT_KEY_START_SERVICE; + } + + @NonNull + @Override + public String getEventKeyRestartService() { + return EVENT_KEY_RESTART_AUTOPILOT; + } + + @NonNull + @Override + public String getEventKeyApUnableStartReason() { + return EVENT_KEY_AP_UNABLE_START_REASON; + } + + @NonNull + @Override + public String getEventKeyClickStartAutopilot() { + return EVENT_KEY_CLICK_START_AUTOPILOT; + } + +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/util/BusSendTripInfoManager.kt b/OCH/offline/driver/src/main/java/com/mogo/och/offline/util/BusSendTripInfoManager.kt new file mode 100644 index 0000000000..cc30b5dae7 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/util/BusSendTripInfoManager.kt @@ -0,0 +1,36 @@ +package com.mogo.och.offline.util + +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant + +/** + * @author: wangmingjun + * @date: 2022/10/24 + */ +object BusSendTripInfoManager{ + + const val START_TRIP = 1 + const val END_TRIP = 2 + const val LEAVE_STATION = 3 + const val ARRIVE_STATION = 4 + + /** + * 行程信息 + * @param type 事件类型, 1:行程开始, 2:行程结束, 3:出站, 4:进站, 5:城市占道施工预警 + * @param lineName 路线名, for type 1, 2 + * @param departureStopName 出站站点名, for type 3, 4 + * @param arrivalStopName 下一站到达站点名, for type 3, 4 + * @param isLastStop 是否终点站(下一站或者要到达站) + * @return + */ + fun sendBusTripInfo(type: Int, lineName: String, + departureStopName: String, + arrivalStopName: String, + isLastStop: Boolean) { + d(SceneConstant.M_BUS + "BusSendTripInfoManager", "type: "+ type + +", lineName: "+ lineName +", departureStopName: "+ departureStopName + + ", arrivalStopName: "+arrivalStopName+", isLastStop: "+isLastStop) + CallerAutoPilotControlManager.sendTripInfo(type,lineName,departureStopName, arrivalStopName, isLastStop) + } +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/util/BusTrajectoryManager.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/util/BusTrajectoryManager.java new file mode 100644 index 0000000000..4370689618 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/util/BusTrajectoryManager.java @@ -0,0 +1,204 @@ +package com.mogo.och.offline.util; + +import androidx.annotation.Nullable; + +import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager; +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; +import com.mogo.eagle.core.utilcode.util.GsonUtils; +import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager; +import com.mogo.och.data.bean.BusRoutesResult; +import com.mogo.och.offline.constant.BusConst; +import com.mogo.och.offline.model.OrderModel; +import com.mogo.och.common.module.biz.login.LoginStatusManager; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import mogo_msg.MogoReportMsg; + +import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS; + +/** + * Bus轨迹管理:给MEC下发用于轨迹下载的信息 + * Created on 2022/6/23 + */ +public class BusTrajectoryManager { + private static final String TAG = BusTrajectoryManager.class.getSimpleName(); + + private static final class SingletonHolder { + private static final BusTrajectoryManager INSTANCE = new BusTrajectoryManager(); + } + + public static BusTrajectoryManager getInstance() { + return BusTrajectoryManager.SingletonHolder.INSTANCE; + } + + private AutopilotControlParameters.AutoPilotLine mAutoPilotLine = null; + private Disposable mSendReqDisposable = null; + + public BusTrajectoryManager() { + mAutoPilotLine = new AutopilotControlParameters.AutoPilotLine(-1, "", + "", "", "", "", 0, "", + "", "", "", "", 0); + } + + /** + * 同步Bus路线信息 + */ + public void syncTrajectoryInfo() { + BusRoutesResult routesResult = OrderModel.getInstance().getBusRoutesResult(); + if (LoginStatusManager.isLogin() && routesResult != null + && OrderModel.getInstance().getCurrentStationIndex() == 0 + && !OrderModel.getInstance().isGoingToNextStation()) { + CallerLogger.d(M_BUS + TAG, "syncTrajectoryInfo() start."); + startTrajReqLoop(); + } else { + // 无路线信息or当前未在始发站 + CallerLogger.d(M_BUS + TAG, "syncTrajectoryInfo() stop."); + stopTrajReqLoop(); + } + } + + public void onAutopilotGuardian(@Nullable MogoReportMsg.MogoReportMessage guardianInfo,long lineId) { + onAutopilotGuardian(guardianInfo); + } + + /** + * 接口MEC反馈的常规信息(MAP v2.5.0新增轨迹相关信息) + * @param guardianInfo + */ + public void onAutopilotGuardian(@Nullable MogoReportMsg.MogoReportMessage guardianInfo) { + if (guardianInfo == null || !guardianInfo.hasCode()) return; + if ("ISYS_INIT_TRAJECTORY_START".equals(guardianInfo.getCode())) { + // 1. 轨迹管理_轨迹开始下载(本地已有对应轨迹也触发) + CallerLogger.d(M_BUS + TAG, "onAutopilotGuardian() 轨迹开始下载"); + OchChainLogManager.writeChainLog("轨迹监控","onAutopilotGuardian() 轨迹开始下载", true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY); + // ToastUtils.showShort("轨迹开始下载"); + stopTrajReqLoop(); + } else if ("ISYS_INIT_TRAJECTORY_SUCCESS".equals(guardianInfo.getCode())) { + // 2. 轨迹管理_轨迹下载成功(本地已有对应轨迹也触发) + CallerLogger.d(M_BUS + TAG, "onAutopilotGuardian() 轨迹下载成功"); + OchChainLogManager.writeChainLog("轨迹监控","onAutopilotGuardian() 轨迹下载成功", true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY); + // ToastUtils.showShort("轨迹下载成功"); + stopTrajReqLoop(); + } else if ("ISYS_INIT_TRAJECTORY_FAILURE".equals(guardianInfo.getCode())) { + // 3. 轨迹管理_轨迹下载失败,本地无对应轨迹 + CallerLogger.d(M_BUS + TAG, "onAutopilotGuardian() " + + "轨迹下载失败,本地无对应轨迹"); + OchChainLogManager.writeChainLog("轨迹监控","onAutopilotGuardian() 轨迹下载失败,本地无对应轨迹", true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY); + // ToastUtils.showShort("轨迹下载失败,本地无对应轨迹"); + } else if ("ISYS_INIT_TRAJECTORY_WARNING".equals(guardianInfo.getCode())) { + // 4. 轨迹管理_轨迹下载失败,本地有对应轨迹,认为成功 + CallerLogger.d(M_BUS + TAG, "onAutopilotGuardian() " + + "轨迹下载失败,本地有对应轨迹,认为成功"); + OchChainLogManager.writeChainLog("轨迹监控","onAutopilotGuardian() 轨迹下载失败,本地有对应轨迹,认为成功", true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY); + // ToastUtils.showShort("轨迹下载失败,本地有对应轨迹,认为成功"); + } else if ("ISYS_INIT_TRAJECTORY_TIMEOUT".equals(guardianInfo.getCode())) { + // 5. 轨迹管理_轨迹下载超时 + CallerLogger.d(M_BUS + TAG, "onAutopilotGuardian() 轨迹下载超时"); + OchChainLogManager.writeChainLog("轨迹监控","onAutopilotGuardian() 轨迹下载超时", true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY); + // ToastUtils.showShort("轨迹下载超时"); + } else if ("ISSM_FUNC_AUTO_PILOT_READY".equals(guardianInfo.getCode())) { + // 收到ssm的自动驾驶变为ready,再次下发轨迹下载.解决:域控重启,或者102域控启动太早,107节点初始化未完成导致的轨迹未进行下载。 + CallerLogger.d(M_BUS + TAG, "onAutopilotGuardian() ssm ready,再次发起下载"); + OchChainLogManager.writeChainLog("轨迹监控","onAutopilotGuardian() 再次发起下载", true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY); + syncTrajectoryInfo(); + } + } + + private void setupAutoPilotLine() { + BusRoutesResult routesResult = OrderModel.getInstance().getBusRoutesResult(); + if (routesResult == null) { + CallerLogger.e(M_BUS + TAG, + "setupAutoPilotLine(): routesResult is null."); + return; + } else { + if (mAutoPilotLine == null) { + mAutoPilotLine = new AutopilotControlParameters.AutoPilotLine( + routesResult.getLineId(), routesResult.getName(), + routesResult.csvFileUrl, routesResult.csvFileMd5, + routesResult.txtFileUrl, routesResult.txtFileMd5, + routesResult.contrailSaveTime, routesResult.carModel, + routesResult.csvFileUrlDPQP, routesResult.csvFileMd5DPQP, + routesResult.txtFileUrlDPQP, routesResult.txtFileMd5DPQP, + routesResult.contrailSaveTimeDPQP); + } else { + mAutoPilotLine.setLineId(routesResult.getLineId()); + mAutoPilotLine.setLineName(routesResult.getName()); + mAutoPilotLine.setTrajUrl(routesResult.csvFileUrl); + mAutoPilotLine.setTrajMd5(routesResult.csvFileMd5); + mAutoPilotLine.setStopUrl(routesResult.txtFileUrl); + mAutoPilotLine.setStopMd5(routesResult.txtFileMd5); + mAutoPilotLine.setTimestamp(routesResult.contrailSaveTime); + mAutoPilotLine.setVehicleModel(routesResult.carModel); + mAutoPilotLine.setTrajUrl_dpqp(routesResult.csvFileUrlDPQP); + mAutoPilotLine.setTrajMd5_dpqp(routesResult.csvFileMd5DPQP); + mAutoPilotLine.setStopUrl_dpqp(routesResult.txtFileUrlDPQP); + mAutoPilotLine.setStopMd5_dpqp(routesResult.txtFileMd5DPQP); + mAutoPilotLine.setTimestamp_dpqp(routesResult.contrailSaveTimeDPQP); + } + } + } + + private void clearAutoPilotLine() { + if (mAutoPilotLine == null) return; + mAutoPilotLine.setLineId(-1); + mAutoPilotLine.setLineName(""); + mAutoPilotLine.setTrajUrl(""); + mAutoPilotLine.setTrajMd5(""); + mAutoPilotLine.setStopUrl(""); + mAutoPilotLine.setStopMd5(""); + mAutoPilotLine.setTimestamp(0); + mAutoPilotLine.setVehicleModel(""); + mAutoPilotLine.setTrajUrl_dpqp(""); + mAutoPilotLine.setTrajMd5_dpqp(""); + mAutoPilotLine.setStopUrl_dpqp(""); + mAutoPilotLine.setStopMd5_dpqp(""); + mAutoPilotLine.setTimestamp_dpqp(0); + } + + private void startTrajReqLoop() { + if (mSendReqDisposable != null && !mSendReqDisposable.isDisposed()) { + return; + } + CallerLogger.d(M_BUS + TAG, "startTrajReqLoop()"); + setupAutoPilotLine(); + mSendReqDisposable = Observable.interval(BusConst.LOOP_DELAY, + BusConst.LOOP_PERIOD_10S, TimeUnit.MILLISECONDS) + .map((aLong -> aLong + 1)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(aLong -> { + if (aLong > BusConst.LOOP_SEND_TRAJ_TIMES) { + stopTrajReqLoop(); + return; + } + CallerLogger.d(M_BUS + TAG, "loop sendTrajectoryReq: " + aLong); + sendTrajectoryReq(); + }); + } + + public void stopTrajReqLoop() { + if (mSendReqDisposable != null) { + CallerLogger.d(M_BUS + TAG, "stopTrajReqLoop()"); + mSendReqDisposable.dispose(); + mSendReqDisposable = null; + clearAutoPilotLine(); + } + } + + private void sendTrajectoryReq() { + if (mAutoPilotLine == null) { + CallerLogger.e(M_BUS + TAG, "sendTrajectoryReq(): mAutoPilotLine is null!!!"); + return; + } + OchChainLogManager.writeChainLog("轨迹监控","sendTrajectoryReq() 下发轨迹 轨迹id"+mAutoPilotLine.getLineId(), true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY); + CallerAutoPilotControlManager.INSTANCE.sendTrajectoryDownloadReq(mAutoPilotLine); + CallerLogger.d(M_BUS + TAG, "sendTrajectoryReq(): " + + GsonUtils.toJson(mAutoPilotLine)); + } +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/util/ShuttleVoiceManager.kt b/OCH/offline/driver/src/main/java/com/mogo/och/offline/util/ShuttleVoiceManager.kt new file mode 100644 index 0000000000..fafac81b18 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/util/ShuttleVoiceManager.kt @@ -0,0 +1,93 @@ +package com.mogo.och.offline.util + +import com.mogo.commons.AbsMogoApplication +import com.mogo.commons.voice.AIAssist +import com.mogo.eagle.core.data.config.FunctionBuildConfig +import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils +import com.mogo.och.common.module.voice.VoiceNotice +import com.mogo.och.offline.R +import com.mogo.tts.base.LangTtsEntity +import com.mogo.tts.base.LanguageType +import java.util.ArrayList + +object ShuttleVoiceManager { + + fun arrivedStationBus(siteNameCN: String?, siteNameKR: String?) { + val context = AbsMogoApplication.getApp() + val list: MutableList = ArrayList() + siteNameCN?.let { + val chineseTTS = LangTtsEntity( + context.getString(R.string.bus_arrived_station_tip, it), + LanguageType.CHINESE + ) + val engTTS = LangTtsEntity( + context.getString(R.string.bus_arrived_station_english_tip, it), + LanguageType.CHINESE + ) + val koreanTTS = LangTtsEntity( + context.getString(R.string.bus_arrived_station_korean_tip, siteNameKR?:it), + LanguageType.KOREAN + ) + list.add(chineseTTS) + list.add(engTTS) + list.add(koreanTTS) + } + + VoiceNotice.showNotice(list, AIAssist.LEVEL1,null) + } + + fun leaveStationBus(siteNameCN: String?, siteNameKR: String?) { + val list: MutableList = ArrayList() + val context = AbsMogoApplication.getApp() + siteNameCN?.let { + val chineseTTS = LangTtsEntity( + context.getString(R.string.bus_leave_station_tip, it), + LanguageType.CHINESE + ) + val engTTS = LangTtsEntity( + context.getString(R.string.bus_leave_station_english_tip, it), + LanguageType.CHINESE + ) + list.add(chineseTTS) + list.add(engTTS) + + val koreanTTS = LangTtsEntity( + context.getString(R.string.bus_leave_station_korean_tip, siteNameKR ?: it), + LanguageType.KOREAN + ) + list.add(koreanTTS) + } + VoiceNotice.showNotice(list, AIAssist.LEVEL1,null) + } + + fun endOrderBus() { + val context = AbsMogoApplication.getApp() + val list: MutableList = ArrayList() + val chineseTTS = LangTtsEntity(context.getString(R.string.bus_end_task_tip), LanguageType.CHINESE) + val engTTS = LangTtsEntity(context.getString(R.string.bus_end_task_english_tip), LanguageType.ENGLISH) + val koreanTTS = LangTtsEntity(context.getString(R.string.bus_end_task_korean_tip), LanguageType.KOREAN) + list.add(chineseTTS) + list.add(engTTS) + list.add(koreanTTS) + VoiceNotice.showNotice(list, AIAssist.LEVEL0,null) + } + + fun writeOffCount(successNum:Int){ + if(successNum<=1){ + VoiceNotice.showNotice("核验通过", AIAssist.LEVEL3); + }else{ + VoiceNotice.showNotice("$successNum 人核验通过", AIAssist.LEVEL3) + } + } + + // 距离发车还有1分钟 + fun showLeafTime(tips: String) { + //语音提示 + VoiceNotice.showNotice(tips) + } + + fun writeOffFaile(reaseon:String) { + VoiceNotice.showNotice("验票失败,${reaseon}", AIAssist.LEVEL3) + } + +} \ No newline at end of file diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/view/BizMapView.kt b/OCH/offline/driver/src/main/java/com/mogo/och/offline/view/BizMapView.kt new file mode 100644 index 0000000000..aaaa2035a2 --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/view/BizMapView.kt @@ -0,0 +1,63 @@ +package com.mogo.och.offline.view + +import android.content.Context +import android.os.Bundle +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.FrameLayout +import com.mogo.eagle.core.data.config.FunctionBuildConfig +import com.mogo.eagle.core.function.view.MapBizView +import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils +import com.mogo.map.uicontroller.IMogoMapUIController +import com.mogo.och.offline.R + +/** + * 魔戒蓝牙控件 + * 放置于StatusBar右侧位置 + */ +class BizMapView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + private lateinit var mapBizView: MapBizView + + init { + if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) { + LayoutInflater.from(context).inflate(R.layout.offline_m2_bizmap_map, this, true) + }else if(AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode)){ + LayoutInflater.from(context).inflate(R.layout.offline_jl_bizmap_map, this, true) + }else{ + LayoutInflater.from(context).inflate(R.layout.offline_jl_bizmap_map, this, true) + } + mapBizView = findViewById(R.id.bizMapView) + } + + fun getUI(): IMogoMapUIController? { + return mapBizView.getUI() + } + + fun onCreate(bundle: Bundle?) { + mapBizView.onCreate(bundle) + } + fun onResume() { + mapBizView.onResume() + } + + fun onSaveInstanceState(outState: Bundle){ + mapBizView.onSaveInstanceState(outState) + } + + fun onLowMemory() { + mapBizView.onLowMemory() + } + + fun onPause() { + mapBizView.onPause() + } + + fun onDestroy() { + mapBizView.onDestroy() + } +} \ No newline at end of file diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/view/SlidePanelView.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/view/SlidePanelView.java new file mode 100644 index 0000000000..d204fcd0ad --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/view/SlidePanelView.java @@ -0,0 +1,300 @@ +package com.mogo.och.offline.view; + +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.DecelerateInterpolator; + +import androidx.annotation.Nullable; + +import com.mogo.commons.AbsMogoApplication; +import com.mogo.eagle.core.utilcode.util.ConvertUtils; +import com.mogo.eagle.core.utilcode.util.ThreadUtils; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; +import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager; +import com.mogo.och.offline.R; + +import me.jessyan.autosize.AutoSizeConfig; +import me.jessyan.autosize.utils.AutoSizeUtils; + +/** + * 滑块滑动面板 + * + * @author tongchenfei + */ +public class SlidePanelView extends View { + private static final String TAG = "SlidePanelView"; + + public SlidePanelView(Context context) { + this(context, null); + } + + public SlidePanelView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public SlidePanelView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.SlidePanelView); + textSize = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_textSize, textSize); + BLOCK_START_X = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_BLOCK_START_X, BLOCK_START_X); + BLOCK_START_Y = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_BLOCK_START_Y, BLOCK_START_Y); + NORMAL_TEXT_MARGIN_LEFT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_NORMAL_TEXT_MARGIN_LEFT, NORMAL_TEXT_MARGIN_LEFT); + NORMAL_TEXT_MARGIN_RIGHT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_NORMAL_TEXT_MARGIN_RIGHT, NORMAL_TEXT_MARGIN_RIGHT); + SHORT_TEXT_MARGIN_LEFT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_SHORT_TEXT_MARGIN_LEFT, SHORT_TEXT_MARGIN_LEFT); + SHORT_TEXT_MARGIN_RIGHT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_SHORT_TEXT_MARGIN_RIGHT, SHORT_TEXT_MARGIN_RIGHT); + init(); + } + + private final Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint blockPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private static int textSize = 40; + private static int BLOCK_START_X = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),15); + private static int BLOCK_START_Y = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),15); + private static int NORMAL_TEXT_MARGIN_LEFT = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),40); + private static int NORMAL_TEXT_MARGIN_RIGHT = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),60); + private static int SHORT_TEXT_MARGIN_LEFT = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),60);; + private static int SHORT_TEXT_MARGIN_RIGHT = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),70);; + + private int textMarginLeft = NORMAL_TEXT_MARGIN_LEFT; + private int textMarginRight = NORMAL_TEXT_MARGIN_RIGHT; + + private OnSlidePanelMoveToEndListener moveToEndListener; + + private int blockWidth = 0; + private int blockOffset = 0; + + private float lastX; + private boolean isToEnd = false; + + private static final String STRING_SLIDE_TO_RIGHT = "向右滑动"; + private RectF bgRectF; + private Bitmap bmBlock; + + private final Matrix gradientMatrix = new Matrix(); + private float matrixTranslate; + private final Rect textRect = new Rect(); + private LinearGradient textGradient; + + private ObjectAnimator matrixAnim; + + private String blockText = STRING_SLIDE_TO_RIGHT; + private final Paint.FontMetrics blockTextMetrics = new Paint.FontMetrics(); + + private static final int GRADIENT_OFFSET = 200; + + public void setOnSlidePanelMoveToEndListener(OnSlidePanelMoveToEndListener moveToEndListener) { + this.moveToEndListener = moveToEndListener; + } + + private void setBlockOffset(int blockOffset) { + this.blockOffset = blockOffset; + invalidate(); + } + + private void setMatrixTranslate(float matrixTranslate) { + this.matrixTranslate = matrixTranslate; + invalidate(); + } + + public void setText(String text) { + this.blockText = text; + requestLayout(); + invalidate(); + } + + private void init() { + bgRectF = new RectF(0, 0, 0, 0); + bgPaint.setColor(Color.parseColor("#CC0F1325")); + bgPaint.setStyle(Paint.Style.FILL); + + textPaint.setStyle(Paint.Style.FILL); + textPaint.setTextSize(textSize); + textPaint.setTextAlign(Paint.Align.LEFT); + textGradient = new LinearGradient(-GRADIENT_OFFSET, 0, 0, 0, new int[]{0x33ffffff, 0xffffffff, 0x33ffffff}, null, Shader.TileMode.CLAMP); + textGradient.setLocalMatrix(gradientMatrix); + textPaint.setShader(textGradient); + textPaint.getFontMetrics(blockTextMetrics); + decodeImage(); + } + + private void decodeImage(){ + ThreadUtils.getCpuPool().execute(() -> { + int size = AutoSizeUtils.dp2px(getContext(), 120); + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inDensity = (int) AutoSizeConfig.getInstance().getInitDensity(); + bmBlock = BitmapFactory.decodeResource(getResources(), R.drawable.bus_base_slide_block,opts); + bmBlock = Bitmap.createScaledBitmap(bmBlock, size, size, true); + blockWidth = bmBlock.getWidth(); + UiThreadHandler.post(this::requestLayout,UiThreadHandler.MODE.QUEUE); + }); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int widthSize; + int heightSize; + + if (blockText.length() < 5) { + textMarginLeft = SHORT_TEXT_MARGIN_LEFT; + textMarginRight = SHORT_TEXT_MARGIN_RIGHT; + } else { + textMarginLeft = NORMAL_TEXT_MARGIN_LEFT; + textMarginRight = NORMAL_TEXT_MARGIN_RIGHT; + } + if(bmBlock!=null) { + if (widthMode == MeasureSpec.AT_MOST) { + // 宽度根据图片大小,字符串长度,各种间隔确定 + // 高度根据图片大小和上下间隔确定 + textPaint.getTextBounds(blockText, 0, blockText.length(), textRect); + widthSize = BLOCK_START_X * 2 + bmBlock.getWidth() + textMarginLeft + textMarginRight + textRect.width(); + heightSize = BLOCK_START_Y * 2 + bmBlock.getHeight(); + widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); + heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode); + } + } + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + private float textOffset = 0; + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (bgRectF != null){ + bgRectF.left = 0; + bgRectF.top = 0; + bgRectF.right = w; + bgRectF.bottom = h; + } + + if (matrixAnim != null) { + matrixAnim.cancel(); + } + textOffset = (getHeight() - blockTextMetrics.ascent - blockTextMetrics.descent) / 2; + matrixAnim = ObjectAnimator.ofFloat(this, "matrixTranslate", 0, w + GRADIENT_OFFSET).setDuration(2000); + matrixAnim.setRepeatCount(ValueAnimator.INFINITE); + matrixAnim.start(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (matrixAnim != null) { + matrixAnim.start(); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (matrixAnim != null) { + matrixAnim.cancel(); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + float y = event.getY(); + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + if (x > BLOCK_START_X + blockOffset && x < blockWidth + BLOCK_START_X + blockOffset && y > BLOCK_START_Y && y < getHeight() - BLOCK_START_Y) { + isToEnd = false; + lastX = x; + } + break; + case MotionEvent.ACTION_MOVE: + if (lastX != 0) { + blockOffset = (int) (x - lastX); + if (blockOffset < 0) { + blockOffset = 0; + } + if (blockOffset + BLOCK_START_X + blockWidth > getWidth()) { + // 超出右边界 + blockOffset = getWidth() - BLOCK_START_X - blockWidth; + if (!isToEnd) { + isToEnd = true; + if (moveToEndListener != null) { + moveToEndListener.moveToEnd(); + } + startBlockBackAnim(); + } + } + invalidate(); + } + break; + case MotionEvent.ACTION_UP: + // 执行滑块回归动画 + if (!isToEnd) { + startBlockBackAnim(); + } + break; + default: + break; + } + + return true; + } + + private void startBlockBackAnim() { + ObjectAnimator blockBackanimator = ObjectAnimator.ofInt(this, "blockOffset", blockOffset, 0); + blockBackanimator.setInterpolator(new DecelerateInterpolator()); + blockBackanimator.setDuration(1000 * blockOffset / getWidth()); + blockBackanimator.start(); + lastX = 0; + } + + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + // 画背景 + canvas.drawRoundRect(bgRectF, (float) getHeight() / 2.0f, (float) getHeight() / 2.0f, bgPaint); + // 画文字 + gradientMatrix.setTranslate(matrixTranslate, 0); + textGradient.setLocalMatrix(gradientMatrix); + canvas.save(); + canvas.drawText(blockText, (float) (blockWidth + BLOCK_START_X + textMarginLeft), (float) textOffset, textPaint); + canvas.restore(); + if (bmBlock != null) { + if(bmBlock.getByteCount()>=5*1024*1024){ + OchChainLogManager.writeChainLog("崩溃兜底策略", + "图片大小监听"+ ConvertUtils.byte2FitMemorySize(bmBlock.getByteCount()),true,OchChainLogManager.EVENT_KEY_INFE_ERROR); + bmBlock.recycle(); + bmBlock = null; + blockWidth = 0; + decodeImage(); + }else { + // 画滑块 + canvas.drawBitmap(bmBlock, (float) (BLOCK_START_X + blockOffset), (float) BLOCK_START_Y, blockPaint); + } + } + + } + + public interface OnSlidePanelMoveToEndListener { + /** + * 滑块滑到了末尾 + */ + void moveToEnd(); + } +} diff --git a/OCH/offline/driver/src/main/java/com/mogo/och/offline/view/VerticalDashLineView.java b/OCH/offline/driver/src/main/java/com/mogo/och/offline/view/VerticalDashLineView.java new file mode 100644 index 0000000000..4ab48e3cda --- /dev/null +++ b/OCH/offline/driver/src/main/java/com/mogo/och/offline/view/VerticalDashLineView.java @@ -0,0 +1,64 @@ +package com.mogo.och.offline.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.DashPathEffect; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Shader; +import android.util.AttributeSet; +import android.view.View; + +import androidx.annotation.Nullable; + +/** + * 垂直虚线 + * + * @author tongchenfei + */ +public class VerticalDashLineView extends View { + public VerticalDashLineView(Context context) { + this(context,null); + } + + public VerticalDashLineView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs,0); + } + + public VerticalDashLineView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private final Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Path dashPath = new Path(); + + private void init(){ + linePaint.setColor(Color.GREEN); + linePaint.setStyle(Paint.Style.STROKE); + linePaint.setStrokeWidth(2); + linePaint.setPathEffect(new DashPathEffect(new float[]{5, 5}, 0)); + } + + public void setGradient(int startColor, int endColor) { + LinearGradient linearGradient = new LinearGradient(0, 0, getWidth(), getHeight(), startColor, endColor, Shader.TileMode.CLAMP); + linePaint.setShader(linearGradient); + invalidate(); + } + + public void setColor(int color) { + linePaint.setShader(null); + linePaint.setColor(color); + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + dashPath.reset(); + dashPath.moveTo((float) getWidth()/2, 0); + dashPath.lineTo((float) getWidth()/2,getHeight()); + canvas.drawPath(dashPath,linePaint); + } +} diff --git a/OCH/offline/driver/src/main/res/color/bus_autopilot_text_color_selector.xml b/OCH/offline/driver/src/main/res/color/bus_autopilot_text_color_selector.xml new file mode 100644 index 0000000000..15f6897792 --- /dev/null +++ b/OCH/offline/driver/src/main/res/color/bus_autopilot_text_color_selector.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_base_icon_in_autopilot.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_base_icon_in_autopilot.png new file mode 100644 index 0000000000..75c26c3d71 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_base_icon_in_autopilot.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_base_icon_not_in_autopilot.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_base_icon_not_in_autopilot.png new file mode 100644 index 0000000000..927296d690 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_base_icon_not_in_autopilot.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_base_slide_block.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_base_slide_block.png new file mode 100644 index 0000000000..ed7b293b90 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_base_slide_block.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_disable_autopilot_icon.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_disable_autopilot_icon.png new file mode 100644 index 0000000000..170f254cd1 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_disable_autopilot_icon.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_dot_line.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_dot_line.png new file mode 100644 index 0000000000..186001352c Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_dot_line.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_ic_autopilot.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_ic_autopilot.png new file mode 100644 index 0000000000..be978145dc Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_ic_autopilot.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_icon_arrived_station.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_icon_arrived_station.png new file mode 100644 index 0000000000..8a065b66dd Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_icon_arrived_station.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_icon_arriving_station.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_icon_arriving_station.png new file mode 100644 index 0000000000..4ed57a0e30 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_icon_arriving_station.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_icon_not_arrive_station.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_icon_not_arrive_station.png new file mode 100644 index 0000000000..e0bb24c526 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_icon_not_arrive_station.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_light_green_nor.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_light_green_nor.png new file mode 100644 index 0000000000..bc9fed952d Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_light_green_nor.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_light_red_nor.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_light_red_nor.png new file mode 100644 index 0000000000..8732508ded Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_light_red_nor.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_lightyellow_nor.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_lightyellow_nor.png new file mode 100644 index 0000000000..bae01408fd Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_lightyellow_nor.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_line_panel_bg.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_line_panel_bg.png new file mode 100755 index 0000000000..3166d20e37 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_line_panel_bg.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_line_panel_bg_1.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_line_panel_bg_1.png new file mode 100755 index 0000000000..09a9c252da Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_line_panel_bg_1.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_line_task_arrow.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_line_task_arrow.png new file mode 100644 index 0000000000..b32f0693a6 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_line_task_arrow.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_loading_autopilot_icon.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_loading_autopilot_icon.png new file mode 100644 index 0000000000..f21a1081f1 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_loading_autopilot_icon.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_no_line_icon.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_no_line_icon.png new file mode 100755 index 0000000000..fc20dca73c Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_no_line_icon.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_och_dot_line.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_och_dot_line.png new file mode 100644 index 0000000000..a720a532ea Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_och_dot_line.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_operation_status_bg.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_operation_status_bg.png new file mode 100644 index 0000000000..3c339efde4 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_operation_status_bg.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_operation_status_select_bg.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_operation_status_select_bg.png new file mode 100644 index 0000000000..c6717d2518 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_operation_status_select_bg.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_right_autopilot_icon.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_right_autopilot_icon.png new file mode 100644 index 0000000000..cc2b18083d Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_right_autopilot_icon.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_selected_btn.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_selected_btn.png new file mode 100644 index 0000000000..3f05565483 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_selected_btn.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_setting_btn_bg.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_setting_btn_bg.png new file mode 100644 index 0000000000..ba41bf3a53 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_setting_btn_bg.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_switch_line_close.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_switch_line_close.png new file mode 100644 index 0000000000..370b61de38 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_switch_line_close.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_switch_map_long.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_switch_map_long.png new file mode 100755 index 0000000000..cf3e5a3778 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_switch_map_long.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_switch_map_medium.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_switch_map_medium.png new file mode 100755 index 0000000000..bdc2725468 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_switch_map_medium.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_unselect_btn.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_unselect_btn.png new file mode 100644 index 0000000000..0114bb4f2b Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_unselect_btn.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/bus_wrong_autopilot_icon.png b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_wrong_autopilot_icon.png new file mode 100644 index 0000000000..0c8988acb3 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/bus_wrong_autopilot_icon.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/end_maker_icon.png b/OCH/offline/driver/src/main/res/drawable-nodpi/end_maker_icon.png new file mode 100755 index 0000000000..8acf113151 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/end_maker_icon.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_ai_collect.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_ai_collect.png new file mode 100755 index 0000000000..6da7b81fe4 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_ai_collect.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_ai_normal.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_ai_normal.png new file mode 100755 index 0000000000..e98738b192 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_ai_normal.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_ai_select.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_ai_select.png new file mode 100755 index 0000000000..d3e0107c02 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_ai_select.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_arrow_blue_bus.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_arrow_blue_bus.png new file mode 100755 index 0000000000..026c36086f Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_arrow_blue_bus.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_arrow_green_bus.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_arrow_green_bus.png new file mode 100755 index 0000000000..06bebc7013 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_arrow_green_bus.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_arrow_grey_bus.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_arrow_grey_bus.png new file mode 100755 index 0000000000..f4f9b2bca2 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_arrow_grey_bus.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_bad_case.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_bad_case.png new file mode 100755 index 0000000000..22f88301f9 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_bad_case.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_bad_case_normal.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_bad_case_normal.png new file mode 100755 index 0000000000..c0a978fc2b Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_bad_case_normal.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_bad_case_select.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_bad_case_select.png new file mode 100755 index 0000000000..ebacf3a11a Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_bad_case_select.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_no_bus_line.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_no_bus_line.png new file mode 100755 index 0000000000..fc20dca73c Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_no_bus_line.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_point_blue_bus.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_point_blue_bus.png new file mode 100755 index 0000000000..dc4c4f6f0d Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_point_blue_bus.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_point_green_bus.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_point_green_bus.png new file mode 100755 index 0000000000..ed3b871338 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_point_green_bus.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_point_grey_bus.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_point_grey_bus.png new file mode 100755 index 0000000000..d43e34bb26 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_point_grey_bus.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/icon_station_start_end.png b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_station_start_end.png new file mode 100644 index 0000000000..04580a8f0d Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/icon_station_start_end.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/no_order_data.png b/OCH/offline/driver/src/main/res/drawable-nodpi/no_order_data.png new file mode 100644 index 0000000000..0e61996d3f Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/no_order_data.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/pingxingjiashi.png b/OCH/offline/driver/src/main/res/drawable-nodpi/pingxingjiashi.png new file mode 100644 index 0000000000..78bfa2687f Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/pingxingjiashi.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/press_start_status.png b/OCH/offline/driver/src/main/res/drawable-nodpi/press_start_status.png new file mode 100755 index 0000000000..af32c20cb5 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/press_start_status.png differ diff --git a/OCH/offline/driver/src/main/res/drawable-nodpi/shuttle_write_off_bg.png b/OCH/offline/driver/src/main/res/drawable-nodpi/shuttle_write_off_bg.png new file mode 100755 index 0000000000..de9b6c49b7 Binary files /dev/null and b/OCH/offline/driver/src/main/res/drawable-nodpi/shuttle_write_off_bg.png differ diff --git a/OCH/offline/driver/src/main/res/drawable/ai_collect_selector.xml b/OCH/offline/driver/src/main/res/drawable/ai_collect_selector.xml new file mode 100755 index 0000000000..a1211f3c47 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/ai_collect_selector.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bad_case_selector.xml b/OCH/offline/driver/src/main/res/drawable/bad_case_selector.xml new file mode 100755 index 0000000000..bc47ce95d7 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bad_case_selector.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bg_bus_traffic_light_background.xml b/OCH/offline/driver/src/main/res/drawable/bg_bus_traffic_light_background.xml new file mode 100644 index 0000000000..e0b90b9c55 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bg_bus_traffic_light_background.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_autopilot_0_1_status_bg.xml b/OCH/offline/driver/src/main/res/drawable/bus_autopilot_0_1_status_bg.xml new file mode 100644 index 0000000000..47ca8c7d4b --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_autopilot_0_1_status_bg.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/OCH/offline/driver/src/main/res/drawable/bus_base_autopilot_status_icon_selector.xml b/OCH/offline/driver/src/main/res/drawable/bus_base_autopilot_status_icon_selector.xml new file mode 100644 index 0000000000..94555d78cc --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_base_autopilot_status_icon_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_checkbox_selector.xml b/OCH/offline/driver/src/main/res/drawable/bus_checkbox_selector.xml new file mode 100644 index 0000000000..d95e931160 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_checkbox_selector.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_line_dividing_line1_selector.xml b/OCH/offline/driver/src/main/res/drawable/bus_line_dividing_line1_selector.xml new file mode 100644 index 0000000000..b00fbd8bd6 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_line_dividing_line1_selector.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_line_dividing_line2_selector.xml b/OCH/offline/driver/src/main/res/drawable/bus_line_dividing_line2_selector.xml new file mode 100644 index 0000000000..ee555aae15 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_line_dividing_line2_selector.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_operation_status_bg_selector.xml b/OCH/offline/driver/src/main/res/drawable/bus_operation_status_bg_selector.xml new file mode 100755 index 0000000000..3a3dc6a292 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_operation_status_bg_selector.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_panel_anchor_bkg.xml b/OCH/offline/driver/src/main/res/drawable/bus_panel_anchor_bkg.xml new file mode 100644 index 0000000000..21b39b7e37 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_panel_anchor_bkg.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_panel_bkg.xml b/OCH/offline/driver/src/main/res/drawable/bus_panel_bkg.xml new file mode 100644 index 0000000000..69539ed40f --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_panel_bkg.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_setting_tip_red_cir_bg.xml b/OCH/offline/driver/src/main/res/drawable/bus_setting_tip_red_cir_bg.xml new file mode 100644 index 0000000000..203971340e --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_setting_tip_red_cir_bg.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_shape_select_line_item_bg_normal.xml b/OCH/offline/driver/src/main/res/drawable/bus_shape_select_line_item_bg_normal.xml new file mode 100644 index 0000000000..e5faafb27b --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_shape_select_line_item_bg_normal.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_shape_select_line_item_bg_selected.xml b/OCH/offline/driver/src/main/res/drawable/bus_shape_select_line_item_bg_selected.xml new file mode 100644 index 0000000000..e5faafb27b --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_shape_select_line_item_bg_selected.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_shape_select_line_item_time_bg.xml b/OCH/offline/driver/src/main/res/drawable/bus_shape_select_line_item_time_bg.xml new file mode 100644 index 0000000000..ee8088637c --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_shape_select_line_item_time_bg.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_shape_select_line_item_time_bg_selected.xml b/OCH/offline/driver/src/main/res/drawable/bus_shape_select_line_item_time_bg_selected.xml new file mode 100644 index 0000000000..e2b482ee5f --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_shape_select_line_item_time_bg_selected.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_station_green_dash_line.xml b/OCH/offline/driver/src/main/res/drawable/bus_station_green_dash_line.xml new file mode 100644 index 0000000000..fe46ef2228 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_station_green_dash_line.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_station_v_green_dash.xml b/OCH/offline/driver/src/main/res/drawable/bus_station_v_green_dash.xml new file mode 100644 index 0000000000..376e0a472c --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_station_v_green_dash.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_switch_line_btn.xml b/OCH/offline/driver/src/main/res/drawable/bus_switch_line_btn.xml new file mode 100644 index 0000000000..8b066b0ce8 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_switch_line_btn.xml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_switch_line_btn_commit.xml b/OCH/offline/driver/src/main/res/drawable/bus_switch_line_btn_commit.xml new file mode 100644 index 0000000000..e94992d507 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_switch_line_btn_commit.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_switch_map_bg.xml b/OCH/offline/driver/src/main/res/drawable/bus_switch_map_bg.xml new file mode 100644 index 0000000000..b34021d977 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_switch_map_bg.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_task_time_bg.xml b/OCH/offline/driver/src/main/res/drawable/bus_task_time_bg.xml new file mode 100644 index 0000000000..917f3932fe --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_task_time_bg.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_yi_biao_pan_bg_nor.xml b/OCH/offline/driver/src/main/res/drawable/bus_yi_biao_pan_bg_nor.xml new file mode 100644 index 0000000000..2ef90e60f7 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_yi_biao_pan_bg_nor.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/drawable/bus_yi_biao_pan_bg_speeding.xml b/OCH/offline/driver/src/main/res/drawable/bus_yi_biao_pan_bg_speeding.xml new file mode 100644 index 0000000000..dea7a88bb6 --- /dev/null +++ b/OCH/offline/driver/src/main/res/drawable/bus_yi_biao_pan_bg_speeding.xml @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file diff --git a/OCH/offline/driver/src/main/res/layout/offline_base_fragment.xml b/OCH/offline/driver/src/main/res/layout/offline_base_fragment.xml new file mode 100644 index 0000000000..7569f3ee91 --- /dev/null +++ b/OCH/offline/driver/src/main/res/layout/offline_base_fragment.xml @@ -0,0 +1,364 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +