diff --git a/OCH/mogo-och-bus-passenger/src/jinlvvan/java/com/mogo/och/bus/passenger/MogoOCHBusPassenger.java b/OCH/mogo-och-bus-passenger/src/jinlvvan/java/com/mogo/och/bus/passenger/MogoOCHBusPassenger.java index c931b96c5b..d90ec06928 100644 --- a/OCH/mogo-och-bus-passenger/src/jinlvvan/java/com/mogo/och/bus/passenger/MogoOCHBusPassenger.java +++ b/OCH/mogo-och-bus-passenger/src/jinlvvan/java/com/mogo/och/bus/passenger/MogoOCHBusPassenger.java @@ -45,10 +45,6 @@ public class MogoOCHBusPassenger implements IMogoOCH { this.mActivity = activity; this.mContainerId = containerId; showFragment(); - - if (AppIdentityModeUtils.isJL(FunctionBuildConfig.appIdentityMode)) { - MultiDisplayUtils.INSTANCE.startActWithSecond(activity, VideoPlayerActivity.class); - } return null; } diff --git a/OCH/mogo-och-common-module/src/main/java/com/mogo/och/common/module/biz/constant/OchCommonConst.kt b/OCH/mogo-och-common-module/src/main/java/com/mogo/och/common/module/biz/constant/OchCommonConst.kt index 7102e3a8f3..fe0e21da28 100644 --- a/OCH/mogo-och-common-module/src/main/java/com/mogo/och/common/module/biz/constant/OchCommonConst.kt +++ b/OCH/mogo-och-common-module/src/main/java/com/mogo/och/common/module/biz/constant/OchCommonConst.kt @@ -15,6 +15,10 @@ class OchCommonConst { fun getShuttleUrl(): String { return FunctionBuildConfig.urlJson.shuttleUrl } + @JvmStatic + fun getSweeperUrl(): String { + return FunctionBuildConfig.urlJson.sweeperUrl + } // token 失效 重新获取token const val WAIT_TAKEN = 100046 diff --git a/OCH/mogo-och-shuttle-passenger/build.gradle b/OCH/mogo-och-shuttle-passenger/build.gradle index 720eb01ca9..3bdddf460d 100644 --- a/OCH/mogo-och-shuttle-passenger/build.gradle +++ b/OCH/mogo-och-shuttle-passenger/build.gradle @@ -52,11 +52,6 @@ android { dimension "vehicle" buildConfigField 'int', 'NEW_TEST', '0' } - // 车型:金旅m1 小巴业务 - m1 { - dimension "vehicle" - buildConfigField 'int', 'NEW_TEST', '1' - } // 车型:金旅m1 小巴业务 m2 { diff --git a/OCH/mogo-och-sweeper/.gitignore b/OCH/sweeper/sweeper-cloud/.gitignore similarity index 100% rename from OCH/mogo-och-sweeper/.gitignore rename to OCH/sweeper/sweeper-cloud/.gitignore diff --git a/OCH/sweeper/sweeper-cloud/AutopilotModeConfig.json b/OCH/sweeper/sweeper-cloud/AutopilotModeConfig.json new file mode 100644 index 0000000000..9b3ec5a186 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/AutopilotModeConfig.json @@ -0,0 +1,38 @@ +{ + "mode": 1, + "source": 1, + "routeInfo": { + "startLocation": { + "longitude": 112.56970262448544, + "latitude": 26.817567832504274 + }, + "startName": "衡阳测试起点", + "endLocation": { + "longitude": 112.57723562874442, + "latitude": 26.819769725304003 + }, + "endName": "衡阳测试终点", + "wayPoints": [ + { + "longitude": 112.56970262448544, + "latitude": 26.817567832504274 + }, + { + "longitude": 112.57723562874442, + "latitude": 26.819769725304003 + } + ], + "vehicleType": 10, + "routeID": 60006, + "routeName": "衡阳测试路段", + "line": { + "lineId": 60006, + "trajUrl": "https://dzt-test.zhidaozhixing.com/yycp-sweeper/largeSweeper/trajInfo/download?key=largeSweeperTraj/0519qsc_1684823042062.csv", + "trajMd5": "6ad8c0456ced62ba1258753588d5d517", + "stopUrl": "https://dzt-test.zhidaozhixing.com/yycp-sweeper/largeSweeper/trajInfo/download?key=largeSweeperTraj/da_dian_hengyang_1684823379063.txt", + "stopMd5": "b1ecdc2c3a9467d58eb013bda53acf97", + "timestamp": 1684823379533, + "vehicleModel": "" + } + } +} \ No newline at end of file diff --git a/OCH/mogo-och-sweeper/build.gradle b/OCH/sweeper/sweeper-cloud/build.gradle similarity index 100% rename from OCH/mogo-och-sweeper/build.gradle rename to OCH/sweeper/sweeper-cloud/build.gradle diff --git a/OCH/mogo-och-sweeper/gradle.properties b/OCH/sweeper/sweeper-cloud/gradle.properties similarity index 100% rename from OCH/mogo-och-sweeper/gradle.properties rename to OCH/sweeper/sweeper-cloud/gradle.properties diff --git a/OCH/mogo-och-sweeper/proguard-rules.pro b/OCH/sweeper/sweeper-cloud/proguard-rules.pro similarity index 100% rename from OCH/mogo-och-sweeper/proguard-rules.pro rename to OCH/sweeper/sweeper-cloud/proguard-rules.pro diff --git a/OCH/sweeper/sweeper-cloud/schemas/com.mogo.och.sweeper.database.MyDataBase/1.json b/OCH/sweeper/sweeper-cloud/schemas/com.mogo.och.sweeper.database.MyDataBase/1.json new file mode 100644 index 0000000000..a9451322a4 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/schemas/com.mogo.och.sweeper.database.MyDataBase/1.json @@ -0,0 +1,86 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "0897ef4b7b6a43fccf8bcf4b2144dafa", + "entities": [ + { + "tableName": "welt_data_table", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `subTaskId` INTEGER NOT NULL, `locLon` REAL NOT NULL, `locLat` REAL NOT NULL, `weltDistance` REAL NOT NULL, `cleanMode` INTEGER NOT NULL, `cleanDirection` INTEGER NOT NULL, `cleanIntensity` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subTaskId", + "columnName": "subTaskId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "locLon", + "columnName": "locLon", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "locLat", + "columnName": "locLat", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "weltDistance", + "columnName": "weltDistance", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "cleanMode", + "columnName": "cleanMode", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "cleanDirection", + "columnName": "cleanDirection", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "cleanIntensity", + "columnName": "cleanIntensity", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_welt_data_table_id", + "unique": true, + "columnNames": [ + "id" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_welt_data_table_id` ON `${TABLE_NAME}` (`id`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '0897ef4b7b6a43fccf8bcf4b2144dafa')" + ] + } +} \ No newline at end of file diff --git a/OCH/mogo-och-sweeper/src/androidTest/java/com/mogo/och/sweeper/ExampleInstrumentedTest.kt b/OCH/sweeper/sweeper-cloud/src/androidTest/java/com/mogo/och/sweeper/ExampleInstrumentedTest.kt similarity index 100% rename from OCH/mogo-och-sweeper/src/androidTest/java/com/mogo/och/sweeper/ExampleInstrumentedTest.kt rename to OCH/sweeper/sweeper-cloud/src/androidTest/java/com/mogo/och/sweeper/ExampleInstrumentedTest.kt diff --git a/OCH/sweeper/sweeper-cloud/src/main/AndroidManifest.xml b/OCH/sweeper/sweeper-cloud/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..62a365f431 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/AndroidManifest.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-sweeper/src/main/assets/map_style.data b/OCH/sweeper/sweeper-cloud/src/main/assets/map_style.data similarity index 100% rename from OCH/mogo-och-sweeper/src/main/assets/map_style.data rename to OCH/sweeper/sweeper-cloud/src/main/assets/map_style.data diff --git a/OCH/mogo-och-sweeper/src/main/assets/map_style_extra.data b/OCH/sweeper/sweeper-cloud/src/main/assets/map_style_extra.data similarity index 100% rename from OCH/mogo-och-sweeper/src/main/assets/map_style_extra.data rename to OCH/sweeper/sweeper-cloud/src/main/assets/map_style_extra.data diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/IMogoOCH.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/IMogoOCH.java new file mode 100644 index 0000000000..028cb07e56 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/IMogoOCH.java @@ -0,0 +1,24 @@ +package com.mogo.och.sweepercloud; + +import androidx.annotation.IdRes; +import androidx.fragment.app.FragmentActivity; + +import com.mogo.eagle.core.function.api.base.IMoGoFunctionProvider; + +public +/** + * @author congtaowang + * @since 2021/1/15 + * + * 网约车抽象接口 + */ +interface IMogoOCH extends IMoGoFunctionProvider { + + /** + * 初始化网约车容器 + * + * @param activity + * @param containerId 容器ID + */ + void createCoverage(FragmentActivity activity, @IdRes int containerId); +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/SweeperProvider.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/SweeperProvider.java new file mode 100644 index 0000000000..476d872e83 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/SweeperProvider.java @@ -0,0 +1,87 @@ +package com.mogo.och.sweepercloud; + + +import android.content.Context; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; + +import com.alibaba.android.arouter.facade.annotation.Route; +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; +import com.mogo.och.sweepercloud.constant.SweeperConst; +import com.mogo.och.sweepercloud.fragment.SweeperFragment; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * 清扫车业务实现入口 + * + * @author tongchenfei + */ +@Route(path = SweeperConst.PATH) +public class SweeperProvider implements IMogoOCH { + + private static final String TAG = "SweeperProvider"; + + private SweeperFragment sweeperFragment; + private int containerId; + private FragmentActivity activity; + + @Override + public void init(Context context) { + } + private void showFragment() { + FragmentManager supportFragmentManager = activity.getSupportFragmentManager(); + if (sweeperFragment == null) { + CallerLogger.INSTANCE.d(TAG, "准备add fragment======"); + Fragment fragmentByTag = supportFragmentManager.findFragmentByTag(sweeperFragment.TAG); + if (fragmentByTag instanceof SweeperFragment) { + sweeperFragment = (SweeperFragment) fragmentByTag; + } else { + sweeperFragment = new SweeperFragment(); + } + if(!sweeperFragment.isAdded()) { + supportFragmentManager.beginTransaction().add(containerId, sweeperFragment, sweeperFragment.TAG).commitAllowingStateLoss(); + } + return; + } + CallerLogger.INSTANCE.d(TAG, "准备show fragment"); + supportFragmentManager.beginTransaction().show(sweeperFragment).commitAllowingStateLoss(); + } + private void hideFragment() { + if (sweeperFragment != null) { + CallerLogger.INSTANCE.d(TAG, "准备hide fragment"); + activity.getSupportFragmentManager().beginTransaction().hide(sweeperFragment).commitAllowingStateLoss(); + } + + } + + @Override + public void createCoverage(FragmentActivity activity, int containerId) { + + } + + @NotNull + @Override + public String getFunctionName() { + return null; + } + + @Nullable + @Override + public Fragment createCoverage(@Nullable FragmentActivity fragmentActivity, @Nullable Integer integer) { + this.containerId = integer; + this.activity = fragmentActivity; + showFragment(); + return null; + } + + @Override + public void onDestroy() { + //若不调用finish, 设置中打开关闭UITouch,会造成och fragment 重叠 + if (activity == null) return; + activity.finish(); + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/bean/SweeperRoutePlanningUpdateReqBean.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/bean/SweeperRoutePlanningUpdateReqBean.java new file mode 100644 index 0000000000..e2b10f7824 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/bean/SweeperRoutePlanningUpdateReqBean.java @@ -0,0 +1,32 @@ +package com.mogo.och.sweepercloud.bean; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by pangfan on 2021/8/19 + * + * 订单状态更新请求数据结构 + */ +public class SweeperRoutePlanningUpdateReqBean implements Serializable { + public String sn; + public int lineId; + public int startSiteId; + public int endSiteId; + public ArrayList points; + + public static class Result implements Serializable{ + public Double latitude; + public Double longitude; + } + + public SweeperRoutePlanningUpdateReqBean(String sn, int lineId, int startSiteId + , int endSiteId, ArrayList points) { + this.sn = sn; + this.lineId = lineId; + this.startSiteId = startSiteId; + this.endSiteId = endSiteId; + this.points = points; + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ICleaningModeStateCallback.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ICleaningModeStateCallback.java new file mode 100644 index 0000000000..300a7300ad --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ICleaningModeStateCallback.java @@ -0,0 +1,12 @@ +package com.mogo.och.sweepercloud.callback; + +import com.mogo.och.sweepercloud.constant.OperateStateEnum; + +import chassis.ChassisStatesOuterClass; + +/** + * 上装状态回调 + */ +public interface ICleaningModeStateCallback { + void cleaningModeState(OperateStateEnum cleaningModeState, ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState,boolean isSelectPureSweepMode); +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperADASStatusCallback.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperADASStatusCallback.java new file mode 100644 index 0000000000..f8ce45d1a5 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperADASStatusCallback.java @@ -0,0 +1,11 @@ +package com.mogo.och.sweepercloud.callback; + +/** + * Created on 2021/9/8 + * + * Model->Presenter回调:ADAS相关(自动驾驶状态回调,到达终点等等) + */ +public interface ISweeperADASStatusCallback { + //自驾返回失败 + void onStartAdasFailure(); +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperCloudTaskCallback.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperCloudTaskCallback.kt new file mode 100644 index 0000000000..92fc78aafb --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperCloudTaskCallback.kt @@ -0,0 +1,69 @@ +package com.mogo.och.sweepercloud.callback + +import chassis.ChassisStatesOuterClass +import com.mogo.och.sweepercloud.bean.SweeperRoutePlanningUpdateReqBean +import com.mogo.och.sweepercloud.database.bean.WeltDataBean +import com.zhjt.mogo.adas.data.sweeper.SweeperCloudTask +import com.zhjt.mogo.adas.data.sweeper.bootable.SweeperBootable +import com.zhjt.mogo.adas.data.sweeper.bootable.SweeperBootable.IsBootableResp +import com.zhjt.mogo.adas.data.sweeper.common.SweeperCommon +import com.zhjt.mogo.adas.data.sweeper.common.SweeperCommon.Code +import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask +import com.zhjt.mogo.adas.data.sweeper.task.big.SweeperBigTaskStatus +import com.zhjt.mogo.adas.data.sweeper.task.stop.SweeperTaskStop.StopTaskType + +/** + * @author: wangmingjun + * @date: 2021/10/22 + */ +interface ISweeperCloudTaskCallback { + /** + * 接取云端任务/正在执行中任务信息回调 + */ + fun onSweeperCloudTask(messageType: SweeperCloudTask.MessageType,taskInfo: SweeperTask.TaskInfo?) + + /** + * 云端下发子任务请求pad确认 + */ + fun onSweeperCloudTaskConfirm(taskId:String,subTaskId:String,isPop:Boolean) + + /** + * 云端下发子任务状态同步 + */ + fun onSweeperCloudTaskStatus(taskId:String,subTaskId:String,subTaskStatus: SweeperCommon.TaskStatus) + + /** + * 云端下发结束大任务指令 + */ + fun onSweeperCloudTaskStop(taskId:String,stopTaskType: StopTaskType,isPop:Boolean) + + /** + * 挂起/恢复 + */ + fun onSweeperCloudTaskSuspendResume(messageType: SweeperCloudTask.MessageType,taskId:String,subTaskId:String,code:Code) + + /** + * pad请求云端进入自驾 + */ + fun onSweeperCloudBootable(taskId:String,subTaskId:String,isBootableResp: IsBootableResp) + + /** + * 云端同步大任务状态 + */ + fun onSweeperCloudBigTaskStatus(taskId:String,subTaskStatus: SweeperBigTaskStatus.BigTaskStatus) + /** + * 设置轨迹坐标点集合 + */ + fun setRouteList(routeList: java.util.ArrayList) + /** + * 贴边数据回传 + */ + fun setWeltDataToMap(weltDataBeans: ArrayList, isWeltData: Boolean, distance: String) + + /** + * 底盘清扫模式数据回传 + */ + fun onSweeperFutianCleanSystemState(cleanSystemState: ChassisStatesOuterClass.SweeperFuTianTaskSystemStates) + + +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperControllerStatusCallback.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperControllerStatusCallback.java new file mode 100644 index 0000000000..2ad48d1d5b --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperControllerStatusCallback.java @@ -0,0 +1,17 @@ +package com.mogo.och.sweepercloud.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 ISweeperControllerStatusCallback { + // 是否vr map模式 + void onVRModeChanged(boolean isVRMode); + // 自车定位 + void onCarLocationChanged(MogoLocation location); + //自动驾驶状态 + void onAutopilotState(int state); +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperTaskDataToFragmentCallback.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperTaskDataToFragmentCallback.kt new file mode 100644 index 0000000000..4e5badf48d --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperTaskDataToFragmentCallback.kt @@ -0,0 +1,15 @@ +package com.mogo.och.sweepercloud.callback + +import com.amap.api.maps.model.LatLng +import com.mogo.och.sweepercloud.bean.SweeperRoutePlanningUpdateReqBean +import com.mogo.och.sweepercloud.database.bean.WeltDataBean +import java.util.ArrayList + +interface ISweeperTaskDataToFragmentCallback { + fun setRouteList(routeList: ArrayList) + fun setWeltData(weltDatas: ArrayList?, distance: String) + fun clearAllMarkerAndPolyline() + fun setProgress(progress:String) + fun setTaskListCoordinatesLatLng(coordinatesLatLng: ArrayList) + fun setCurrentTaskCoordinatesLatLng(coordinatesLatLng: LatLng) +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperTaskRouteCallback.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperTaskRouteCallback.kt new file mode 100644 index 0000000000..81f37c8a64 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/ISweeperTaskRouteCallback.kt @@ -0,0 +1,8 @@ +package com.mogo.och.sweepercloud.callback + +import com.mogo.och.sweepercloud.bean.SweeperRoutePlanningUpdateReqBean +import java.util.ArrayList + +interface ISweeperTaskRouteCallback { + fun setRouteList(routeList:ArrayList) +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/IWeltMapSwitchToSmallCallback.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/IWeltMapSwitchToSmallCallback.kt new file mode 100644 index 0000000000..20748b003b --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/IWeltMapSwitchToSmallCallback.kt @@ -0,0 +1,5 @@ +package com.mogo.och.sweepercloud.callback + +interface IWeltMapSwitchToSmallCallback { + fun onWeltMapSwitchToSmall() +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/SweeperCloudDialogClickListener.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/SweeperCloudDialogClickListener.kt new file mode 100644 index 0000000000..abf3be40ca --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/callback/SweeperCloudDialogClickListener.kt @@ -0,0 +1,8 @@ +package com.mogo.och.sweepercloud.callback + +interface SweeperCloudDialogClickListener { + fun onConfirm() + fun onRefuseOrEnd() + fun onCountDownStop() + fun onNext() +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/constant/OperateStateEnum.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/constant/OperateStateEnum.kt new file mode 100644 index 0000000000..d757fee453 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/constant/OperateStateEnum.kt @@ -0,0 +1,12 @@ +package com.mogo.och.sweepercloud.constant + +/** + * 上装面板操作状态 + */ +enum class OperateStateEnum(val code: Int) { + SYNCING_STATUS( 1),//清扫车底盘状态同步中 + STARTING_STATUS( 2),//上装中 + FAIL_STATUS( 3),//上装失败 + SUCCESS_STATUS(4),//上装成功 + NO_STATUS(-1);//暂无模式 +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/constant/SweeperConst.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/constant/SweeperConst.kt new file mode 100644 index 0000000000..aa96c7f40d --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/constant/SweeperConst.kt @@ -0,0 +1,70 @@ +package com.mogo.och.sweepercloud.constant + +import com.mogo.commons.debug.DebugConfig + +/** + * Created on 2021/12/6 + */ +class SweeperConst { + companion object { + + // OCH arouter 路由path + const val PATH = "/driver/api" + + // 测试用的广播 + const val BROADCAST_TEST_SWEEPER_CONTROL_TYPE_EXTRA_KEY = "sceneType" + + // 上报心跳轮询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 SWEEPER_START_MAP_MAKER = "sweeper_start_map_maker"; + + //终点UUID + const val SWEEPER_END_MAP_MAKER = "sweeper_end_map_maker"; + + // 埋点key:接管后点击'自动驾驶'按钮启动 + const val EVENT_KEY_RESTART_AUTOPILOT = "event_key_och_sweeper_restart_autopilot" + + // 埋点key:开始服务开启自动驾驶(成功/失败) + const val EVENT_KEY_START_SERVICE = "event_key_och_sweeper_start_service" + const val EVENT_PARAM_SN = "sn" + const val EVENT_PARAM_TIME = "time" + const val EVENT_PARAM_START_NAME = "start_name" + const val EVENT_PARAM_END_NAME = "end_name" + const val EVENT_PARAM_LINE_ID = "line_id" + const val EVENT_PARAM_START_RESULT = "start_autopilot" // true/false + const val EVENT_PARAM_START_FAILURE_CODE = "start_autopilot_failure_code" // 启动自驾失败code + const val EVENT_PARAM_START_FAILURE_MSG = "start_autopilot_failure_msg" // 启动自驾失败原因 + const val EVENT_PARAM_PLATE_NUM = "plate_number" // 车牌号 + const val EVENT_PARAM_ENV_ONLINE = "env_online" // 是否线上环境:true/false + + // 埋点key:开启自动驾驶前已识别的异常,会导致无法开启自驾 + const val EVENT_KEY_AP_UNABLE_START_REASON = "event_key_och_bus_ap_unable_start_reason" + const val EVENT_PARAM_UNABLE_START_REASON = "unable_start_reason"; + + /** + * 订单起终点Marker类型 + */ + const val TYPE_MARKER_SWEEPER_ORDER = "TYPE_MARKER_SWEEPER_ORDER" + + const val TIMER_START_AUTOPILOT_INTERVAL = 20 * 1000L + + //围栏到站 暂定10米 + const val ARRIVE_AT_END_STATION_DISTANCE = 10 + + //非贴边 + const val NONWELT = -10000.0 + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/database/MyDataBase.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/database/MyDataBase.java new file mode 100644 index 0000000000..7d2cdb3e22 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/database/MyDataBase.java @@ -0,0 +1,31 @@ +package com.mogo.och.sweepercloud.database; + +import com.mogo.commons.AbsMogoApplication; +import com.mogo.och.sweepercloud.database.bean.WeltDataBean; +import com.mogo.och.sweepercloud.database.dao.WeltDataDao; +import com.mogo.och.sweepercloud.database.bean.WeltDataBean; +import com.mogo.och.sweepercloud.database.dao.WeltDataDao; + +import androidx.room.Database; +import androidx.room.Room; +import androidx.room.RoomDatabase; + +//注解Database告诉系统这是Room数据库对象 +//entities指定该数据库有哪些表,多张表就逗号分隔 +//version指定数据库版本号,升级时需要用到 +//数据库继承自RoomDatabase +@Database(entities = {WeltDataBean.class}, version = 1) +public abstract class MyDataBase extends RoomDatabase { + private static final String DATABASE_NAME = "weltData_db"; + + //结合单例模式完成数据库实例创建 + public static MyDataBase getInstance() { + return SingleTon.instance; + } + + private static class SingleTon { + private static final MyDataBase instance = + Room.databaseBuilder(AbsMogoApplication.getApp().getApplicationContext(), MyDataBase.class, DATABASE_NAME).build(); + } + public abstract WeltDataDao getWeltDataDao(); +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/database/bean/WeltDataBean.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/database/bean/WeltDataBean.java new file mode 100644 index 0000000000..f6a3be84ee --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/database/bean/WeltDataBean.java @@ -0,0 +1,127 @@ +package com.mogo.och.sweepercloud.database.bean; + +import java.io.Serializable; + +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.Index; +import androidx.room.PrimaryKey; + +@Entity(tableName = WeltDataBean.WeltDataTable, indices = {@Index(value = "id", unique = true)}) +public class WeltDataBean implements Serializable { + + public static final String WeltDataTable = "welt_data_table"; + //ColumnInfo用于指定该字段存储在表中的名字,并指定类型 + + @PrimaryKey(autoGenerate = true) + + @ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER) + + private int id; + + @ColumnInfo(name = "subTaskId", typeAffinity = ColumnInfo.TEXT)//子任务id + + private String subTaskId; + + @ColumnInfo(name = "locLon", typeAffinity = ColumnInfo.REAL) + + private double locLon;//自车RTK定位经度 + + @ColumnInfo(name = "locLat", typeAffinity = ColumnInfo.REAL) + + private double locLat;//自车RTK定位纬度 + + @ColumnInfo(name = "weltDistance", typeAffinity = ColumnInfo.REAL) + + private double weltDistance;//贴边距离 + + @ColumnInfo(name = "cleanMode", typeAffinity = ColumnInfo.INTEGER) + + private int cleanMode;//清扫作业模式 1–纯扫 2--洗扫, 3--纯洗, 4--纯吸 + + @ColumnInfo(name = "cleanDirection", typeAffinity = ColumnInfo.INTEGER) + + private int cleanDirection;//清扫方向 1--两侧, 2--左侧, 3--右侧 + + @ColumnInfo(name = "cleanIntensity", typeAffinity = ColumnInfo.INTEGER) + + private int cleanIntensity;//清扫强度 1--两侧, 2--左侧, 3--右侧 + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getSubTaskId() { + return subTaskId; + } + + public void setSubTaskId(String subTaskId) { + this.subTaskId = subTaskId; + } + + public double getLocLon() { + return locLon; + } + + public void setLocLon(double locLon) { + this.locLon = locLon; + } + + public double getLocLat() { + return locLat; + } + + public void setLocLat(double locLat) { + this.locLat = locLat; + } + + public double getWeltDistance() { + return weltDistance; + } + + public void setWeltDistance(double weltDistance) { + this.weltDistance = weltDistance; + } + + public int getCleanMode() { + return cleanMode; + } + + public void setCleanMode(int cleanMode) { + this.cleanMode = cleanMode; + } + + public int getCleanDirection() { + return cleanDirection; + } + + public void setCleanDirection(int cleanDirection) { + this.cleanDirection = cleanDirection; + } + + public int getCleanIntensity() { + return cleanIntensity; + } + + public void setCleanIntensity(int cleanIntensity) { + this.cleanIntensity = cleanIntensity; + } + + @Override + public String toString() { + return "WeltDataBean{" + + "id=" + id + + ", subTaskId='" + subTaskId + '\'' + + ", locLon=" + locLon + + ", locLat=" + locLat + + ", weltDistance=" + weltDistance + + ", cleanMode=" + cleanMode + + ", cleanDirection=" + cleanDirection + + ", cleanIntensity=" + cleanIntensity + + '}'; + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/database/dao/WeltDataDao.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/database/dao/WeltDataDao.java new file mode 100644 index 0000000000..4217b93d85 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/database/dao/WeltDataDao.java @@ -0,0 +1,28 @@ +package com.mogo.och.sweepercloud.database.dao; + +import com.mogo.och.sweepercloud.database.bean.WeltDataBean; +import com.mogo.och.sweepercloud.database.bean.WeltDataBean; + +import java.util.List; + +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; + +import static com.mogo.och.sweepercloud.database.bean.WeltDataBean.WeltDataTable; + +@Dao +public interface WeltDataDao { + //插入数据 + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insert(WeltDataBean fileInfo); + + //删除所有数据 + @Query("DELETE FROM " + WeltDataBean.WeltDataTable) + int deleteAllWeltData(); + + //查询所有数据 + @Query("SELECT * FROM " + WeltDataBean.WeltDataTable) + List loadAllWeltDataInfo(); +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/BaseSweeperTabFragment.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/BaseSweeperTabFragment.java new file mode 100644 index 0000000000..3cab0a8613 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/BaseSweeperTabFragment.java @@ -0,0 +1,611 @@ +package com.mogo.och.sweepercloud.fragment; + +import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_SWEEPER; + +import android.os.Bundle; +import android.os.Parcelable; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.constraintlayout.widget.Group; +import androidx.fragment.app.FragmentTransaction; + +import com.amap.api.maps.model.LatLng; +import com.elegant.network.utils.GsonUtil; +import com.google.protobuf.TextFormat; +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.autopilot.AutopilotControlParameters; +import com.mogo.eagle.core.data.config.FunctionBuildConfig; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager; +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.hmi.CallerHmiManager; +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.view.MapBizView; +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; +import com.mogo.eagle.core.utilcode.mogo.view.OnPreventFastClickListener; +import com.mogo.eagle.core.utilcode.util.ThreadUtils; +import com.mogo.eagle.core.utilcode.util.ToastUtils; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; +import com.mogo.map.listener.IMogoMapListener; +import com.mogo.map.listener.MogoMapListenerHandler; +import com.mogo.map.marker.IMogoMarkerManager; +import com.mogo.map.uicontroller.IMogoMapUIController; +import com.mogo.map.uicontroller.VisualAngleMode; +import com.mogo.och.common.module.manager.OCHAdasAbilityManager; +import com.mogo.och.common.module.utils.CoordinateCalculateRouteUtil; +import com.mogo.och.common.module.utils.PinYinUtil; +import com.mogo.och.sweepercloud.R; +import com.mogo.och.sweepercloud.bean.SweeperRoutePlanningUpdateReqBean; +import com.mogo.och.sweepercloud.callback.ISweeperTaskDataToFragmentCallback; +import com.mogo.och.sweepercloud.callback.IWeltMapSwitchToSmallCallback; +import com.mogo.och.sweepercloud.database.bean.WeltDataBean; +import com.mogo.och.sweepercloud.util.AutopilotModeConfigManager; +import com.mogo.och.sweepercloud.util.SweeperCloudTaskUtils; +import com.mogo.och.sweepercloud.view.SweeperTrafficDataView; +import com.mogo.och.sweepercloud.view.WeltSmallMapView; +import com.zhjt.mogo.adas.data.sweeper.SweeperCloudTask; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; + +import mogo.telematics.pad.MessagePad; + +/** + * 网约车基础Fragment,主要负责布局通用界面,处理站点面板和通话面板互斥情况 + *

+ * 部分业务放在了此处处理 + * + * @author tongchenfei + */ +public abstract class BaseSweeperTabFragment> extends MvpFragment implements IMogoMapListener, + IWeltMapSwitchToSmallCallback, View.OnTouchListener { + + private static final String TAG = "BaseSweeperTabFragment"; + //地图放大缩小 + private ImageView mSwitchMapModeImage; + //设置信息面板 + protected ImageView mSettingBtn; + //安全员问题上报面板 + protected ImageView mCardBtn; + //道路状况上报面板 + protected ImageView mAICollectBtn; + //任务列表面板 + private FrameLayout flTaskListPanelContainer; + private MapBizView mapBizView; + private Group groupTestPanel; + //清扫车车辆基本信息 速度 档位 转向灯 红绿灯等 + private SweeperTrafficDataView mTrafficDataView; + //作业任务贴边数据展示图 + private WeltSmallMapView mMapWeltView; + //任务作业全览图 + private WeltMapOverViewFragment mWeltMapOverViewFragment; + private FrameLayout mFlWeltMapOverView; + private DriverMsgBoxButtonView mViewDriverMsgBoxButton; + private DriverMsgBoxListView mViewDriverMsgBoxList; + private DriverMsgBoxBubbleView mViewDriverMsgBoxBubble; + private ArrayList mWeltDataBeanList;//存储贴边数据 + private ArrayList mSubTaskCoordinates;//存储当前大任务的所有子任务起点和终点 + // 当前子任务的终点坐标 + protected LatLng mCurrentTaskEndStation; + private ArrayList mRouteList;//存储任务的坐标轨迹 + private String mProgress; + private ISweeperTaskDataToFragmentCallback mTaskDataToFragmentCallback; + + @Override + protected int getLayoutId() { + return R.layout.sweeper_base_fragment; + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + + @Override + protected void initViews() { + mapBizView = findViewById(R.id.mapBizView); + groupTestPanel = findViewById(R.id.groupTestPanel); + flTaskListPanelContainer = findViewById(R.id.module_mogo_och_task_list_container); + mTrafficDataView = findViewById(R.id.sweeper_arc); + LayoutInflater.from(getContext()).inflate(getTaskListPanelViewId(), flTaskListPanelContainer); + mSwitchMapModeImage = findViewById(R.id.sweeper_switch_model_icon); + mSettingBtn = findViewById(R.id.sweeper_setting_model_icon); + mCardBtn = findViewById(R.id.sweeper_card_model_icon); + mAICollectBtn = findViewById(R.id.sweeper_collect_model_icon); + mMapWeltView = findViewById(R.id.sweeper_task_welt_small_map); + mFlWeltMapOverView = findViewById(R.id.sweeper_welt_map_overview); + initListener(); + //设置消息盒子 + setMessageBox(); + //设置左下角四个按钮监听事件 + setBottomBtnListener(); + // 模拟 下发启动自驾命令 + findViewById(R.id.btnStartAutopilot).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!FunctionBuildConfig.isDemoMode && !OCHAdasAbilityManager.getInstance().getAutopilotAbilityStatus()) { + ToastUtils.showLong(OCHAdasAbilityManager.getInstance().getAutopilotUnAbilityReason() + ", 请稍候重试"); + return; + } + new AutopilotModeConfigManager(new AutopilotModeConfigManager.OnReadAutopilotModeConfigListener() { + @Override + public void onReadFailed(String err) { + ThreadUtils.runOnUiThread(() -> { + ToastUtils.showLong("读取失败=" + err); + }); + } + + @Override + public void onParseFailed(String err) { + ToastUtils.showLong("解析失败=" + err); + } + + @Override + public void onParse(MessagePad.SetAutopilotModeReq bean) { + ToastUtils.showLong("下发命令\n" + TextFormat.printer().escapingNonAscii(false).printToString(bean)); + AutopilotControlParameters parameters = new AutopilotControlParameters(); + MessagePad.RouteInfo routeInfo = bean.getRouteInfo(); + if (routeInfo.getRouteID() > 0) { + parameters.routeID = routeInfo.getRouteID(); + } + parameters.routeName = routeInfo.getRouteName(); + parameters.startName = routeInfo.getStartName();//拼音 + parameters.endName = routeInfo.getEndName();//拼音 + parameters.startLatLon = new AutopilotControlParameters + .AutoPilotLonLat(routeInfo.getStartLocation().getLatitude(), routeInfo.getStartLocation().getLongitude()); + parameters.endLatLon = new AutopilotControlParameters + .AutoPilotLonLat(routeInfo.getEndLocation().getLatitude(), routeInfo.getEndLocation().getLongitude()); + parameters.vehicleType = 10; + MessagePad.Line line = routeInfo.getLine(); + parameters.autoPilotLine = new AutopilotControlParameters.AutoPilotLine( + line.getLineId(), + line.getTrajUrl(), line.getTrajMd5(), + line.getStopUrl(), line.getStopMd5(), + line.getTimestamp(), line.getVehicleModel(), + line.getTrajUrlDpqp(), line.getTrajMd5Dpqp(), + line.getStopUrlDpqp(), line.getStopMd5Dpqp(), + line.getTimestampDpqp()); + CallerAutoPilotControlManager.INSTANCE.startAutoPilot(parameters); + } + }).read(); + } + }); + // 模拟 查询当前任务 + findViewById(R.id.btnQueryCurrentTask).setOnClickListener(view -> + SweeperCloudTaskUtils.mockQueryCurrentTaskInfo() + ); + // 模拟 云端发送任务 + findViewById(R.id.btnSendTask).setOnClickListener(view -> { + SweeperCloudTaskUtils.mockSendCloudTaskInfo(SweeperCloudTask.MessageType.CloudPushTask); + UiThreadHandler.postDelayed(() -> { + debugEndSubTask(); + }, 5000); + + } + + ); + // 模拟 云端发送子任务确认 + findViewById(R.id.btnSendSubTaskConfirm).setOnClickListener(view -> + SweeperCloudTaskUtils.mockSendCloudSubTaskConfirm() + ); + + // 模拟 云端请求结束大任务 + findViewById(R.id.btnSendEndTask).setOnClickListener(view -> + SweeperCloudTaskUtils.mockSendCloudBigTaskEnd() + ); + // 模拟 云端发送子任务状态 + findViewById(R.id.btnSendSubtaskStatus).setOnClickListener(view -> + SweeperCloudTaskUtils.mockSendCloudUpdateSubTaskStatus() + ); + // 模拟 云端发送大任务状态 + findViewById(R.id.btnSendTaskStatus).setOnClickListener(view -> + SweeperCloudTaskUtils.mockSendCloudBigTaskStatus() + ); + mTrafficDataView.getSpeedImage().setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + debugTestBar(); + return false; + } + }); + } + + private void updateSwitchMapIcon() { + IMogoMapUIController controller = CallerMapUIServiceManager.INSTANCE.getMapUIController(); + if (controller != null) { + if (controller.getCurrentMapVisualAngle().isLongSight()) { + mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_big_selector); + } else if (controller.getCurrentMapVisualAngle().isMediumSight()) { + mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_small_selector); + } else { + mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_small_selector); + } + } + } + + /** + * 设置任务进度 + * + * @param progress + */ + protected void setTaskProgress(String progress) { + ThreadUtils.runOnUiThread(() -> { + mMapWeltView.setTaskProgress(progress); + mProgress = progress; + if (mTaskDataToFragmentCallback != null) { + mTaskDataToFragmentCallback.setProgress(progress); + } + }); + } + + @Override + protected void initViews(Bundle savedInstanceState) { + super.initViews(savedInstanceState); + mapBizView.onCreate(savedInstanceState); + mMapWeltView.onCreateView(savedInstanceState); + } + + public void setAutoState(int state) { + mTrafficDataView.setAutoState(state); + } + + /** + * 消息盒子 + */ + private void setMessageBox() { + mViewDriverMsgBoxButton = findViewById(R.id.viewDriverMsgBoxButton); + mViewDriverMsgBoxList = findViewById(R.id.viewDriverMsgBoxList); + mViewDriverMsgBoxBubble = findViewById(R.id.viewDriverMsgBoxBubble); + //消息盒子 + mViewDriverMsgBoxButton.setClickListener(show -> { + if (show) { + mViewDriverMsgBoxList.setVisibility(View.VISIBLE); + mViewDriverMsgBoxList.notifyData(); + mViewDriverMsgBoxBubble.setVisibility(View.GONE); + mViewDriverMsgBoxBubble.isShowData(false); + } else { + mViewDriverMsgBoxList.setVisibility(View.GONE); + mViewDriverMsgBoxBubble.setVisibility(View.VISIBLE); + mViewDriverMsgBoxBubble.isShowData(true); + } + }); + } + + @Override + public void onPause() { + super.onPause(); + mMapWeltView.onPause(); + } + + @Override + public void onResume() { + super.onResume(); + mapBizView.onResume(); + mMapWeltView.onResume(); + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + mapBizView.onSaveInstanceState(outState); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapBizView.onLowMemory(); + } + + @Override + public void onDestroyView() { + mapBizView.onDestroy(); + super.onDestroyView(); + CallerAutopilotRecordListenerManager.INSTANCE.removeListener(TAG); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + view.setOnTouchListener(this); + + } + + private void initListener() { + MogoMapListenerHandler.Companion.getMogoMapListenerHandler().registerHostMapListener(TAG, this); + mMapWeltView.getSwitchToBig().setOnClickListener((v) -> { + showOrHideOverMapViewFragment(true); + }); + } + + /** + * 清扫车任务列表面板view,在{@link #initViews()}时候添加到container中 + * + * @return 站点面板view + */ + public abstract int getTaskListPanelViewId(); + + + /** + * 迈速表实时更新 + * + * @param newSpeed + */ + public void updateSpeedView(float newSpeed) { + int speed = (int) (Math.abs(newSpeed) * 3.6F); // 倒车时工控机反馈定位信息中speed为负值 + if (mTrafficDataView != null) { + mTrafficDataView.updateSpeedWithValue(speed); + } + } + + /** + * 车辆基本信息View + * + * @return + */ + public SweeperTrafficDataView getTrafficDataView() { + return mTrafficDataView; + } + + @Override + public void onDestroy() { + super.onDestroy(); + mMapWeltView.onDestroy(); + MogoMapListenerHandler.Companion.getMogoMapListenerHandler().unregisterHostMapListener(TAG); + } + + @Override + public void onMapVisualAngleChanged(VisualAngleMode visualAngleMode) { + if (visualAngleMode.isMediumSight()) { + mSwitchMapModeImage.setVisibility(View.VISIBLE); + } else if (visualAngleMode.isLongSight()) { + mSwitchMapModeImage.setVisibility(View.VISIBLE); + } else if (visualAngleMode.isCloseSight()) { + mSwitchMapModeImage.setVisibility(View.GONE); + } + } + + /** + * sweeper调试面板打开关闭 + */ + public void debugTestBar() { + if (groupTestPanel.getVisibility() == View.VISIBLE) { + groupTestPanel.setVisibility(View.GONE); + } else { + groupTestPanel.setVisibility(View.VISIBLE); + } + } + + /** + * 底部四个按钮监听 + * 1.地图放大缩小 + * 2.设置面板 + * 3.安全员问题上报面板 + * 4.道路状况上报面板 + */ + private void setBottomBtnListener() { + updateSwitchMapIcon(); + mSwitchMapModeImage.setOnClickListener(new OnPreventFastClickListener() { + @Override + public void onClickImpl(View v) { + IMogoMapUIController controller = CallerMapUIServiceManager.INSTANCE.getMapUIController(); + IMogoMarkerManager markerManager = CallerMapUIServiceManager.INSTANCE.getMarkerManager(AbsMogoApplication.getApp()); + if (controller != null && markerManager != null) { + //切换地图的远近视图 + if (controller.getCurrentMapVisualAngle().isLongSight()) { + // 2.11.0去掉 +// MogoMarkerManager.getInstance(AbsMogoApplication.getApp()).visibleAllMarkers(); + controller.changeMapVisualAngle(VisualAngleMode.MODE_MEDIUM_SIGHT, null); + mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_small_selector); + } else if (controller.getCurrentMapVisualAngle().isMediumSight()) { + // 2.11.0去掉 +// MogoMarkerManager.getInstance(AbsMogoApplication.getApp()) +// .inVisibleWithoutMarkers(DataTypes.TYPE_MARKER_ADAS, BusConst.TYPE_MARKER_BUS_ORDER); + controller.changeMapVisualAngle(VisualAngleMode.MODE_LONG_SIGHT, null); + mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_big_selector); + } else { + // 2.11.0去掉 +// MogoMarkerManager.getInstance(AbsMogoApplication.getApp()).visibleAllMarkers(); + controller.changeMapVisualAngle(VisualAngleMode.MODE_MEDIUM_SIGHT, null); + mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_big_selector); + } + } + } + }); + mSettingBtn.setOnClickListener(v -> { + // TODO: 2021/12/9 + CallerHmiManager.INSTANCE.showToolsView(); + }); + if (mCardBtn != null) { + CallerDevaToolsManager.INSTANCE.initBadCase(mCardBtn); + } + if (mAICollectBtn != null) { + CallerDevaToolsManager.INSTANCE.initAiCollect(mAICollectBtn); + } + } + + /** + * 设置作业任务全览图隐藏或者显示 + * + * @param isShow + */ + public void showOrHideOverMapViewFragment(boolean isShow) { + FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); + if (isShow) { + mFlWeltMapOverView.setVisibility(View.VISIBLE); + if (mWeltMapOverViewFragment == null) { + mWeltMapOverViewFragment = mWeltMapOverViewFragment.newInstance( + (IWeltMapSwitchToSmallCallback) this, + mCurrentTaskEndStation, + mWeltDataBeanList, + mSubTaskCoordinates, + mRouteList, + mProgress, + (SweeperFragment) this); + } + if (mWeltMapOverViewFragment.isHidden()) { + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .show(mWeltMapOverViewFragment).commitAllowingStateLoss(); + return; + } + if (mWeltMapOverViewFragment.isAdded()) { + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .show(mWeltMapOverViewFragment).commitAllowingStateLoss(); + return; + } + transaction + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .add(R.id.sweeper_welt_map_overview, mWeltMapOverViewFragment) + .show(mWeltMapOverViewFragment).commitAllowingStateLoss(); + } else { + mFlWeltMapOverView.setVisibility(View.GONE); + if (mWeltMapOverViewFragment != null) { + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE) + .hide(mWeltMapOverViewFragment).commitAllowingStateLoss(); + } + } + } + + @Override + public void onWeltMapSwitchToSmall() { + showOrHideOverMapViewFragment(false); + } + + /** + * 设置贴边数据到地图 + * + * @param weltDataBeans + */ + public void setWeltDataToMap(ArrayList weltDataBeans, Boolean isWeltData, String distance) { + mWeltDataBeanList = weltDataBeans; + ThreadUtils.getSinglePool().execute(new Runnable() { + @Override + public void run() { + if (mMapWeltView != null) { + mMapWeltView.setWeltData(weltDataBeans, isWeltData, distance); + } + if (mTaskDataToFragmentCallback != null) { + mTaskDataToFragmentCallback.setWeltData(weltDataBeans, distance); + } + } + }); + } + + public void setTaskListCoordinatesLatLng(ArrayList subTaskCoordinates) { + this.mSubTaskCoordinates = subTaskCoordinates; + if (mMapWeltView != null) { + mMapWeltView.setTaskListCoordinatesLatLng(subTaskCoordinates); + } + if (mTaskDataToFragmentCallback != null) { + mTaskDataToFragmentCallback.setTaskListCoordinatesLatLng(subTaskCoordinates); + } + } + + /** + * 设置当前任务终点 + * + * @param subTaskCoordinate + */ + public void setCurrentTaskEndMarker(LatLng subTaskCoordinate) { + if (mMapWeltView != null) { + mMapWeltView.setCurrentTaskCoordinatesLatLng(subTaskCoordinate); + } + if (mTaskDataToFragmentCallback != null) { + mTaskDataToFragmentCallback.setCurrentTaskCoordinatesLatLng(subTaskCoordinate); + } + } + + /** + * 清除marker标记和任务路线数据 + */ + public void clearAllMarkerAndPolyline() { + if (mMapWeltView != null) { + mMapWeltView.clearAllMarkerAndPolyline(); + } + if (mTaskDataToFragmentCallback != null) { + mTaskDataToFragmentCallback.clearAllMarkerAndPolyline(); + } + } + + /** + * 设置任务轨迹点数据 + */ + public void setTaskRouteList(ArrayList routeList) { + mRouteList = routeList; + ThreadUtils.getSinglePool().execute(() -> { + mMapWeltView.setRouteList(routeList); + if (mTaskDataToFragmentCallback != null) { + mTaskDataToFragmentCallback.setRouteList(routeList); + } + }); + } + + public static String format(double value) { + BigDecimal bd = new BigDecimal(value); + bd = bd.setScale(2, RoundingMode.HALF_UP); + return bd.toString(); + } + + public void setTaskDataToFragmentCallback(ISweeperTaskDataToFragmentCallback mTaskDataToFragmentCallback) { + this.mTaskDataToFragmentCallback = mTaskDataToFragmentCallback; + } + + /** + * 结束子任务 + */ + public void debugEndSubTask() { + ArrayList resultArrayList = tempData(); + setTaskRouteList(resultArrayList); + UiThreadHandler.postDelayed(() -> { + ArrayList routeList = tempData1(); + ArrayList weltDataBeans = new ArrayList<>(); + ArrayList subTaskCoordinates = new ArrayList<>(); + for (int i = 0; i < routeList.size(); i++) { + WeltDataBean weltDataBean = new WeltDataBean(); + weltDataBean.setLocLon(routeList.get(i).longitude); + weltDataBean.setLocLat(routeList.get(i).latitude); + weltDataBean.setWeltDistance(Math.random() * 50); + weltDataBeans.add(weltDataBean); + subTaskCoordinates.add(new LatLng(routeList.get(i).latitude, routeList.get(i).longitude)); + } + setTaskListCoordinatesLatLng(subTaskCoordinates); + setWeltDataToMap(weltDataBeans, true, format(Math.random() * 50)); + }, 2000); + } + + private ArrayList tempData() { + ArrayList results = new ArrayList<>(); + results.add(getRoute(112.56970669282785, 26.8175674285121)); + results.add(getRoute(112.57154905962457, 26.81762377130161)); + results.add(getRoute(112.57723562917293, 26.819769721883098)); + return results; + } + + private ArrayList tempData1() { + ArrayList results = new ArrayList<>(); + results.add(getRoute(112.56970669282785, 26.8175674285121)); + results.add(getRoute(112.57154905962457, 26.81762377130161)); + results.add(getRoute(112.57723562917293, 26.819769721883098)); + return results; + } + + private SweeperRoutePlanningUpdateReqBean.Result getRoute(double longitude, double latitude) { + LatLng latLng = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj(AbsMogoApplication.getApp(), longitude, latitude); + SweeperRoutePlanningUpdateReqBean.Result result = new SweeperRoutePlanningUpdateReqBean.Result(); + result.latitude = latLng.latitude; + result.longitude = latLng.longitude; + return result; + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/BaseSweeperUIFragment.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/BaseSweeperUIFragment.java new file mode 100644 index 0000000000..e220d1a777 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/BaseSweeperUIFragment.java @@ -0,0 +1,50 @@ +package com.mogo.och.sweepercloud.fragment; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +/** + * @author: wangmingjun + * @date: 2021/9/9 + */ +public abstract class BaseSweeperUIFragment extends Fragment { + private View mRootView; + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (mRootView == null) { + mRootView = inflater.inflate(getLayoutId(), container, false); + } else { + ViewGroup viewGroup = (ViewGroup) mRootView.getParent(); + if (viewGroup != null) { + viewGroup.removeView(mRootView); + } + } + initViews(mRootView); + initViews(savedInstanceState); + return mRootView; + } + /** + * 布局资源 + * + * @return + */ + protected abstract int getLayoutId(); + + protected abstract void initViews(View view); + + protected void initViews(Bundle savedInstanceState) { + } + + @Override + public void onDestroy() { + super.onDestroy(); + mRootView = null; + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/SweeperAmapNaviFragment.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/SweeperAmapNaviFragment.java new file mode 100644 index 0000000000..e05d396e95 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/SweeperAmapNaviFragment.java @@ -0,0 +1,230 @@ +package com.mogo.och.sweepercloud.fragment; + +import android.os.Bundle; +import android.view.View; + +import com.amap.api.navi.AMapNaviViewListener; +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; +import com.mogo.och.common.module.map.AmapNaviToDestinationModel; +import com.mogo.och.common.module.map.CommonAmapNaviVIew; +import com.mogo.och.common.module.map.ICommonNaviChangedCallback; +import com.mogo.och.sweepercloud.R; + +import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_TAXI; + +/** + * @author: wangmingjun + * @date: 2021/11/30 + */ +public class SweeperAmapNaviFragment extends BaseSweeperUIFragment implements AMapNaviViewListener { + + private CommonAmapNaviVIew mAMapNaviView; + private ICommonNaviChangedCallback mNaviToStartInfoCallback; + public static SweeperAmapNaviFragment newInstance() { + + Bundle args = new Bundle(); + + SweeperAmapNaviFragment fragment = new SweeperAmapNaviFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected int getLayoutId() { + return R.layout.sweeper_amap_navi_view; + } + + @Override + protected void initViews(View view) { + mAMapNaviView = view.findViewById(R.id.navi_view); + } + + @Override + protected void initViews(Bundle savedInstanceState) { + super.initViews(savedInstanceState); + if (mAMapNaviView != null) + mAMapNaviView.onCreate(savedInstanceState); + } + + @Override + public void onResume() { + super.onResume(); + if (mAMapNaviView != null) + mAMapNaviView.onResume(); + } + + @Override + public void onPause() { + super.onPause(); + if (mAMapNaviView != null) + mAMapNaviView.onPause(); + } + + @Override + public void onHiddenChanged(boolean hidden) { + super.onHiddenChanged(hidden); + if (hidden) { //不在最前端界面显示 + if (mAMapNaviView != null){ + mAMapNaviView.onPause(); + } + } else { //重新显示到最前端 + if (mAMapNaviView != null){ + mAMapNaviView.onResume(); + } + } + } + @Override + public void onDestroy() { + super.onDestroy(); + + AmapNaviToDestinationModel.getInstance(getContext()).setVoiceIsMute(false); + if (mAMapNaviView != null){ + mAMapNaviView.onDestroy(); + } + + if (mNaviToStartInfoCallback != null){ + mNaviToStartInfoCallback = null; + } + } + + @Override + public void onNaviSetting() { + //底部导航设置点击回调 + } + + @Override + public void onNaviCancel() { + } + + @Override + public void onNaviMapMode(int naviMode) { + //导航态车头模式,0:车头朝上状态;1:正北朝上模式。 + } + + @Override + public void onNaviTurnClick() { + //转弯view的点击回调 + } + + @Override + public void onNextRoadClick() { + //下一个道路View点击回调 + } + + + @Override + public void onScanViewButtonClick() { + //全览按钮点击回调 + } + + + @Override + public void onLockMap(boolean isLock) { + //锁地图状态发生变化时回调 + } + + @Override + public void onNaviViewLoaded() { + CallerLogger.INSTANCE.d(M_TAXI + "wlx", "导航页面加载成功"); + CallerLogger.INSTANCE.d(M_TAXI + "wlx", "请不要使用AMapNaviView.getMap().setOnMapLoadedListener();会overwrite导航SDK内部画线逻辑"); + } + + @Override + public void onMapTypeChanged(int i) { + + } + + @Override + public void onNaviViewShowMode(int i) { + + } + + @Override + public boolean onNaviBackClick() { + return false; + } + + /** + * 车道信息说明: + *

+ * 0xFF, 无对应车道 + * 0, 直行 + * 1, 左转 + * 2, 直行+左转 + * 3, 右转 + * 4, 直行+右转 + * 5, 左掉头 + * 6, 左转+右转 + * 7, 直行+左转+右转 + * 8, 右掉头 + * 9, 直行+左掉头 + * 10, 直行+右掉头 + * 11, 左转+左掉头 + * 12, 右转+右掉头 + * 13, 直行+扩展 + * 14, 左转+左掉头+扩展 + * 15, 保留 + * 16, 直行+左转+左掉头 + * 17, 右转+左掉头 + * 18, 左转+右转+左掉头 + * 19, 直行+右转+左掉头 + * 20, 左转+右掉头 + * 21, 公交车道 + * 22, 空车道 + * 23 可变车道 + */ + + String[] array = { + "直行车道" + , "左转车道" + , "左转或直行车道" + , "右转车道" + , "右转或直行车道" + , "左掉头车道" + , "左转或者右转车道" + , " 左转或右转或直行车道" + , "右转掉头车道" + , "直行或左转掉头车道" + , "直行或右转掉头车道" + , "左转或左掉头车道" + , "右转或右掉头车道" + , "直行并且车道扩展" + , "左转+左掉头+扩展" + , "不可以选择该车道" + , "直行+左转+左掉头车道" + , "右转+左掉头" + , "左转+右转+左掉头" + , "直行+右转+左掉头" + , "左转+右掉头" + , "公交车道" + , "空车道" + , "可变车道" + }; + + String[] actions = { + "直行" + , "左转" + , "左转或直行" + , "右转" + , "右转或这行" + , "左掉头" + , "左转或者右转" + , " 左转或右转或直行" + , "右转掉头" + , "直行或左转掉头" + , "直行或右转掉头" + , "左转或左掉头" + , "右转或右掉头" + , "直行并且车道扩展" + , "左转+左掉头+扩展" + , "不可以选择" + , "直行+左转+左掉头" + , "右转+左掉头" + , "左转+右转+左掉头" + , "直行+右转+左掉头" + , "左转+右掉头" + , "公交车道" + , "空车道" + , "可变车道" + }; +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/SweeperFragment.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/SweeperFragment.kt new file mode 100644 index 0000000000..a59f2c0fd7 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/SweeperFragment.kt @@ -0,0 +1,587 @@ +package com.mogo.och.sweepercloud.fragment + +import android.os.Bundle +import android.view.View +import androidx.lifecycle.lifecycleScope +import chassis.ChassisStatesOuterClass +import com.amap.api.maps.model.LatLng +import com.elegant.utils.UiThreadHandler +import com.mogo.eagle.core.data.map.MogoLocation +import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener.Companion.STATUS_AUTOPILOT_ENABLE +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.ToastUtils +import com.mogo.och.common.module.voice.VoiceNotice.showNotice +import com.mogo.och.sweepercloud.R +import com.mogo.och.sweepercloud.bean.SweeperRoutePlanningUpdateReqBean +import com.mogo.och.sweepercloud.callback.SweeperCloudDialogClickListener +import com.mogo.och.sweepercloud.database.MyDataBase +import com.mogo.och.sweepercloud.presenter.SweeperPresenter +import com.mogo.och.sweepercloud.ui.dialog.SweeperCloudDialog +import com.mogo.och.sweepercloud.ui.dialog.SweeperCloudLoadingDialog +import com.mogo.och.sweepercloud.util.SweeperCloudTaskUtils.createConfirmStartSubTaskDialog +import com.mogo.och.sweepercloud.util.SweeperCloudTaskUtils.createReceivedTaskInfoDialog +import com.mogo.och.sweepercloud.util.SweeperCloudTaskUtils.createSweeperTaskEndDialog +import com.mogo.och.sweepercloud.util.SweeperCloudTaskUtils.createSweeperTaskNormalEndDialog +import com.mogo.och.sweepercloud.util.SweeperCloudTaskUtils.printMessage +import com.mogo.och.sweepercloud.view.SweeperCurrentTaskInfoView +import com.zhjt.mogo.adas.data.sweeper.SweeperCloudTask +import com.zhjt.mogo.adas.data.sweeper.bootable.SweeperBootable +import com.zhjt.mogo.adas.data.sweeper.common.SweeperCommon +import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask +import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask.SubTaskInfo +import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask.TaskModel +import com.zhjt.mogo.adas.data.sweeper.task.big.SweeperBigTaskStatus +import com.zhjt.mogo.adas.data.sweeper.task.confirm.SweeperTaskConfirm +import com.zhjt.mogo.adas.data.sweeper.task.stop.SweeperTaskStop +import kotlinx.android.synthetic.main.fragment_och_sweeper.* +import kotlinx.android.synthetic.main.sweeper_no_data_common_view.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +/** + * 清扫车主界面 + */ +class SweeperFragment : BaseSweeperTabFragment() { + + companion object { + const val TAG = "SweeperFragment" + } + + private var mSubMutableList: MutableList? = null + private var mCleanSystemState: ChassisStatesOuterClass.SweeperFuTianTaskSystemStates? = null + private var mLocation: MogoLocation? = null + private var mTaskInfo: SweeperTask.TaskInfo? = null + private var mSubTaskType: TaskModel = TaskModel.DEFAULT_MODEL //1:自动驾驶子任务 2:人工驾驶子任务 -1:未知任务类型 + private var mCurrentSubTaskInfo: SubTaskInfo? = null//当前正在执行的子任务 + private val mLoadingDialog: SweeperCloudLoadingDialog by lazy { SweeperCloudLoadingDialog(requireContext()) } + private var mDialog: SweeperCloudDialog? = null + + override fun getTagName(): String { + return "SweepersFragment" + } + + override fun initViews() { + super.initViews() + initListener() + sweeper_cl_work_mode.setTrafficDataView(trafficDataView) + } + + override fun createPresenter(): SweeperPresenter { + return SweeperPresenter(this) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + mPresenter?.getCurrentTask() + } + + override fun getTaskListPanelViewId(): Int { + return R.layout.fragment_och_sweeper + } + + /** + * 设置当前任务信息列表是否显示 + */ + private fun setShowCurrentTaskPanelView(isShow: Boolean) { + if (isShow) { + sweeper_current_task_view.visibility = View.VISIBLE + noTaskDataView.visibility = View.GONE + } else { + sweeper_current_task_view.visibility = View.GONE + noTaskDataView.visibility = View.VISIBLE + } + } + + /** + * VR模式切换 + * + * @param isVRMode + */ + fun onVRModeChanged(isVRMode: Boolean) { + if (mRootView != null) { + mRootView.visibility = if (isVRMode) View.VISIBLE else View.GONE + } + } + + fun hideOchSweeper() {} + + /** + * 设置各种监听事件 + */ + private fun initListener() { + getCurrentView().getAutoBtn().setOnClickListener { + //前置条件 (1)必须处于人工驾驶状态 (2)必须有正在执行的子任务,且子任务类型为自动驾驶子任务 才能请求云端进入自驾 + mCurrentSubTaskInfo?.let { + if (mPresenter?.autopilotState == STATUS_AUTOPILOT_ENABLE && it.taskModel == TaskModel.AUTO) { + mLoadingDialog.showLoading() + mPresenter?.sendSweeperAutopilotBootable(mTaskInfo?.taskId, it.subTaskId, it.lineId.toLong()) + } + } + } + } + + fun onSweeperFutianCleanSystemState(cleanSystemState: ChassisStatesOuterClass.SweeperFuTianTaskSystemStates) { + mCleanSystemState = cleanSystemState + sweeper_cl_work_mode.setSweeperFutianCleanSystemState(mSubTaskType, cleanSystemState) + } + + /** + * 当前位置经纬度 + */ + fun setCurrentLocation(location: MogoLocation) { + this.mLocation = location + } + + /** + * 大任务中所有子任务起终点集合 + */ + private fun addTaskData() { + lifecycleScope.launch(Dispatchers.IO) { + mSubMutableList?.let { subList -> + if (subList.size <= 0) { + return@launch + } + val dataList = ArrayList() + for (index in subList.indices) { + val startLocation = subList[index].startLocation + val startLatLng = LatLng(startLocation.latitude, startLocation.longitude) + dataList.add(index, startLatLng) + val endLocation = subList[index].endLocation + val endLatLng = LatLng(endLocation.latitude, endLocation.longitude) + dataList.add(index + 1, endLatLng) + } + setTaskListCoordinatesLatLng(dataList) + } + } + } + + /** + * 设置当前子任务终点 + */ + private fun setEndStationMarker(position: Int) { + lifecycleScope.launch(Dispatchers.IO) { + mSubMutableList?.let { subList -> + val endPoint = subList[position - 1].endLocation + val endLatLng = LatLng(endPoint.latitude, endPoint.longitude) + super.mCurrentTaskEndStation = endLatLng + setCurrentTaskEndMarker(endLatLng) + } + } + } + + /** + * 设置云端任务信息 + */ + fun onSweeperCloudTask(messageType: SweeperCloudTask.MessageType, taskInfo: SweeperTask.TaskInfo?) { + this.mTaskInfo = taskInfo + this.mSubMutableList = taskInfo?.subListList + CallerLogger.d(SceneConstant.M_SWEEPER + TAG, taskInfo?.let { printMessage(it) }) + if (taskInfo == null || this.mSubMutableList == null) { + resetTaskInfoPanel() + return + } + //主动拉取云端正在执行的任务,有则直接在任务列表展示 + if (messageType == SweeperCloudTask.MessageType.PadSendGetTaskReq) { + getCurrentView().setData(taskInfo, getCurrentPosition()) + setShowCurrentTaskPanelView(true) + addTaskData() + mPresenter?.isHasTaskInfo(true) + } else {//云端下发的任务信息需要弹窗接取 + if (taskInfo.isPop) {//是否需要弹窗确认 + receivedTaskInfoDialog() + } else { + mPresenter?.sendSweeperStartTaskResp(taskInfo.taskId, SweeperTask.StartTaskCode.RECEIVED) + setShowCurrentTaskPanelView(true) + getCurrentView().setData(taskInfo) + addTaskData() + mPresenter?.isHasTaskInfo(true) + //延时2秒再上报确认接取任务,防止时间太短跟收到任务指令冲突 + UiThreadHandler.postDelayed({ mPresenter?.sendSweeperStartTaskResp(taskInfo.taskId, SweeperTask.StartTaskCode.MANUAL_CONFIRM) }, 2000) + } + //设置任务进度 + this.mSubMutableList?.let { + setTaskProgress("0/${it.size}") + } + } + } + + /** + * 根据云端同步的子任务状态,更新列表中任务状态 + */ + fun onSweeperUpdateSubTaskStatus(taskId: String, subTaskId: String, subTaskStatus: SweeperCommon.TaskStatus) { + mLoadingDialog.hideLoading() + updateSubTaskInfo(taskId, subTaskId, subTaskStatus) + } + + /** + * 子任务确认时,更新子任务信息 + */ + private fun updateSubTaskInfo(taskId: String, subTaskId: String, subTaskStatus: SweeperCommon.TaskStatus) { + mTaskInfo?.let { + //如果云端要更新的任务和本地缓存任务不是同一个,在无法更新子任务状态 + if (taskId != it.taskId) { + return + } + mSubMutableList?.let { subTaskList -> + for (index in 0 until subTaskList.size) { + if (subTaskList[index].subTaskId == subTaskId) { + val subBuilder = subTaskList[index].toBuilder() + subBuilder.taskStatus = subTaskStatus + if (subTaskStatus == SweeperCommon.TaskStatus.RUNNING) { + mCurrentSubTaskInfo = subBuilder.build() + //更新当前正在执行的任务状态 + updateCurrentSubTaskInfo(index + 1) + } else { + mCurrentSubTaskInfo = null + } + //判断是否结束子任务 + if (subTaskStatus == SweeperCommon.TaskStatus.FINISHED) { + //已完成的计入任务进度,未完成的不计入 + ToastUtils.showLong("任务完成") + showNotice("任务完成") + } + val builder = it.toBuilder() + builder.setSubList(index, subBuilder.build()) + mTaskInfo = builder.build() + mSubMutableList = mTaskInfo?.subListList + getCurrentView().setData(mTaskInfo, index) + } + } + } + } + } + + /** + * 云端请求结束大任务 + */ + fun onSweeperCloudTaskStop(taskId: String, stopTaskType: SweeperTaskStop.StopTaskType, isPop: Boolean) { + mTaskInfo?.let { + //如果云端要更新的任务和本地缓存任务不是同一个,在无法结束任务 + if (taskId != it.taskId) { + return + } + if (isPop) { + sweeperCloudTaskStopDialog(taskId, stopTaskType, it) + } else { + mPresenter?.sendSweeperStopTaskResp(taskId, SweeperTaskStop.StopTaskCode.MANUAL_CONFIRM) + } + } + + } + + /** + * 结束任务弹窗处理 + */ + private fun sweeperCloudTaskStopDialog(taskId: String, stopTaskType: SweeperTaskStop.StopTaskType, taskInfo: SweeperTask.TaskInfo) { + mLoadingDialog.hideLoading() + val timeout: String = getTimeSpent(taskInfo.taskEndTime) + //数据重复导致连续弹窗 + if (mDialog != null && mDialog!!.isShowing) { + return + } + if (stopTaskType == SweeperTaskStop.StopTaskType.NORMAL) { + mPresenter?.isHasTaskInfo(false) + mDialog = sweeperCloudTaskNormalEndDialog() + showNotice("任务已结束") + } else { + mDialog = createSweeperTaskEndDialog(context, object : SweeperCloudDialogClickListener { + override fun onConfirm() { + mPresenter?.sendSweeperStopTaskResp(taskId, SweeperTaskStop.StopTaskCode.MANUAL_CONFIRM) + mLoadingDialog.showLoading() + //ToastUtils.showLong("确认") + } + + override fun onRefuseOrEnd() { + mPresenter?.sendSweeperStopTaskResp(taskId, SweeperTaskStop.StopTaskCode.MANUAL_REFUSE) + mLoadingDialog.showLoading() + //ToastUtils.showLong("拒绝") + } + + override fun onCountDownStop() { + mPresenter?.sendSweeperStopTaskResp(taskId, SweeperTaskStop.StopTaskCode.OVER_TIME) + mLoadingDialog.showLoading() + //ToastUtils.showLong("倒计时") + } + + override fun onNext() { + } + + }, stopTaskType, timeout) + } + mDialog?.show() + } + + /** + * 大任务结束弹窗 + */ + private fun sweeperCloudTaskNormalEndDialog(): SweeperCloudDialog? { + return createSweeperTaskNormalEndDialog(context, object : SweeperCloudDialogClickListener { + override fun onConfirm() { + ToastUtils.showLong("任务已结束") + resetTaskInfoPanel() + } + + override fun onRefuseOrEnd() { + + } + + override fun onCountDownStop() { + ToastUtils.showLong("任务已结束") + resetTaskInfoPanel() + } + + override fun onNext() { + + } + + }) + } + + /** + * 云端同步大任务状态 + */ + fun onSweeperCloudBigTaskStatus(taskId: String, subTaskStatus: SweeperBigTaskStatus.BigTaskStatus) { + //隐藏loading + mLoadingDialog.hideLoading() + mTaskInfo?.let { + //如果云端要更新的任务和本地缓存任务不是同一个,在无法进行任务列表状态更新 + if (it.taskId != taskId) { + return + } + //大任务处于取消状态 异常状态pad端都显示无任务列表 + if (subTaskStatus == SweeperBigTaskStatus.BigTaskStatus.CANCLE || subTaskStatus == SweeperBigTaskStatus.BigTaskStatus.ABNORMAL || subTaskStatus == SweeperBigTaskStatus.BigTaskStatus.FINISHED) { + mPresenter?.isHasTaskInfo(false) + //数据重复导致连续弹窗 + if (mDialog != null && mDialog!!.isShowing) { + return + } + mDialog = sweeperCloudTaskNormalEndDialog() + mDialog?.show() + showNotice("任务已结束") + } + } + } + + /** + * pad请求云端进入自动驾驶回调 + */ + fun onSweeperCloudAutopilotBootable(taskId: String, subTaskId: String, isBootableResp: SweeperBootable.IsBootableResp) { + mLoadingDialog.hideLoading() + //如果云端要更新的任务和本地缓存任务不是同一个,在无法进行任务列表状态更新 + mTaskInfo?.let { + if (it.taskId != taskId) { + return + } + if (isBootableResp.code == SweeperCommon.Code.SUCCEED) { + ToastUtils.showLong("上报云控成功") + } else { + ToastUtils.showLong("上报云控失败") + } + } + } + + /** + * 重置任务面板为无数据状态 + */ + private fun resetTaskInfoPanel() { + //清除任务缓存数据 + mPresenter?.clearRouteList() + lifecycleScope.launch(Dispatchers.IO) { + //清除任务地图绘制标记和作业路线 + clearAllMarkerAndPolyline() + //清除贴边数据缓存 + MyDataBase.getInstance().weltDataDao.deleteAllWeltData() + } + setShowCurrentTaskPanelView(false) + mTaskInfo = null + mCurrentSubTaskInfo = null + mSubMutableList = null + mSubTaskType = TaskModel.DEFAULT_MODEL + setTaskProgress("0") + } + + /** + * + * 获取当前正在执行的子任务在列表中的位置 + */ + private fun getCurrentPosition(): Int { + mSubMutableList = mTaskInfo?.subListList + mSubMutableList?.apply { + for (index in 0 until size) { + if (get(index).taskStatus == SweeperCommon.TaskStatus.RUNNING) { + mCurrentSubTaskInfo = get(index) + updateCurrentSubTaskInfo(index + 1) + return index + } + } + } + return -1 + } + + /** + * 根据子任务id获取子任务信息 + */ + private fun bySubTaskIdFindSubTaskInfo(subTaskId: String): SubTaskInfo? { + mSubMutableList = mTaskInfo?.subListList + mSubMutableList?.apply { + for (index in 0 until size) { + if (get(index).subTaskId == subTaskId) { + return get(index) + } + } + } + return null + } + + /** + * 更新当前子任务信息 + */ + private fun updateCurrentSubTaskInfo(position: Int) { + mCurrentSubTaskInfo?.let { + mSubTaskType = it.taskModel + mPresenter?.setSubtask(it.subTaskId, it.taskModel, it.lineId) + setEndStationMarker(position) + //设置任务进度 + this.mSubMutableList?.apply { + setTaskProgress("${position}/${size}") + } + } + } + + /** + * 设置路线轨迹 + */ + override fun setTaskRouteList(routeList: ArrayList) { + super.setTaskRouteList(routeList) + } + + private fun getCurrentView(): SweeperCurrentTaskInfoView = sweeper_current_task_view + + + fun handleSubTaskInfoDialog(taskId: String, subTaskId: String, isPop: Boolean) { + if (mTaskInfo == null) return + if (mTaskInfo?.taskId != taskId) return + val subInfo = bySubTaskIdFindSubTaskInfo(subTaskId) + subInfo?.let { + if (isPop) { + showSubTaskInfoDialog(taskId, subTaskId, it) + } else { + mPresenter?.sendSweeperTaskConfirmResp(taskId, subTaskId, SweeperTaskConfirm.TaskConfirmCode.MANUAL_CONFIRM) + //mPresenter?.setPreLineId(-1) + updateSubTaskInfo(taskId, subTaskId, SweeperCommon.TaskStatus.RUNNING) + } + } + } + + /** + * 云控下发子任务确认弹窗 + */ + private fun showSubTaskInfoDialog(taskId: String, subTaskId: String, subTaskInfo: SubTaskInfo) { + mLoadingDialog.hideLoading() + if (mTaskInfo == null) return + if (mTaskInfo?.taskId != taskId) return + //数据重复导致连续弹窗 + if (mDialog != null && mDialog!!.isShowing) { + return + } + mDialog = createConfirmStartSubTaskDialog(context, object : SweeperCloudDialogClickListener { + override fun onConfirm() { + //ToastUtils.showLong("确认") + mPresenter?.sendSweeperTaskConfirmResp(taskId, subTaskId, SweeperTaskConfirm.TaskConfirmCode.MANUAL_CONFIRM) + //mPresenter?.setPreLineId(-1) + updateSubTaskInfo(taskId, subTaskId, SweeperCommon.TaskStatus.RUNNING) + mLoadingDialog.showLoading() + } + + override fun onRefuseOrEnd() { + //ToastUtils.showLong("结束") + mPresenter?.sendSweeperTaskConfirmResp(taskId, subTaskId, SweeperTaskConfirm.TaskConfirmCode.MANUAL_REFUSE_ALL) + mLoadingDialog.showLoading() + } + + override fun onCountDownStop() { + //ToastUtils.showLong("倒计时结束") + mPresenter?.sendSweeperTaskConfirmResp(taskId, subTaskId, SweeperTaskConfirm.TaskConfirmCode.OVER_TIME) + mLoadingDialog.showLoading() + } + + override fun onNext() { + //ToastUtils.showLong("下一个") + mPresenter?.sendSweeperTaskConfirmResp(taskId, subTaskId, SweeperTaskConfirm.TaskConfirmCode.MANUAL_REFUSE_SINGLE) + mLoadingDialog.showLoading() + } + + }, subTaskInfo) + mDialog?.show() + showNotice("请确认是否执行任务") + } + + /** + * 接取云端任务弹窗 + */ + private fun receivedTaskInfoDialog() { + mTaskInfo?.let { + mPresenter?.sendSweeperStartTaskResp(it.taskId, SweeperTask.StartTaskCode.RECEIVED) + //数据重复导致连续弹窗 + if (mDialog != null && mDialog!!.isShowing) { + return + } + mDialog = createReceivedTaskInfoDialog(context, object : SweeperCloudDialogClickListener { + override fun onConfirm() { + //ToastUtils.showLong("确认") + mPresenter?.sendSweeperStartTaskResp(it.taskId, SweeperTask.StartTaskCode.MANUAL_CONFIRM) + setShowCurrentTaskPanelView(true) + getCurrentView().setData(it) + mLoadingDialog.showLoading() + addTaskData() + mPresenter?.isHasTaskInfo(true) + } + + override fun onRefuseOrEnd() { + //ToastUtils.showLong("拒绝") + mPresenter?.sendSweeperStartTaskResp(it.taskId, SweeperTask.StartTaskCode.MANUAL_REFUSE) + mLoadingDialog.showLoading() + resetTaskInfoPanel() + } + + override fun onCountDownStop() { + //ToastUtils.showLong("倒计时结束") + resetTaskInfoPanel() + mPresenter?.sendSweeperStartTaskResp(it.taskId, SweeperTask.StartTaskCode.OVER_TIME) + mLoadingDialog.showLoading() + } + + override fun onNext() { + + } + + }, it) + mDialog?.show() + showNotice("请确认是否接取任务") + } + + } + + /** + * 计算任务超时时间 + */ + private fun getTimeSpent(taskEndTime: Long): String { + + val timeLag: Long = System.currentTimeMillis() - taskEndTime + //天 + val day: Long = timeLag / (24 * 60 * 60 * 1000) + //小时 + val hour = (timeLag / (60 * 60 * 1000) - day * 24) + //分钟 + val minute = ((timeLag / (60 * 1000)) - day * 24 * 60 - hour * 60) + + if (day >= 1) { + return "${day}天${hour}时${minute}分钟" + } + if (hour >= 1) { + return "${hour}时${minute}分钟" + } + return "${minute}分钟" + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/WeltMapOverViewFragment.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/WeltMapOverViewFragment.kt new file mode 100644 index 0000000000..de471c94b8 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/fragment/WeltMapOverViewFragment.kt @@ -0,0 +1,129 @@ +package com.mogo.och.sweepercloud.fragment + +import android.os.Bundle +import com.amap.api.maps.model.LatLng +import com.mogo.commons.mvp.BaseFragment +import com.mogo.och.sweepercloud.R +import com.mogo.och.sweepercloud.bean.SweeperRoutePlanningUpdateReqBean +import com.mogo.och.sweepercloud.callback.ISweeperTaskDataToFragmentCallback +import com.mogo.och.sweepercloud.callback.IWeltMapSwitchToSmallCallback +import com.mogo.och.sweepercloud.database.bean.WeltDataBean +import kotlinx.android.synthetic.main.fragment_welt_map_overview.* +import kotlinx.android.synthetic.main.sweeper_welt_map_overview.* + +/** + * 作业任务全览图 + */ +class WeltMapOverViewFragment : BaseFragment(), ISweeperTaskDataToFragmentCallback { + private var mIWeltMapSwitchToSmallCallBack: IWeltMapSwitchToSmallCallback? = null + private var mFragment: SweeperFragment? = null + override fun getLayoutId(): Int = R.layout.fragment_welt_map_overview + override fun getTagName(): String { + return "WeltMapOverViewFragment" + } + + override fun initViews() { + + } + fun setWeltMapSwitchToSmallCallBack(iWeltMapSwitchToSmallCallback: IWeltMapSwitchToSmallCallback){ + this.mIWeltMapSwitchToSmallCallBack=iWeltMapSwitchToSmallCallback + } + fun setSweeperFragment(fragment: SweeperFragment){ + this.mFragment=fragment + mFragment?.setTaskDataToFragmentCallback(this) + } + override fun initViews(savedInstanceState: Bundle?) { + super.initViews(savedInstanceState) + weltMapOverView?.onCreateView(savedInstanceState) + sweeperSwitchToSmall.setOnClickListener { + mIWeltMapSwitchToSmallCallBack?.onWeltMapSwitchToSmall() + } + val bundle = arguments + if (bundle != null) { + val latLngs = bundle.getSerializable("subTaskCoordinates") as? ArrayList + val latLng = bundle.getParcelable("subTaskEndCoordinates") + val weltDataList = bundle.getSerializable("weltDataList") as? ArrayList + val routeList = bundle.getSerializable("routeList") as? ArrayList + val progress = bundle.getString("progress") + routeList?.let { + weltMapOverView?.setRouteList(it) + } + latLng?.let { + setCurrentTaskCoordinatesLatLng(it) + } + latLngs?.let { + setTaskListCoordinatesLatLng(it) + } + weltDataList?.let { + setWeltData(it,"0.0cm") + } + progress?.let { + weltMapOverView?.setProgress(progress) + } + } + + } + + companion object { + @JvmStatic + fun newInstance( + mIWeltMapSwitchToSmallCallBack: IWeltMapSwitchToSmallCallback, + mCurrentTaskEndStation:LatLng?, + weltDataList: ArrayList?, + latLngs: ArrayList?, + routeList: ArrayList?, + progress:String?, + sweeperFragment: SweeperFragment + ): WeltMapOverViewFragment { + val args = Bundle() + args.putSerializable("weltDataList", weltDataList) + args.putSerializable("subTaskCoordinates", latLngs) + args.putParcelable("subTaskEndCoordinates", mCurrentTaskEndStation) + args.putSerializable("routeList", routeList) + args.putString("progress", progress) + val fragment = WeltMapOverViewFragment() + fragment.setWeltMapSwitchToSmallCallBack(mIWeltMapSwitchToSmallCallBack) + fragment.setSweeperFragment(sweeperFragment) + fragment.arguments = args + return fragment + } + } + + override fun onPause() { + super.onPause() + weltMapOverView?.onPause() + } + + override fun onResume() { + super.onResume() + weltMapOverView?.onResume() + } + + override fun onDestroy() { + super.onDestroy() + weltMapOverView?.onDestroy() + } + override fun setTaskListCoordinatesLatLng(coordinatesLatLng: java.util.ArrayList) { + weltMapOverView?.setTaskListCoordinatesLatLng(coordinatesLatLng) + } + + override fun setCurrentTaskCoordinatesLatLng(coordinatesLatLng: LatLng) { + weltMapOverView?.setCurrentTaskCoordinatesLatLng(coordinatesLatLng) + } + + override fun clearAllMarkerAndPolyline() { + weltMapOverView?.clearAllMarkerAndPolyline() + } + + override fun setProgress(progress: String) { + weltMapOverView?.setProgress(progress) + } + + override fun setRouteList(routeList: java.util.ArrayList) { + weltMapOverView?.setRouteList(routeList) + } + + override fun setWeltData(weltDatas: java.util.ArrayList?, distance: String) { + weltMapOverView?.setWeltData(weltDatas,true,distance) + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/model/SweeperTaskModel.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/model/SweeperTaskModel.java new file mode 100644 index 0000000000..bcacdb6ffb --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/model/SweeperTaskModel.java @@ -0,0 +1,661 @@ +package com.mogo.och.sweepercloud.model; + +import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_SWEEPER; +import static com.mogo.och.sweepercloud.util.SweeperCloudTaskUtils.printMessage; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.amap.api.maps.model.LatLng; +import com.mogo.cloud.passport.MoGoAiCloudClientConfig; +import com.mogo.commons.AbsMogoApplication; +import com.mogo.commons.module.status.IMogoStatusChangedListener; +import com.mogo.commons.module.status.MogoStatusManager; +import com.mogo.commons.module.status.StatusDescriptor; +import com.mogo.eagle.core.data.autopilot.AutopilotStatusInfo; +import com.mogo.eagle.core.data.map.MogoLocation; +import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; +import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener; +import com.mogo.eagle.core.function.api.autopilot.IMoGoPlanningRottingListener; +import com.mogo.eagle.core.function.api.autopilot.IMoGoSweeperFutianCleanSystemListener; +import com.mogo.eagle.core.function.api.autopilot.IMoGoSweeperFutianCloudTaskListener; +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.function.call.autopilot.CallerPlanningRottingListenerManager; +import com.mogo.eagle.core.function.call.autopilot.CallerSweeperFutianCleanSystemListenerManager; +import com.mogo.eagle.core.function.call.autopilot.CallerSweeperFutianCloudTaskListenerManager; +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; +import com.mogo.och.common.module.manager.OCHAdasAbilityManager; +import com.mogo.och.common.module.utils.CoordinateCalculateRouteUtil; +import com.mogo.och.common.module.utils.NumberFormatUtil; +import com.mogo.och.sweepercloud.bean.SweeperRoutePlanningUpdateReqBean; +import com.mogo.och.sweepercloud.callback.ISweeperCloudTaskCallback; +import com.mogo.och.sweepercloud.callback.ISweeperControllerStatusCallback; +import com.mogo.och.sweepercloud.constant.SweeperConst; +import com.mogo.och.sweepercloud.database.MyDataBase; +import com.mogo.och.sweepercloud.database.bean.WeltDataBean; +import com.mogo.och.sweepercloud.util.SweeperCloudTaskUtils; +import com.zhjt.mogo.adas.data.sweeper.SweeperCloudTask; +import com.zhjt.mogo.adas.data.sweeper.bootable.SweeperBootable; +import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask; +import com.zhjt.mogo.adas.data.sweeper.task.SweeperTaskSuspendResume; +import com.zhjt.mogo.adas.data.sweeper.task.big.SweeperBigTaskStatus; +import com.zhjt.mogo.adas.data.sweeper.task.confirm.SweeperTaskConfirm; +import com.zhjt.mogo.adas.data.sweeper.task.status.SweeperTaskStatus; +import com.zhjt.mogo.adas.data.sweeper.task.stop.SweeperTaskStop; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import chassis.ChassisStatesOuterClass; +import io.reactivex.exceptions.UndeliverableException; +import io.reactivex.functions.Consumer; +import io.reactivex.plugins.RxJavaPlugins; +import mogo.telematics.pad.MessagePad; +import mogo_msg.MogoReportMsg; +import planning.RoboSweeperTaskIndexOuterClass; +import system_master.SystemStatusInfo; + +/** + * @author congtaowang + * @since 2021/3/23 + *

+ * 清扫车任务管理 + */ +public class SweeperTaskModel implements IMoGoSweeperFutianCloudTaskListener, IMoGoAutopilotStatusListener, IMoGoSweeperFutianCleanSystemListener { + private final String TAG = SweeperTaskModel.class.getSimpleName(); + private static volatile SweeperTaskModel sInstance; + public double mLongitude = 0; + public double mLatitude = 0; + private Context mContext; + private ISweeperControllerStatusCallback mControllerStatusCallback; //Model->Presenter:VR mode等 + private ISweeperCloudTaskCallback mSweeperTaskCallback; + ArrayList points = new ArrayList<>();//全路径信息 + private SweeperTask.TaskModel mSubTaskType = SweeperTask.TaskModel.DEFAULT_MODEL; //1自动驾驶 2.人工驾驶 0:无效值 + private int mCurrentLineId = 0; //当前路线id + private int mPreLineId = -1;//上一次存储的路线id + //自动驾驶状态 + private int mAutopilotState = IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE; + //当前子任务id + private String mSubTaskId = ""; + // 清扫模式回调时间间隔 + private static final long VEHICLE_STATE_INTERVAL_MILLIS = 500L; + // 清扫模式当前时间戳 + private long mVehicleStateCurrentTimeMillis; + // 贴边数据回调时间间隔 + private static final long WELT_DATA_INTERVAL_MILLIS = 1000L; + // 贴边数据当前时间戳 + private long mWeltDataCurrentTimeMillis; + + // 轨迹数据回调时间间隔 + private static final long ROUTE_DATA_INTERVAL_MILLIS = 1000L; + // 轨迹数据当前时间戳 + private long mRouteDataCurrentTimeMillis; + + private String longitude;//经度 + + private String latitude;//纬度 + + private boolean isHasTaskInfo = false;//判断是否有任务数据 + + //用于对应messageType和reqNo绑定在一起,保证请求的reqNo和响应的reqNo一致 + private HashMap msgTypeAndReqNo = new HashMap<>(); + + public static SweeperTaskModel getInstance() { + if (sInstance == null) { + synchronized (SweeperTaskModel.class) { + if (sInstance == null) { + sInstance = new SweeperTaskModel(); + } + } + } + return sInstance; + } + + private SweeperTaskModel() { + + } + + public void init() { + mContext = AbsMogoApplication.getApp(); + // 定位监听 + CallerChassisLocationGCJ02ListenerManager.INSTANCE.addListener(TAG, mMapLocationListener); + + MogoStatusManager.getInstance().registerStatusChangedListener(TAG, StatusDescriptor.VR_MODE, mMogoStatusChangedListener); + + //自动驾驶路线规划接口 + CallerPlanningRottingListenerManager.INSTANCE.addListener(TAG, moGoAutopilotPlanningListener); + + //添加清扫车云控任务回调监听 + CallerSweeperFutianCloudTaskListenerManager.INSTANCE.addListener(TAG, this); + + //自动驾驶状态监听 + CallerAutoPilotStatusListenerManager.INSTANCE.addListener(TAG, this); + + //清扫车模式和贴边数据回调监听 + CallerSweeperFutianCleanSystemListenerManager.INSTANCE.addListener(TAG, this); + + //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.INSTANCE.d(M_SWEEPER + TAG, "UndeliverableException"); + } + if ((e instanceof IOException)) {// + // fine, irrelevant network problem or API that throws on cancellation + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "IOException"); + return; + } + if (e instanceof InterruptedException) { + // fine, some blocking code was interrupted by a dispose call + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "InterruptedException"); + return; + } + if ((e instanceof NullPointerException) || (e instanceof IllegalArgumentException)) { + // that's likely a bug in the application + CallerLogger.INSTANCE.d(M_SWEEPER + 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.INSTANCE.d(M_SWEEPER + TAG, "IllegalStateException"); + Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e); + return; + } + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "Undeliverable exception"); + } + }); + } + + + public void setControllerStatusCallback(ISweeperControllerStatusCallback callback) { + this.mControllerStatusCallback = callback; + } + + public void setSweeperTaskCallback(ISweeperCloudTaskCallback callback) { + this.mSweeperTaskCallback = callback; + } + + private final IMoGoPlanningRottingListener moGoAutopilotPlanningListener = new IMoGoPlanningRottingListener() { + + @Override + public void onAutopilotRotting(MessagePad.GlobalPathResp routeList) { + if (null != routeList && routeList.getWayPointsList() != null && routeList.getWayPointsList().size() > 0) { + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onAutopilotRotting: " + printMessage(routeList)); + + // MAP返回路线信息,在1秒内返回了2次,这里加上数据过滤 + long current = System.currentTimeMillis(); + if (current - mRouteDataCurrentTimeMillis <= ROUTE_DATA_INTERVAL_MILLIS) { + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onAutopilotRotting: interval <=" + ROUTE_DATA_INTERVAL_MILLIS + " data is abandon"); + return; + } + mRouteDataCurrentTimeMillis = current; + + if (mCurrentLineId != mPreLineId) {//判断是否同一条路线 + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onAutopilotRotting: mCurrentLineId" + mCurrentLineId + "mPreLineId:" + mPreLineId); + mPreLineId = mCurrentLineId; + points.addAll(coordinateConverterWgsToGcjList(mContext, routeList.getWayPointsList())); + if (mSweeperTaskCallback != null) { + mSweeperTaskCallback.setRouteList(points); + } + } + } + } + + }; + + public void setSubtask(String subTaskId, SweeperTask.TaskModel subTaskType, int currentLineId) { + this.mSubTaskId = subTaskId; + this.mSubTaskType = subTaskType; + this.mCurrentLineId = currentLineId; + } + + /** + * 清除路线缓存数据 + */ + public void clearRouteList() { + points.clear(); + mSubTaskType = SweeperTask.TaskModel.UNRECOGNIZED; + mCurrentLineId = 0; + mPreLineId = -1; + } + + /** + * 重新设置上一次的lineId,防止同一个轨迹,同一个lineid时不绘制轨迹 + */ + public void setPreLineId(int preLineId) { + this.mPreLineId = preLineId; + } + + /** + * 判断是否有任务数据 + */ + public void isHasTaskInfo(boolean isHasTaskInfo) { + this.isHasTaskInfo = isHasTaskInfo; + } + + /** + * 获取自动开始状态 + */ + public int getAutopilotState() { + return this.mAutopilotState; + } + + public static List coordinateConverterWgsToGcjList(Context mContext, + List mogoLatLngList) { + List points = new ArrayList<>(); + for (MessagePad.Location m : mogoLatLngList) { + LatLng mogoLatLng = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj(mContext, m); + SweeperRoutePlanningUpdateReqBean.Result result = new SweeperRoutePlanningUpdateReqBean.Result(); + result.latitude = mogoLatLng.latitude; + result.longitude = mogoLatLng.longitude; + points.add(result); + } + return points; + } + + public void release() { + MogoStatusManager.getInstance().unregisterStatusChangedListener(TAG, StatusDescriptor.VR_MODE, mMogoStatusChangedListener); + // 注销定位监听 + CallerChassisLocationGCJ02ListenerManager.INSTANCE.removeListener(TAG); + //自动驾驶路线规划接口 + CallerPlanningRottingListenerManager.INSTANCE.removeListener(moGoAutopilotPlanningListener); + OCHAdasAbilityManager.getInstance().setAdasStartFailureCallback(null); + } + + private Object readResolve() { + // 阻止反序列化,必须实现 Serializable 接口 + return sInstance; + } + + private final IMogoStatusChangedListener mMogoStatusChangedListener = new IMogoStatusChangedListener() { + // VR mode变更回调 + @Override + public void onStatusChanged(StatusDescriptor descriptor, boolean isTrue) { + if (StatusDescriptor.VR_MODE == descriptor) { + if (mControllerStatusCallback != null) { + mControllerStatusCallback.onVRModeChanged(isTrue); + } + } + } + }; + // 自车定位 + private final IMoGoChassisLocationGCJ02Listener mMapLocationListener = new IMoGoChassisLocationGCJ02Listener() { + @Override + public void onChassisLocationGCJ02(@Nullable MogoLocation gnssInfo) { + if (null == gnssInfo) return; + if (mControllerStatusCallback != null) { + mControllerStatusCallback.onCarLocationChanged(gnssInfo); + } + if (mSubTaskType == SweeperTask.TaskModel.MANUAL) {//收集人工驾驶子任务坐标点 + addCoordinates(gnssInfo); + return; + } + } + }; + + /** + * 根据当前定位收集人工驾驶子任务轨迹点 + * + * @param mogoLatLng + */ + private void addCoordinates(MogoLocation mogoLatLng) { + String tempLongitude = NumberFormatUtil.cutOutNumber(mogoLatLng.getLongitude(), 5); + String tempLatitude = NumberFormatUtil.cutOutNumber(mogoLatLng.getLatitude(), 5); + //用于过滤车是否停在原地,经纬度相同的情况 + if (!tempLongitude.equals(mLongitude) && !tempLatitude.equals(mLatitude)) { + mLongitude = mogoLatLng.getLongitude(); + mLatitude = mogoLatLng.getLatitude(); + SweeperRoutePlanningUpdateReqBean.Result result = new SweeperRoutePlanningUpdateReqBean.Result(); + result.latitude = mogoLatLng.getLatitude(); + result.longitude = mogoLatLng.getLongitude(); + points.add(result); + if (mSweeperTaskCallback != null) { + mSweeperTaskCallback.setRouteList(points); + } + } + } + + @Override + public void onSweeperFutianCloudTask(@NonNull SweeperCloudTask.MessageType messageType, String reqNo, long sysTime, + SweeperTask.TaskInfo taskInfo) { + + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, + "messageType: " + messageType.getNumber() + " sysTime:" + sysTime + " reqNo:" + reqNo + " onSweeperFutianCloudTask:" + (taskInfo == null ? "null" : printMessage(taskInfo)) + " mSweeperTaskCallback:" + mSweeperTaskCallback); + if (mSweeperTaskCallback != null) { + msgTypeAndReqNo.put(messageType.getNumber(), reqNo); + mSweeperTaskCallback.onSweeperCloudTask(messageType, taskInfo); + } + } + + @Override + public void onSweeperFutianCloudTaskConfirm(@NonNull SweeperCloudTask.MessageType messageType, String reqNo, long sysTime, + SweeperTaskConfirm.TaskConfirm taskConfirm) { + + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "messageType: " + messageType.getNumber() + " sysTime:" + sysTime + " reqNo:" + reqNo + " " + + "onSweeperFutianCloudTaskConfirm:" + printMessage(taskConfirm)); + if (mSweeperTaskCallback != null && taskConfirm != null) { + msgTypeAndReqNo.put(messageType.getNumber(), reqNo); + mSweeperTaskCallback.onSweeperCloudTaskConfirm(taskConfirm.getTaskId(), taskConfirm.getSubTaskId(), taskConfirm.getIsPop()); + } + } + + @Override + public void onSweeperFutianCloudTaskStatus(@NonNull SweeperCloudTask.MessageType messageType, String reqNo, long sysTime, + SweeperTaskStatus.TaskStatusPush taskStatusPush) { + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "messageType: " + messageType.getNumber() + " sysTime:" + sysTime + " reqNo:" + reqNo + " " + + "onSweeperFutianCloudTaskStatus:" + printMessage(taskStatusPush)); + if (mSweeperTaskCallback != null && taskStatusPush != null) { + msgTypeAndReqNo.put(messageType.getNumber(), reqNo); + mSweeperTaskCallback.onSweeperCloudTaskStatus(taskStatusPush.getTaskId(), taskStatusPush.getSubTaskId(), taskStatusPush.getTaskStatus()); + } + } + + @Override + public void onSweeperFutianCloudTaskStop(@NonNull SweeperCloudTask.MessageType messageType, String reqNo, long sysTime, + SweeperTaskStop.StopTaskReq stopTaskReq) { + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "messageType: " + messageType.getNumber() + " sysTime:" + sysTime + " reqNo:" + reqNo + " " + + "onSweeperFutianCloudTaskStop:" + printMessage(stopTaskReq)); + if (mSweeperTaskCallback != null && stopTaskReq != null) { + msgTypeAndReqNo.put(messageType.getNumber(), reqNo); + mSweeperTaskCallback.onSweeperCloudTaskStop(stopTaskReq.getTaskId(), stopTaskReq.getType(), stopTaskReq.getIsPop()); + } + } + + @Override + public void onSweeperFutianCloudTaskSuspendResume(@NonNull SweeperCloudTask.MessageType messageType, String reqNo, long sysTime, + SweeperTaskSuspendResume.SuspendResumeTaskResp suspendResumeTaskResp) { + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "messageType: " + messageType.getNumber() + " sysTime:" + sysTime + " reqNo:" + reqNo + " " + + "onSweeperFutianCloudTaskSuspendResume:" + printMessage(suspendResumeTaskResp)); + if (mSweeperTaskCallback != null && suspendResumeTaskResp != null) { + msgTypeAndReqNo.put(messageType.getNumber(), reqNo); + mSweeperTaskCallback.onSweeperCloudTaskSuspendResume(messageType, suspendResumeTaskResp.getTaskId(), + suspendResumeTaskResp.getSubTaskId(), suspendResumeTaskResp.getCode()); + } + } + + @Override + public void onSweeperFutianCloudBootable(@NonNull SweeperCloudTask.MessageType messageType, String reqNo, long sysTime, + SweeperBootable.IsBootableResp isBootableResp) { + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "messageType: " + messageType.getNumber() + " sysTime:" + sysTime + " reqNo:" + reqNo + " " + + "onSweeperFutianCloudBootable:" + printMessage(isBootableResp)); + if (mSweeperTaskCallback != null && isBootableResp != null) { + msgTypeAndReqNo.put(messageType.getNumber(), reqNo); + mSweeperTaskCallback.onSweeperCloudBootable(isBootableResp.getTaskId(), isBootableResp.getSubTaskId(), isBootableResp); + } + } + + @Override + public void onSweeperFutianCloudBigTaskStatus(@NonNull SweeperCloudTask.MessageType messageType, String reqNo, long sysTime, + SweeperBigTaskStatus.BigTaskStatusPush bigTaskStatusPush) { + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "messageType: " + messageType.getNumber() + " sysTime:" + sysTime + " reqNo:" + reqNo + " " + + "onSweeperFutianCloudBigTaskStatus:" + printMessage(bigTaskStatusPush)); + if (mSweeperTaskCallback != null && bigTaskStatusPush != null) { + msgTypeAndReqNo.put(messageType.getNumber(), reqNo); + mSweeperTaskCallback.onSweeperCloudBigTaskStatus(bigTaskStatusPush.getTaskId(), bigTaskStatusPush.getTaskStatus()); + } + } + + @Override + public void onSweeperFutianCleanSystemState(@NonNull ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) { + if (cleanSystemState == null) { + return; + } + long current = System.currentTimeMillis(); + if (current - mVehicleStateCurrentTimeMillis <= VEHICLE_STATE_INTERVAL_MILLIS) { + return; + } + mVehicleStateCurrentTimeMillis = current; + // CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onSweeperFutianCleanSystemState:" + printMessage(cleanSystemState)); + if (mSweeperTaskCallback != null) { + mSweeperTaskCallback.onSweeperFutianCleanSystemState(cleanSystemState); + } + } + + @Override + public void onSweeperFutianTaskIndexData(@NonNull RoboSweeperTaskIndexOuterClass.RoboSweeperTaskIndex roboSweeperTaskIndex) { + if (roboSweeperTaskIndex == null) { + return; + } + + long current = System.currentTimeMillis(); + if (current - mWeltDataCurrentTimeMillis <= WELT_DATA_INTERVAL_MILLIS) { + return; + } + mWeltDataCurrentTimeMillis = current; + + //没有任务数据时,不处理贴边 + if (!isHasTaskInfo) { + return; + } + + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, + "mSubTaskType:" + mSubTaskType + "+ onSweeperFutianTaskIndexData:" + printMessage(roboSweeperTaskIndex)); + handleWeltData(roboSweeperTaskIndex); + } + + /** + * 贴边数据处理 + */ + private void handleWeltData(RoboSweeperTaskIndexOuterClass.RoboSweeperTaskIndex roboSweeperTaskIndex) { + String tempLongitude = NumberFormatUtil.cutOutNumber(roboSweeperTaskIndex.getLocLon(), 6); + String tempLatitude = NumberFormatUtil.cutOutNumber(roboSweeperTaskIndex.getLocLat(), 6); + //用于过滤车是否停在原地,经纬度相同的情况 + if (!tempLongitude.equals(longitude) && !tempLatitude.equals(latitude)) { + latitude = NumberFormatUtil.cutOutNumber(roboSweeperTaskIndex.getLocLat(), 6); + longitude = NumberFormatUtil.cutOutNumber(roboSweeperTaskIndex.getLocLon(), 6); + //保存贴边数据到数据库中 + WeltDataBean weltDataBean = new WeltDataBean(); + //把wgs坐标系坐标转换成gcj坐标 + LatLng latLng = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj(AbsMogoApplication.getApp(), roboSweeperTaskIndex.getLocLon(), + roboSweeperTaskIndex.getLocLat()); + weltDataBean.setLocLon(latLng.longitude); + weltDataBean.setLocLat(latLng.latitude); + int edgeCleanState = roboSweeperTaskIndex.getEdgeCleanState(); + if (edgeCleanState == 0 || + (mSubTaskType == SweeperTask.TaskModel.MANUAL)) { + //人工子任务 当前因为云控需求时MAP不能获取任务状态,在人工子任务时还是返回的上一个任务的贴边数据 + // 所以 20230529 暂时过滤掉,待后面MAP修改后这里可删除,这里人工子任务默认都是非贴边 + weltDataBean.setWeltDistance(SweeperConst.NONWELT); + } else { + weltDataBean.setWeltDistance(roboSweeperTaskIndex.getDistToRefEdgePoint()); + } + weltDataBean.setCleanMode(roboSweeperTaskIndex.getCleanMode()); + weltDataBean.setCleanDirection(roboSweeperTaskIndex.getCleanDirection()); + weltDataBean.setCleanIntensity(roboSweeperTaskIndex.getCleanIntensity()); + weltDataBean.setSubTaskId(mSubTaskId); + MyDataBase.getInstance().getWeltDataDao().insert(weltDataBean); + String distance; + if (roboSweeperTaskIndex.getDistToRefEdgePoint() >= 1.0) {//大于等于1m + distance = format(roboSweeperTaskIndex.getDistToRefEdgePoint()) + "m"; + } else {//小于1m + distance = Math.round(roboSweeperTaskIndex.getDistToRefEdgePoint() * 100) + "cm";//m->cm 四舍五入到整数 + } + if (mSweeperTaskCallback != null) { + mSweeperTaskCallback.setWeltDataToMap((ArrayList) MyDataBase.getInstance().getWeltDataDao().loadAllWeltDataInfo(), + true, distance); + } + } + } + + public static String format(double value) { + BigDecimal bd = new BigDecimal(value); + bd = bd.setScale(2, RoundingMode.HALF_UP); + return bd.toString(); + } + + /** + * 获取当前正在执行的任务 + */ + public void getCurrentTask() { + SweeperTask.GetTaskReq.Builder builder = SweeperTask.GetTaskReq.newBuilder(); + builder.setSn(getDriverSn()); + String reqNo = SweeperCloudTaskUtils.getRequestId(); + SweeperTask.GetTaskReq getTaskReq = builder.build(); + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, + "getCurrentTask:" + printMessage(getTaskReq) + " reqNo:" + reqNo + " messageType:" + SweeperCloudTask.MessageType.PadSendGetTaskReq.getNumber()); + getAutoPilotControlManager().sendSweeperGetTaskReq(reqNo, getTaskReq); + } + + /** + * 接取任务响应 + */ + public void sendSweeperStartTaskResp(String taskId, SweeperTask.StartTaskCode code) { + SweeperTask.StartTaskResp.Builder builder = SweeperTask.StartTaskResp.newBuilder(); + builder.setSn(getDriverSn()); + builder.setTaskId(taskId); + builder.setCode(code); + SweeperTask.StartTaskResp startTaskResp = builder.build(); + String reqNo = msgTypeAndReqNo.get(SweeperCloudTask.MessageType.CloudPushTask.getNumber()); + getAutoPilotControlManager().sendSweeperStartTaskResp(reqNo, startTaskResp); + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, + "sendSweeperStartTaskResp:" + printMessage(startTaskResp) + " reqNo:" + reqNo + " messageType:" + SweeperCloudTask.MessageType.CloudPushTask.getNumber()); + } + + /** + * 子任务开始确认 + */ + public void sendSweeperTaskConfirmResp(String taskId, String subTaskId, SweeperTaskConfirm.TaskConfirmCode code) { + SweeperTaskConfirm.TaskConfirmResp.Builder builder = SweeperTaskConfirm.TaskConfirmResp.newBuilder(); + builder.setSn(getDriverSn()); + builder.setTaskId(taskId); + builder.setSubTaskId(subTaskId); + builder.setCode(code); + SweeperTaskConfirm.TaskConfirmResp taskConfirmResp = builder.build(); + String reqNo = msgTypeAndReqNo.get(SweeperCloudTask.MessageType.CloudPushTaskConfirm.getNumber()); + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, + "sendSweeperTaskConfirmResp" + printMessage(taskConfirmResp) + " reqNo:" + reqNo + " messageType:" + SweeperCloudTask.MessageType.CloudPushTaskConfirm.getNumber()); + getAutoPilotControlManager().sendSweeperTaskConfirmResp(reqNo, taskConfirmResp); + } + + /** + * 大任务结束确认 + * + * @param taskId + * @param code + */ + public void sendSweeperStopTaskResp(String taskId, SweeperTaskStop.StopTaskCode code) { + SweeperTaskStop.StopTaskResp.Builder builder = SweeperTaskStop.StopTaskResp.newBuilder(); + builder.setSn(getDriverSn()); + builder.setTaskId(taskId); + builder.setCode(code); + SweeperTaskStop.StopTaskResp stopTaskResp = builder.build(); + String reqNo = msgTypeAndReqNo.get(SweeperCloudTask.MessageType.CloudPushTaskStop.getNumber()); + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, + "sendSweeperStopTaskResp" + printMessage(stopTaskResp) + " reqNo:" + reqNo + " messageType:" + SweeperCloudTask.MessageType.CloudPushTaskStop.getNumber()); + getAutoPilotControlManager().sendSweeperStopTaskResp(reqNo, stopTaskResp); + } + + /** + * pad上报是否可以进自驾 + * + * @param taskId + * @param subTaskId + * @param lineId + */ + public void sendSweeperAutopilotBootable(String taskId, String subTaskId, long lineId) { + SweeperBootable.IsBootable.Builder builder = SweeperBootable.IsBootable.newBuilder(); + builder.setSn(getDriverSn()); + builder.setTaskId(taskId); + builder.setSubTaskId(subTaskId); + builder.setLineId(lineId); + SweeperBootable.IsBootable isBootable = builder.build(); + String reqNo = SweeperCloudTaskUtils.getRequestId(); + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, + "sendSweeperAutopilotBootable" + printMessage(isBootable) + " reqNo:" + reqNo + " messageType:" + SweeperCloudTask.MessageType.PadSendBootable.getNumber()); + getAutoPilotControlManager().sendSweeperAutopilotBootable(reqNo, isBootable); + // TODO: 2023/5/16 + //SweeperCloudTaskUtils.mockSendCloudBootable(); + } + + public CallerAutoPilotControlManager getAutoPilotControlManager() { + return CallerAutoPilotControlManager.INSTANCE; + } + + public String getDriverSn() { + return MoGoAiCloudClientConfig.getInstance().getSn(); + } + + @Override + public void onAutopilotStatusResponse(@NonNull AutopilotStatusInfo autoPilotStatusInfo) { + //CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onAutopilotStatusResponse state:" + autoPilotStatusInfo.getState()); + this.mAutopilotState = autoPilotStatusInfo.getState(); + if (mControllerStatusCallback != null) { + mControllerStatusCallback.onAutopilotState(autoPilotStatusInfo.getState()); + } + switch (autoPilotStatusInfo.getState()) { + case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE://不可自动驾驶 + break; + case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE://人工驾驶 + break; + case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING://自动驾驶中 + break; + case IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING://平行驾驶 + break; + default: + break; + } + } + + @Override + public void onAutopilotArriveAtStation(@Nullable MessagePad.ArrivalNotification arrivalNotification) { + + } + + @Override + public void onAutopilotSNRequest() { + + } + + @Override + public void onAutopilotGuardian(@Nullable MogoReportMsg.MogoReportMessage guardianInfo) { + + } + + @Override + public void onAutopilotIpcConnectStatusChanged(int status, @Nullable String reason) { + if (status == 0x00) {//判断工控机重连后,获取当前正在执行的子任务,延时10秒,防止工控机连接上时SN为空 + UiThreadHandler.postDelayed(() -> { + getCurrentTask(); + }, 10000); + } + //CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onAutopilotIpcConnectStatusChanged status:" + status + " reason:" + reason); + } + + @Override + public void onAutopilotStatusRespByQuery(@NonNull SystemStatusInfo.StatusInfo status) { + // CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onAutopilotStatusRespByQuery status:" + status.getSysState().getNumber()); + } + + @Override + public void onAutopilotRouteLineId(long lineId) { + + } + + /** + * 云控数据异常或者工控机传递数据异常 + * + * @param bytes + */ + @Override + public void onSweeperFutianCloudTaskUnknown(@NonNull byte[] bytes) { + String string = new String(bytes, StandardCharsets.UTF_8); + CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onSweeperFutianCloudTaskUnknown:" + string); + } + +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/presenter/SweeperPresenter.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/presenter/SweeperPresenter.java new file mode 100644 index 0000000000..c454c5e66f --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/presenter/SweeperPresenter.java @@ -0,0 +1,228 @@ +package com.mogo.och.sweepercloud.presenter; + + +import com.mogo.commons.AbsMogoApplication; +import com.mogo.commons.mvp.Presenter; +import com.mogo.eagle.core.data.map.MogoLocation; +import com.mogo.eagle.core.function.call.autopilot.CallerSweeperFutianCleanSystemListenerManager; +import com.mogo.eagle.core.utilcode.util.ThreadUtils; +import com.mogo.och.common.module.manager.OCHAdasAbilityManager; +import com.mogo.och.sweepercloud.bean.SweeperRoutePlanningUpdateReqBean; +import com.mogo.och.sweepercloud.callback.ISweeperControllerStatusCallback; +import com.mogo.och.sweepercloud.callback.ISweeperCloudTaskCallback; +import com.mogo.och.sweepercloud.callback.ISweeperTaskRouteCallback; +import com.mogo.och.sweepercloud.database.bean.WeltDataBean; +import com.mogo.och.sweepercloud.fragment.SweeperFragment; +import com.mogo.och.sweepercloud.model.SweeperTaskModel; +import com.zhjt.mogo.adas.data.sweeper.SweeperCloudTask; +import com.zhjt.mogo.adas.data.sweeper.bootable.SweeperBootable; +import com.zhjt.mogo.adas.data.sweeper.common.SweeperCommon; +import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask; +import com.zhjt.mogo.adas.data.sweeper.task.big.SweeperBigTaskStatus; +import com.zhjt.mogo.adas.data.sweeper.task.confirm.SweeperTaskConfirm; +import com.zhjt.mogo.adas.data.sweeper.task.stop.SweeperTaskStop; + + +import java.util.ArrayList; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LifecycleOwner; +import chassis.ChassisStatesOuterClass; + +/** + * 网约车小巴 + * + * @author tongchenfei + */ +public class SweeperPresenter extends Presenter + implements ISweeperControllerStatusCallback, + ISweeperCloudTaskCallback, ISweeperTaskRouteCallback { + + private static final String TAG = "SweeperPresenter"; + + public SweeperPresenter(SweeperFragment view) { + super(view); + SweeperTaskModel.getInstance().init(); + OCHAdasAbilityManager.getInstance().init(AbsMogoApplication.getApp()); + } + + @Override + public void onCreate(@NonNull LifecycleOwner owner) { + super.onCreate(owner); + initModelListener(); + } + + @Override + public void onDestroy(@NonNull LifecycleOwner owner) { + super.onDestroy(owner); + SweeperTaskModel.getInstance().release(); + releaseListener(); + } + + public void initModelListener() { + SweeperTaskModel.getInstance().setControllerStatusCallback(this); + SweeperTaskModel.getInstance().setSweeperTaskCallback(this); + } + + public void releaseListener() { + SweeperTaskModel.getInstance().setControllerStatusCallback(null); + SweeperTaskModel.getInstance().setSweeperTaskCallback(null); + CallerSweeperFutianCleanSystemListenerManager.INSTANCE.removeListener(TAG); + } + + @Override + public void onVRModeChanged(boolean isVRMode) { + ThreadUtils.runOnUiThread(() -> mView.onVRModeChanged(isVRMode)); + } + + @Override + public void onCarLocationChanged(MogoLocation location) { + if (null != location) { + ThreadUtils.runOnUiThread(() -> mView.updateSpeedView((float) location.getGnssSpeed())); + ThreadUtils.runOnUiThread(() -> mView.setCurrentLocation(location)); + } + } + + @Override + public void onAutopilotState(int state) { + ThreadUtils.runOnUiThread(() -> mView.setAutoState(state)); + } + + /** + * 获取自动驾驶状态 + * + * @return + */ + public int getAutopilotState() { + return SweeperTaskModel.getInstance().getAutopilotState(); + } + + /** + * 清除路线缓存数据 + */ + public void clearRouteList() { + SweeperTaskModel.getInstance().clearRouteList(); + } + + /** + * 设置当前子任务信息 + */ + public void setSubtask(String subTaskId, SweeperTask.TaskModel subTaskType, int currentLineId) { + SweeperTaskModel.getInstance().setSubtask(subTaskId, subTaskType, currentLineId); + } + + /** + * 判断是否有任务数据 + */ + public void isHasTaskInfo(boolean isHasTaskInfo) { + SweeperTaskModel.getInstance().isHasTaskInfo(isHasTaskInfo); + } + + /** + * 设置上一个任务的lineId + * @param preLineId + */ + public void setPreLineId(int preLineId) { + SweeperTaskModel.getInstance().setPreLineId(preLineId); + } + + /** + * 获取当前正在执行的任务 + */ + public void getCurrentTask() { + SweeperTaskModel.getInstance().getCurrentTask(); + } + + /** + * 接取任务弹窗响应 + * + * @param taskId + * @param code + */ + public void sendSweeperStartTaskResp(String taskId, SweeperTask.StartTaskCode code) { + SweeperTaskModel.getInstance().sendSweeperStartTaskResp(taskId, code); + } + + /** + * 子任务弹窗确认 + * + * @param taskId + * @param subTaskId + * @param code + */ + public void sendSweeperTaskConfirmResp(String taskId, String subTaskId, SweeperTaskConfirm.TaskConfirmCode code) { + SweeperTaskModel.getInstance().sendSweeperTaskConfirmResp(taskId, subTaskId, code); + } + + /** + * 大任务结束弹窗确认 + * + * @param taskId + * @param code + */ + public void sendSweeperStopTaskResp(String taskId, SweeperTaskStop.StopTaskCode code) { + SweeperTaskModel.getInstance().sendSweeperStopTaskResp(taskId, code); + } + + /** + * pad上报是否可以进自驾 + * + * @param taskId + * @param subTaskId + * @param lineId + */ + public void sendSweeperAutopilotBootable(String taskId, String subTaskId, long lineId) { + SweeperTaskModel.getInstance().sendSweeperAutopilotBootable(taskId, subTaskId, lineId); + } + + @Override + public void setRouteList(@NonNull ArrayList routeList) { + mView.setTaskRouteList(routeList); + } + + @Override + public void onSweeperCloudTask(@NonNull SweeperCloudTask.MessageType messageType, SweeperTask.TaskInfo taskInfo) { + ThreadUtils.runOnUiThread(() -> mView.onSweeperCloudTask(messageType, taskInfo)); + } + + @Override + public void onSweeperCloudTaskConfirm(@NonNull String taskId, @NonNull String subTaskId, boolean isPop) { + ThreadUtils.runOnUiThread(() -> mView.handleSubTaskInfoDialog(taskId, subTaskId, isPop)); + } + + @Override + public void onSweeperCloudTaskStatus(@NonNull String taskId, @NonNull String subTaskId, SweeperCommon.TaskStatus subTaskStatus) { + ThreadUtils.runOnUiThread(() -> mView.onSweeperUpdateSubTaskStatus(taskId, subTaskId, subTaskStatus)); + } + + @Override + public void onSweeperCloudTaskStop(@NonNull String taskId, SweeperTaskStop.StopTaskType stopTaskType, boolean isPop) { + ThreadUtils.runOnUiThread(() -> mView.onSweeperCloudTaskStop(taskId, stopTaskType, isPop)); + } + + @Override + public void onSweeperCloudTaskSuspendResume(@NonNull SweeperCloudTask.MessageType messageType, @NonNull String taskId, + @NonNull String subTaskId, SweeperCommon.Code code) { + + } + + @Override + public void onSweeperCloudBootable(@NonNull String taskId, @NonNull String subTaskId, SweeperBootable.IsBootableResp isBootableResp) { + ThreadUtils.runOnUiThread(() -> mView.onSweeperCloudAutopilotBootable(taskId, subTaskId, isBootableResp)); + } + + @Override + public void onSweeperCloudBigTaskStatus(@NonNull String taskId, SweeperBigTaskStatus.BigTaskStatus subTaskStatus) { + ThreadUtils.runOnUiThread(() -> mView.onSweeperCloudBigTaskStatus(taskId, subTaskStatus)); + } + + @Override + public void setWeltDataToMap(@NonNull ArrayList weltDataBeans, boolean isWeltData, @NonNull String distance) { + ThreadUtils.runOnUiThread(() -> mView.setWeltDataToMap(weltDataBeans, isWeltData, distance)); + } + + @Override + public void onSweeperFutianCleanSystemState(@NonNull ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) { + ThreadUtils.runOnUiThread(() -> mView.onSweeperFutianCleanSystemState(cleanSystemState)); + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/receiver/TestSweeperBroadcastReceiver.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/receiver/TestSweeperBroadcastReceiver.java new file mode 100644 index 0000000000..29a82c69ab --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/receiver/TestSweeperBroadcastReceiver.java @@ -0,0 +1,42 @@ +package com.mogo.och.sweepercloud.receiver; + +import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; +import com.mogo.och.sweepercloud.constant.SweeperConst; + +/** + * 测试小巴车的场景 + * + * @author donghongyu + * @date 4/26/21 12:08 PM + */ +public class TestSweeperBroadcastReceiver extends BroadcastReceiver { + private static final String TAG = "TestBusBroadcastReceiver"; + + private Context mContext; + + @Override + public void onReceive(Context context, Intent intent) { + try { + this.mContext = context; + int sceneType = intent.getIntExtra(SweeperConst.BROADCAST_TEST_SWEEPER_CONTROL_TYPE_EXTRA_KEY, 0); + CallerLogger.INSTANCE.d(M_BUS + TAG, "sceneType:" + sceneType); + + // 分发场景 + dispatchSceneTest(sceneType); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void dispatchSceneTest(int sceneType) { + + } + + +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/SweeperOperatePanelView.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/SweeperOperatePanelView.java new file mode 100644 index 0000000000..741b9a9e6e --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/SweeperOperatePanelView.java @@ -0,0 +1,1097 @@ +package com.mogo.och.sweepercloud.ui; + +import static com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil.CLEAN_DIRECTION_BOTH_SIDE; +import static com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil.CLEAN_DIRECTION_LEFT_SIDE; +import static com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil.CLEAN_DIRECTION_RIGHT_SIDE; +import static com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil.CLEAN_INTENSITY_STRAND; +import static com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil.CLEAN_INTENSITY_STRONG; +import static com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil.CLEAN_MODE_PURE_DRAW; +import static com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil.CLEAN_MODE_PURE_SWEEP; +import static com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil.CLEAN_MODE_PURE_WASH; +import static com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil.CLEAN_MODE_WASH_SWEEP; + +import android.animation.ObjectAnimator; +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.animation.LinearInterpolator; +import android.widget.CheckedTextView; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager; +import com.mogo.eagle.core.utilcode.mogo.view.OnPreventFastClickListener; +import com.mogo.eagle.core.utilcode.util.ToastUtils; +import com.mogo.och.sweepercloud.R; +import com.mogo.och.sweepercloud.callback.ICleaningModeStateCallback; +import com.mogo.och.sweepercloud.constant.OperateStateEnum; +import com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil; +import com.mogo.och.sweepercloud.view.NoTouchConstraintLayout; +import com.mogo.och.sweepercloud.callback.ICleaningModeStateCallback; +import com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil; +import com.mogo.och.sweepercloud.view.NoTouchConstraintLayout; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import chassis.ChassisStatesOuterClass; +import chassis.SpecialVehicleTaskCmdOuterClass; + +import static com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil.CLEAN_DIRECTION_CLOSE; +import static com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil.CLEAN_MODE_CLOSE; +import static com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil.CLEAN_WORK_CLOSE; +import static com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil.CLEAN_WORK_OPEN; + +/** + * 清扫车操作面板View + */ +public class SweeperOperatePanelView extends LinearLayout { + + private static final String TAG = "SweeperOperatePanelView"; + private static final int CMD_EXECUTE_TIMEOUT_SECONDS = 30; + private static final int CMD_EXECUTE_MOCK_SUCCESS_SECONDS = 3; + private boolean isFirst = false; + + CheckedTextView mBtnCleanWorkOpenClose;//开关 + CheckedTextView mBtnCleanModePureSweep;//纯扫 + CheckedTextView mBtnCleanModePureWash;//纯洗 + CheckedTextView mBtnCleanModeSweepWash;//洗扫 + CheckedTextView mBtnCleanModePureAbsorption;//纯吸 + CheckedTextView mBtnCleanDirectionLeftSide;//左侧 + CheckedTextView mBtnCleanDirectionRightSide;//右侧 + CheckedTextView mBtnCleanDirectionBothSide;//两侧 + CheckedTextView mBtnCleanIntensityStandard;//普通 + CheckedTextView mBtnCleanIntensityStrong;//强力 + FrameLayout mLoadingContainer;//loading container + TextView mLoadingHint;//loading 文本提示 + ImageView mLoadingView;//loading 转圈动画 + NoTouchConstraintLayout mWorkmodePanelRootView; + + // 作业模式相关操作按钮的id + List cleanModeBtnViewIds = Arrays.asList( + R.id.btn_clean_mode_pure_sweep, + R.id.btn_clean_mode_pure_wash, + R.id.btn_clean_mode_sweep_wash, + R.id.btn_clean_mode_pure_absorption); + + // 作业模式相关操作按钮,对应命令参数值 + HashMap cleanModeBtnAndCmdValueMap = new HashMap() { + { + put(R.id.btn_clean_mode_pure_sweep, SweeperFutianCmdUtil.CLEAN_MODE_PURE_SWEEP); + put(R.id.btn_clean_mode_pure_wash, SweeperFutianCmdUtil.CLEAN_MODE_PURE_WASH); + put(R.id.btn_clean_mode_sweep_wash, SweeperFutianCmdUtil.CLEAN_MODE_WASH_SWEEP); + put(R.id.btn_clean_mode_pure_absorption, SweeperFutianCmdUtil.CLEAN_MODE_PURE_DRAW); + } + }; + + // 清扫方向相关操作按钮的id + List cleanDirectionBtnViewIds = Arrays.asList( + R.id.btn_clean_direction_left_side, + R.id.btn_clean_direction_right_side, + R.id.btn_clean_direction_both_side); + + // 清扫方向相关按钮操作,对应命令参数值 + HashMap cleanDirectionBtnAndCmdValueMap = new HashMap() { + { + put(R.id.btn_clean_direction_left_side, SweeperFutianCmdUtil.CLEAN_DIRECTION_LEFT_SIDE); + put(R.id.btn_clean_direction_right_side, SweeperFutianCmdUtil.CLEAN_DIRECTION_RIGHT_SIDE); + put(R.id.btn_clean_direction_both_side, SweeperFutianCmdUtil.CLEAN_DIRECTION_BOTH_SIDE); + } + }; + + // 作业强度相关按钮操作 + List cleanIntensityBtnViewIds = Arrays.asList( + R.id.btn_clean_intensity_standard, + R.id.btn_clean_intensity_strong); + + // 作业强度相关按钮操作,对应命令参数值 + HashMap cleanIntensityBtnAndCmdValueMap = new HashMap() { + { + put(R.id.btn_clean_intensity_standard, SweeperFutianCmdUtil.CLEAN_INTENSITY_STRAND); + put(R.id.btn_clean_intensity_strong, SweeperFutianCmdUtil.CLEAN_INTENSITY_STRONG); + } + }; + private boolean isSelectPureSweepMode = false;//用于标注是否选中纯扫 + + private ICleaningModeStateCallback cleaningModeStateCallback; + + private OperateStateEnum operateStateEnum = OperateStateEnum.SYNCING_STATUS; + + private ObjectAnimator objectAnimator; + + private static ChassisStatesOuterClass.SweeperFuTianTaskSystemStates mCurrentCleanSystemState;//当前作业模式 + + public SweeperOperatePanelView(Context context) { + super(context); + } + + public SweeperOperatePanelView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initView(context); + } + + public SweeperOperatePanelView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initView(context); + } + + public SweeperOperatePanelView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + initView(context); + } + + private void initView(Context context) { + LayoutInflater.from(context).inflate(R.layout.sweeper_operate_panel_view, this, true); + mBtnCleanWorkOpenClose = (CheckedTextView) findViewById(R.id.btn_clean_work_open_close); + mWorkmodePanelRootView = (NoTouchConstraintLayout) findViewById(R.id.work_mode_panel_root_view); + mBtnCleanModePureSweep = (CheckedTextView) findViewById(R.id.btn_clean_mode_pure_sweep); + mBtnCleanModePureWash = (CheckedTextView) findViewById(R.id.btn_clean_mode_pure_wash); + mBtnCleanModeSweepWash = (CheckedTextView) findViewById(R.id.btn_clean_mode_sweep_wash); + mBtnCleanModePureAbsorption = (CheckedTextView) findViewById(R.id.btn_clean_mode_pure_absorption); + mBtnCleanDirectionLeftSide = (CheckedTextView) findViewById(R.id.btn_clean_direction_left_side); + mBtnCleanDirectionRightSide = (CheckedTextView) findViewById(R.id.btn_clean_direction_right_side); + mBtnCleanDirectionBothSide = (CheckedTextView) findViewById(R.id.btn_clean_direction_both_side); + mBtnCleanIntensityStandard = (CheckedTextView) findViewById(R.id.btn_clean_intensity_standard); + mBtnCleanIntensityStrong = (CheckedTextView) findViewById(R.id.btn_clean_intensity_strong); + mLoadingContainer = findViewById(R.id.loading_hint_container); + mLoadingHint = findViewById(R.id.loading_hint); + mLoadingView = findViewById(R.id.loading_view); + initViewListener(); + } + + private void initViewListener() { + setClickListener(mBtnCleanWorkOpenClose, (v) -> onCleanWorkBtnClick()); + setClickListener(mBtnCleanModePureSweep, (v) -> onCleanModeBtnClick(v)); + setClickListener(mBtnCleanModePureWash, (v) -> onCleanModeBtnClick(v)); + setClickListener(mBtnCleanModeSweepWash, (v) -> onCleanModeBtnClick(v)); + setClickListener(mBtnCleanModePureAbsorption, (v) -> onCleanModeBtnClick(v)); + setClickListener(mBtnCleanDirectionLeftSide, (v) -> onCleanDirectionBtnClick(v)); + setClickListener(mBtnCleanDirectionRightSide, (v) -> onCleanDirectionBtnClick(v)); + setClickListener(mBtnCleanDirectionBothSide, (v) -> onCleanDirectionBtnClick(v)); + setClickListener(mBtnCleanIntensityStandard, (v) -> onCleanIntensityBtnClick(v)); + setClickListener(mBtnCleanIntensityStrong, (v) -> onCleanIntensityBtnClick(v)); + } + + /** + * 清扫任务开关按钮点击事件 + */ + private void onCleanWorkBtnClick() { + // 是否是 关闭 操作 + boolean isCloseAction = mBtnCleanWorkOpenClose.isChecked(); + CmdRequestCallback cmdRequestCallback = new CmdRequestCallback() { + @Override + public void onSendCmd() { + showLoadingMask(CMD_EXECUTE_TIMEOUT_SECONDS); + } + + @Override + public void onCountDownTick(int seconds) { + updateLoadingCountDown(seconds); + } + + @Override + public boolean onCheckIfCmdSuccess(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) { + boolean success = false; + if (cleanSystemState == null) { + return success; + } + if (isCloseAction) { + success = !cleanSystemState.getSecuMotWorkSts(); + } else { + success = cleanSystemState.getSecuMotWorkSts(); + } + return success; + } + + @Override + public void onCmdSuccess() { + if (isCloseAction) { + mBtnCleanWorkOpenClose.setText("打开"); + mBtnCleanWorkOpenClose.setChecked(false); + toggleCleanModeBtnsStatus(false); + toggleCleanDirectionBtnsStatus(false); + toggleCleanIntensityBtnsStatus(false); + } else { + mBtnCleanWorkOpenClose.setText("关闭"); + mBtnCleanWorkOpenClose.setChecked(true); + toggleCleanModeBtnsStatus(true); + } + hideLoadingMask(); + showCmdExecuteSuccessToast(); + } + + @Override + public void onCmdFailed() { + } + + @Override + public void onCmdTimeout() { + //按钮样式恢复原样 + if (isCloseAction) { + mBtnCleanWorkOpenClose.setText("关闭"); + mBtnCleanWorkOpenClose.setChecked(true); + } else { + mBtnCleanWorkOpenClose.setText("打开"); + mBtnCleanWorkOpenClose.setChecked(false); + } + hideLoadingMask(); + showCmdExecuteTimeoutToast(); + } + }; + if (isCloseAction) { + //关闭操作,点击时需要弹框提示确认后,关闭 + sendSweeperCmd( + SweeperFutianCmdUtil.buildCleanWorkStopCmd(), + cmdRequestCallback + , CMD_EXECUTE_TIMEOUT_SECONDS); + } else { + //打开操作,点击时打开 + sendSweeperCmd( + SweeperFutianCmdUtil.buildCleanWorkStartCmd(), + cmdRequestCallback, + CMD_EXECUTE_TIMEOUT_SECONDS); + } + } + + /** + * 作业模式按钮点击事件 + * + * @param currentClickView + */ + private void onCleanModeBtnClick(final View currentClickView) { + CheckedTextView currentChoosedModeBtnView = null; + for (Integer viewId : cleanModeBtnViewIds) { + CheckedTextView view = (CheckedTextView) findViewById(viewId); + if (view.isChecked()) { + currentChoosedModeBtnView = view; + break; + } + } + boolean isClickCurrentChoosedModeBtn = currentChoosedModeBtnView != null + && currentChoosedModeBtnView.getId() == currentClickView.getId(); + //是否纯吸View + boolean isPureAbsorptionClick = currentClickView.getId() == R.id.btn_clean_mode_pure_absorption; + //是否纯洗View + boolean isPureWashClick = currentClickView.getId() == R.id.btn_clean_mode_pure_wash; + //是否纯扫View + boolean isPureSweepClick = currentClickView.getId() == R.id.btn_clean_mode_pure_sweep; + //是否洗扫View + boolean isWashSweepClick = currentClickView.getId() == R.id.btn_clean_mode_sweep_wash; + CmdRequestCallback cmdRequestCallback = new CmdRequestCallback() { + @Override + public void onSendCmd() { + showLoadingMask(CMD_EXECUTE_TIMEOUT_SECONDS); + } + + @Override + public void onCountDownTick(int seconds) { + updateLoadingCountDown(seconds); + } + + @Override + public boolean onCheckIfCmdSuccess(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) { + boolean success = false; + if (cleanSystemState == null) { + return success; + } + // 洗扫 + boolean clean_mode_wash_sweep = cleanSystemState.getSecuModWashSweepSts(); + // 纯洗 + boolean clean_mode_pure_wash = cleanSystemState.getSecuModWashSts(); + // 纯吸 + boolean clean_mode_pure_draw = cleanSystemState.getSecuWorkTonSts(); + // 纯扫 模式判断:不是另外其他3个模式,同时有清扫方向,说明开启了纯扫模式 + boolean clean_mode_pure_sweep = SweeperFutianCmdUtil.checkIfCleanModePureSweep(cleanSystemState); + // 关闭作业模式(实际执行了3个操作: 关闭作业模式 关闭清扫方向 切换标准强度,实际以关闭作业模式成功为准) + boolean clean_mode_close = !clean_mode_wash_sweep + && !clean_mode_pure_wash + && !clean_mode_pure_draw + && !clean_mode_pure_sweep; + + if (isClickCurrentChoosedModeBtn && clean_mode_close) {// 关闭放第一判断 + success = clean_mode_close; + isSelectPureSweepMode = false; + } else if (isPureSweepClick) { + //success = clean_mode_pure_sweep; + //纯扫 这个模式实际在福田清扫车上没有这个按钮,只是发送指令给特种车端,默认此命令肯定是正确的 + success = true; + isSelectPureSweepMode = true; + } else if (isPureWashClick) { + success = clean_mode_pure_wash; + isSelectPureSweepMode = false; + } else if (isWashSweepClick) { + success = clean_mode_wash_sweep; + isSelectPureSweepMode = false; + } else if (isPureAbsorptionClick) { + success = clean_mode_pure_draw; + isSelectPureSweepMode = false; + } + return success; + } + + @Override + public void onCmdSuccess() { + ((CheckedTextView) currentClickView).setChecked(!isClickCurrentChoosedModeBtn); + toggleCleanModeBtnsByChoosedViewId(currentClickView.getId(), isClickCurrentChoosedModeBtn); + if (isClickCurrentChoosedModeBtn) { + toggleCleanDirectionBtnsStatus(false); + toggleCleanIntensityBtnsStatus(false); + } else { + // 如果是纯吸,没有设置清扫方向,同时自动设置作业强度为标准 + if (isPureAbsorptionClick) { + toggleCleanDirectionBtnsStatus(false); + setCleanIntensityStandard(); + } else { + toggleCleanDirectionBtnsStatus(true); + toggleCleanIntensityBtnsStatus(false); + } + } + hideLoadingMask(); + showCmdExecuteSuccessToast(); + } + + @Override + public void onCmdFailed() { + } + + @Override + public void onCmdTimeout() { + ((CheckedTextView) currentClickView).setChecked(isClickCurrentChoosedModeBtn); + hideLoadingMask(); + showCmdExecuteTimeoutToast(); + } + }; + + if (isClickCurrentChoosedModeBtn) { + //当前已选择模式的按钮,取消当前模式,并关闭清扫方向 + sendSweeperCmd( + SweeperFutianCmdUtil.buildCleanModeCloseCmd(), + cmdRequestCallback, + CMD_EXECUTE_TIMEOUT_SECONDS); + } else { + //开启新的作业模式,直接发送命令(纯吸需要一并设置作业强度为标准) + int cmdValue = cleanModeBtnAndCmdValueMap.get(currentClickView.getId()); + sendSweeperCmd( + isPureAbsorptionClick ? SweeperFutianCmdUtil.buildCleanModePureDrawCmd() + : SweeperFutianCmdUtil.buildCleanModeCmd(cmdValue), + cmdRequestCallback, + CMD_EXECUTE_TIMEOUT_SECONDS); + } + } + + private void onCleanDirectionBtnClick(final View currentClickView) { + CheckedTextView currentChoosedDirectionBtnView = null; + for (Integer viewId : cleanDirectionBtnViewIds) { + CheckedTextView view = (CheckedTextView) findViewById(viewId); + if (view.isChecked()) { + currentChoosedDirectionBtnView = view; + break; + } + } + boolean isClickCurrentChoosedDirectionBtn = currentChoosedDirectionBtnView != null + && currentChoosedDirectionBtnView.getId() == currentClickView.getId(); + + boolean isLeftSide = currentClickView.getId() == R.id.btn_clean_direction_left_side; + boolean isRightSide = currentClickView.getId() == R.id.btn_clean_direction_right_side; + boolean isBothSide = currentClickView.getId() == R.id.btn_clean_direction_both_side; + CmdRequestCallback cmdRequestCallback = new CmdRequestCallback() { + @Override + public void onSendCmd() { + showLoadingMask(CMD_EXECUTE_TIMEOUT_SECONDS); + } + + @Override + public void onCountDownTick(int seconds) { + updateLoadingCountDown(seconds); + } + + @Override + public boolean onCheckIfCmdSuccess(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) { + boolean success = false; + if (cleanSystemState == null) { + return success; + } + // 左侧 + boolean clean_direction_left_side = cleanSystemState.getSecuWorkLeftSts(); + // 右侧 + boolean clean_direction_right_side = cleanSystemState.getSecuWorkRightSts(); + // 两侧 + boolean clean_direction_both_side = cleanSystemState.getSecuWorkOnBothsidesSts(); + // 关闭清扫方向(实际执行了2个操作:关闭清扫方向 切换标准强度,实际以关闭清扫方向成功为准) + boolean clean_direction_close = !clean_direction_left_side && !clean_direction_right_side + && !clean_direction_both_side; + + if (isClickCurrentChoosedDirectionBtn && clean_direction_close) {//关闭放第一判断 + success = clean_direction_close; + } else if (isLeftSide) { + success = clean_direction_left_side; + } else if (isRightSide) { + success = clean_direction_right_side; + } else if (isBothSide) { + success = clean_direction_both_side; + } + return success; + } + + @Override + public void onCmdSuccess() { + ((CheckedTextView) currentClickView).setChecked(!isClickCurrentChoosedDirectionBtn); + toggleCleanDirectionBtnsByChoosedViewId(currentClickView.getId(), isClickCurrentChoosedDirectionBtn); + if (isClickCurrentChoosedDirectionBtn) { + toggleCleanIntensityBtnsStatus(false); + } else { + toggleCleanIntensityBtnsStatus(true); + // 一并设置作业强度为标准 + setCleanIntensityStandard(); + } + hideLoadingMask(); + showCmdExecuteSuccessToast(); + } + + @Override + public void onCmdFailed() { + } + + @Override + public void onCmdTimeout() { + ((CheckedTextView) currentClickView).setChecked(isClickCurrentChoosedDirectionBtn); + hideLoadingMask(); + showCmdExecuteTimeoutToast(); + } + }; + if (isClickCurrentChoosedDirectionBtn) { + //当前已选择模式的按钮,取消当前模式,重置作业强度为标准,并置灰作业强度按钮 + sendSweeperCmd( + SweeperFutianCmdUtil.buildCleanDirectionCloseCmd(), + cmdRequestCallback, + CMD_EXECUTE_TIMEOUT_SECONDS); + } else { + //开启新的作业模式,直接发送命令(作业强度默认为标准) + int cmdValue = cleanDirectionBtnAndCmdValueMap.get(currentClickView.getId()); + sendSweeperCmd( + SweeperFutianCmdUtil.buildCleanDirectionCmd(cmdValue), + cmdRequestCallback, + CMD_EXECUTE_TIMEOUT_SECONDS); + } + } + + private void onCleanIntensityBtnClick(final View currentClickView) { + CheckedTextView currentChoosedModeBtnView = null; + for (Integer viewId : cleanIntensityBtnViewIds) { + CheckedTextView view = (CheckedTextView) findViewById(viewId); + if (view.isChecked()) { + currentChoosedModeBtnView = view; + break; + } + } + boolean isClickCurrentChoosedModeBtn = currentChoosedModeBtnView != null + && currentChoosedModeBtnView.getId() == currentClickView.getId(); + //作业强度如果已经选中,则重复点击时不需要再重复发送指令 + if (isClickCurrentChoosedModeBtn) { + return; + } + boolean isStandardBtnClick = currentClickView.getId() == R.id.btn_clean_intensity_standard; + boolean isStrongBtnClick = currentClickView.getId() == R.id.btn_clean_intensity_strong; + CmdRequestCallback cmdRequestCallback = new CmdRequestCallback() { + @Override + public void onSendCmd() { + showLoadingMask(CMD_EXECUTE_TIMEOUT_SECONDS); + } + + @Override + public void onCountDownTick(int seconds) { + updateLoadingCountDown(seconds); + } + + @Override + public boolean onCheckIfCmdSuccess(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) { + boolean success = false; + if (cleanSystemState == null) { + return success; + } + boolean clean_intensity_standard = cleanSystemState.getSecuWorkStandSts(); + boolean clean_intensity_strong = cleanSystemState.getSecuWorkStrongSts(); + if (isStandardBtnClick) { + success = clean_intensity_standard; + } else if (isStrongBtnClick) { + success = clean_intensity_strong; + } + return success; + } + + @Override + public void onCmdSuccess() { + ((CheckedTextView) currentClickView).setChecked(true); + if (isStandardBtnClick) { + setCleanIntensityStandard(); + } else { + setCleanIntensityStrong(); + } + hideLoadingMask(); + showCmdExecuteSuccessToast(); + } + + @Override + public void onCmdFailed() { + } + + @Override + public void onCmdTimeout() { + ((CheckedTextView) currentClickView).setChecked(false); + hideLoadingMask(); + showCmdExecuteTimeoutToast(); + } + }; + int cmdValue = cleanIntensityBtnAndCmdValueMap.get(currentClickView.getId()); + sendSweeperCmd( + SweeperFutianCmdUtil.buildCleanIntensityCmd(cmdValue), + cmdRequestCallback, + CMD_EXECUTE_TIMEOUT_SECONDS); + } + + /** + * 作业模式按钮状态切换-置灰/开启 按钮 + * + * @param enable + */ + private void toggleCleanModeBtnsStatus(boolean enable) { + for (Integer viewId : cleanModeBtnViewIds) { + CheckedTextView view = (CheckedTextView) findViewById(viewId); + view.setEnabled(enable); + view.setChecked(false); + } + } + + /** + * 作业模式按钮状态切换-将当前点击按钮之外的其他按钮 置灰或开启 + * + * @param choosedBtnId + * @param enable + */ + private void toggleCleanModeBtnsByChoosedViewId(int choosedBtnId, boolean enable) { + for (Integer viewId : cleanModeBtnViewIds) { + CheckedTextView view = (CheckedTextView) findViewById(viewId); + if (view.getId() != choosedBtnId) { + view.setEnabled(enable); + view.setChecked(false); + } + } + } + + /** + * 清扫方向按钮状态切换-置灰/开启 按钮 + * + * @param enable + */ + private void toggleCleanDirectionBtnsStatus(boolean enable) { + for (Integer viewId : cleanDirectionBtnViewIds) { + CheckedTextView view = (CheckedTextView) findViewById(viewId); + view.setEnabled(enable); + view.setChecked(false); + } + } + + /** + * 清扫方向按钮状态切换-将当前点击按钮之外的其他按钮 置灰或开启 + * + * @param choosedBtnId + * @param enable + */ + private void toggleCleanDirectionBtnsByChoosedViewId(int choosedBtnId, boolean enable) { + for (Integer viewId : cleanDirectionBtnViewIds) { + CheckedTextView view = (CheckedTextView) findViewById(viewId); + if (view.getId() != choosedBtnId) { + view.setEnabled(enable); + view.setChecked(false); + } + } + } + + /** + * 作业强度按钮状态切换-置灰/开启 按钮 + * + * @param enable + */ + private void toggleCleanIntensityBtnsStatus(boolean enable) { + for (Integer viewId : cleanIntensityBtnViewIds) { + CheckedTextView view = (CheckedTextView) findViewById(viewId); + view.setEnabled(enable); + view.setChecked(false); + } + } + + /** + * 设置作业强度-标准 + */ + private void setCleanIntensityStandard() { + mBtnCleanIntensityStandard.setChecked(true); + mBtnCleanIntensityStandard.setEnabled(true); + mBtnCleanIntensityStrong.setChecked(false); + mBtnCleanIntensityStrong.setEnabled(true); + } + + /** + * 设置作业强度-加强 + */ + private void setCleanIntensityStrong() { + mBtnCleanIntensityStandard.setChecked(false); + mBtnCleanIntensityStandard.setEnabled(true); + mBtnCleanIntensityStrong.setChecked(true); + mBtnCleanIntensityStrong.setEnabled(true); + } + + /** + * 发送命令后等待时,展示loading + * + * @param timeout + */ + private void showLoadingMask(int timeout) { + mLoadingContainer.setVisibility(View.VISIBLE); + mWorkmodePanelRootView.setInterceptTouchEvent(true); + if (timeout < 0) {//状态同步中 + mLoadingHint.setText("状态同步中,请稍后"); + mLoadingView.setVisibility(View.GONE); + } else { + mLoadingHint.setText(timeout + "s"); + mLoadingView.setVisibility(View.VISIBLE); + startRotation(); + } + if (cleaningModeStateCallback != null && timeout > 0) { + operateStateEnum = OperateStateEnum.STARTING_STATUS; + cleaningModeStateCallback.cleaningModeState(operateStateEnum, mCurrentCleanSystemState, isSelectPureSweepMode); + } + } + + /** + * 隐藏loading + */ + private void hideLoadingMask() { + mSweeperOperateCmdHandler.removeMessages(MSG_CMD_EXECUTE_COUNT_DOWN); + mLoadingContainer.setVisibility(View.GONE); + mWorkmodePanelRootView.setInterceptTouchEvent(false); + } + + /** + * 更新loading中倒计时 + * + * @param timeout + */ + private void updateLoadingCountDown(int timeout) { + mLoadingHint.setText(timeout + "s"); + } + + /** + * 命令执行成功toast + */ + private void showCmdExecuteSuccessToast() { + if (cleaningModeStateCallback != null) { + operateStateEnum = OperateStateEnum.SUCCESS_STATUS; + cleaningModeStateCallback.cleaningModeState(operateStateEnum, mCurrentCleanSystemState, isSelectPureSweepMode); + } + //停止旋转动画 + stopRotation(); + ToastUtils.showLong("设备已响应,操作成功"); + } + + /** + * 命令执行超时toast + */ + private void showCmdExecuteTimeoutToast() { + if (cleaningModeStateCallback != null) { + operateStateEnum = OperateStateEnum.FAIL_STATUS; + cleaningModeStateCallback.cleaningModeState(operateStateEnum, mCurrentCleanSystemState, isSelectPureSweepMode); + } + //停止旋转动画 + stopRotation(); + ToastUtils.showLong("超时未响应,操作失败"); + } + + private void setClickListener(View view, OnClickListener listener) { + view.setOnClickListener(new OnPreventFastClickListener() { + @Override + public void onClickImpl(View v) { + listener.onClick(v); + } + }); + } + + public void setSweeperFutianCleanSystemState(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState, + ICleaningModeStateCallback cleaningModeStateCallback) { + this.cleaningModeStateCallback = cleaningModeStateCallback; + // 有命令正在执行 + if (mCurrentCmdRequestCallback != null) { + Log.d(TAG, "getSecuWorkLeftSts = " + cleanSystemState.getSecuWorkLeftSts()); + if (mCurrentCmdRequestCallback.onCheckIfCmdSuccess(cleanSystemState)) { + mCurrentCmdRequestCallback.onCmdSuccess(); + mCurrentCmdRequestCallback = null; + } + } + //正在上装中或者上装失败,则不更新面板内容 + if (operateStateEnum == OperateStateEnum.STARTING_STATUS) { + return; + } + if (!isFirst) { + isFirst = true; + onSyncVehicleStateCallBack(cleanSystemState); + } + } + + /** + * 设置是否展示状态同步中 + * + * @param operateState + */ + public void showSyncing(OperateStateEnum operateState) { + if (operateState == OperateStateEnum.SYNCING_STATUS) { + syncVehicleStateAndRecoverOperatePanelStates(); + isFirst = false; + } else { + hideLoadingMask(); + } + } + + /** + * 等待同步底盘数据,并根据底盘数据恢复操作面板中按钮的状态 + */ + private synchronized void syncVehicleStateAndRecoverOperatePanelStates() { + // show sync loading + showLoadingMask(-1); + } + + private synchronized void onSyncVehicleStateCallBack(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) { + if (cleanSystemState == null) return; + // 清扫作业开启状态(以电机状态为true代表Open成功,实际控制端控制步骤为:1.发送远程控制上装指令 2.发送电机启动指令) + boolean clean_open_requirement = cleanSystemState.getSecuMotWorkSts(); + // 作业模式状态 + // 洗扫 + boolean clean_mode_wash_sweep = cleanSystemState.getSecuModWashSweepSts(); + // 纯洗 + boolean clean_mode_pure_wash = cleanSystemState.getSecuModWashSts(); + // 纯吸 + boolean clean_mode_pure_draw = cleanSystemState.getSecuWorkTonSts(); + + // 清扫方向状态 + // 左侧 + boolean clean_direction_left_side = cleanSystemState.getSecuWorkLeftSts(); + // 右侧 + boolean clean_direction_right_side = cleanSystemState.getSecuWorkRightSts(); + // 两侧 + boolean clean_direction_both_side = cleanSystemState.getSecuWorkOnBothsidesSts(); + + // 纯扫 模式判断:不是另外其他3个模式,同时有清扫方向,说明开启了纯扫模式 + boolean clean_mode_pure_sweep = SweeperFutianCmdUtil.checkIfCleanModePureSweep(cleanSystemState); + + // 作业强度状态 + boolean clean_intensity_standard = cleanSystemState.getSecuWorkStandSts(); + boolean clean_intensity_strong = cleanSystemState.getSecuWorkStrongSts(); + if (clean_open_requirement) { + // 打开状态 + mBtnCleanWorkOpenClose.setText("关闭"); + mBtnCleanWorkOpenClose.setChecked(true); + } else { + // 关闭状态 + mBtnCleanWorkOpenClose.setText("打开"); + mBtnCleanWorkOpenClose.setChecked(false); + } + if (clean_mode_pure_sweep) { + //纯扫 + mBtnCleanModePureSweep.setChecked(true); + mBtnCleanModePureSweep.setEnabled(true); + toggleCleanModeBtnsByChoosedViewId(R.id.btn_clean_mode_pure_sweep, false); + } else if (clean_mode_pure_wash) { + //纯洗 + mBtnCleanModePureWash.setChecked(true); + mBtnCleanModePureWash.setEnabled(true); + toggleCleanModeBtnsByChoosedViewId(R.id.btn_clean_mode_pure_wash, false); + } else if (clean_mode_wash_sweep) { + //洗扫 + mBtnCleanModeSweepWash.setChecked(true); + mBtnCleanModeSweepWash.setEnabled(true); + toggleCleanModeBtnsByChoosedViewId(R.id.btn_clean_mode_sweep_wash, false); + } else if (clean_mode_pure_draw) { + //纯吸,需要disable作业方向 + mBtnCleanModePureAbsorption.setChecked(true); + mBtnCleanModePureAbsorption.setEnabled(true); + toggleCleanModeBtnsByChoosedViewId(R.id.btn_clean_mode_pure_absorption, false); + toggleCleanDirectionBtnsStatus(false); + } + + if (!clean_mode_pure_draw) {// 非纯吸模式才有清扫方向 + if (clean_direction_left_side) { + mBtnCleanDirectionLeftSide.setChecked(true); + mBtnCleanDirectionLeftSide.setEnabled(true); + toggleCleanDirectionBtnsByChoosedViewId(R.id.btn_clean_direction_left_side, false); + } else if (clean_direction_right_side) { + mBtnCleanDirectionRightSide.setChecked(true); + mBtnCleanDirectionRightSide.setEnabled(true); + toggleCleanDirectionBtnsByChoosedViewId(R.id.btn_clean_direction_right_side, false); + } else if (clean_direction_both_side) { + mBtnCleanDirectionBothSide.setChecked(true); + mBtnCleanDirectionBothSide.setEnabled(true); + toggleCleanDirectionBtnsByChoosedViewId(R.id.btn_clean_direction_both_side, false); + } + } + if (clean_intensity_standard) { + setCleanIntensityStandard(); + } else if (clean_intensity_strong) { + setCleanIntensityStrong(); + } + hideLoadingMask(); + } + + /** + * 发送清扫车相关作业命令 + * + * @param fuTianCleanCmd + * @param cmdRequestCallback + * @param timeout + */ + private void sendSweeperCmd( + SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd fuTianCleanCmd, + CmdRequestCallback cmdRequestCallback, + int timeout) { + // 设置当前请求的回调 + mCurrentCmdRequestCallback = cmdRequestCallback; + // onSendCmd + mCurrentCmdRequestCallback.onSendCmd(); + // 发送命令 + CallerAutoPilotControlManager.INSTANCE.sendSweeperFuTianTaskCmd(fuTianCleanCmd); + // log发送命令 + logSweeperCmdValue(fuTianCleanCmd); + // 开启倒计时 + Message msg = Message.obtain(); + msg.what = MSG_CMD_EXECUTE_COUNT_DOWN; + msg.obj = timeout; + mSweeperOperateCmdHandler.sendMessage(msg); + // Mock Cmd Success + //mockCleanModeSuccess(fuTianCleanCmd); + } + + private void mockSendCmdSuccess() { + Message successMsg = Message.obtain(); + successMsg.what = MSG_CMD_EXECUTE_MOCK_SUCCESS; + mSweeperOperateCmdHandler.sendMessageDelayed(successMsg, 1000L * CMD_EXECUTE_MOCK_SUCCESS_SECONDS); + } + + private void logSweeperCmdValue(SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd taskCmd) { + SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd roboSweeperFutianCleanCmd = taskCmd.getRoboSweeperFutianCleanCmd(); + int clean_open_requirement = roboSweeperFutianCleanCmd.getCleanOpenRequirement(); + int clean_mode_requirement = roboSweeperFutianCleanCmd.getCleanModeRequirement(); + int clean_direction_requirement = roboSweeperFutianCleanCmd.getCleanDirectionRequirement(); + int clean_intensity_requirement = roboSweeperFutianCleanCmd.getCleanIntensityRequirement(); + Log.d(TAG, "---- sendSweeperFuTianTaskCmd ----" + + "[clean_open_requirement = " + clean_open_requirement + "]," + + "[clean_mode_requirement = " + clean_mode_requirement + "]," + + "[clean_direction_requirement = " + clean_direction_requirement + "]," + + "[clean_intensity_requirement = " + clean_intensity_requirement + "]" + ); + } + + private final static SweeperOperateCmdHandler mSweeperOperateCmdHandler = new SweeperOperateCmdHandler(); + private static CmdRequestCallback mCurrentCmdRequestCallback;//发送命令后的回调 + private static final int MSG_CMD_EXECUTE_COUNT_DOWN = 10001; + private static final int MSG_CMD_EXECUTE_MOCK_SUCCESS = 10002; + + /** + * 执行命令时倒计时的Handler + */ + static class SweeperOperateCmdHandler extends Handler { + + @Override + public void handleMessage(@NonNull Message msg) { + super.handleMessage(msg); + if (msg.what == MSG_CMD_EXECUTE_COUNT_DOWN) { + int seconds = (int) msg.obj; + if (seconds > 0) { + if (mCurrentCmdRequestCallback != null) { + mCurrentCmdRequestCallback.onCountDownTick(seconds); + } + Message newMsg = Message.obtain(); + newMsg.what = MSG_CMD_EXECUTE_COUNT_DOWN; + newMsg.obj = seconds - 1; + mSweeperOperateCmdHandler.sendMessageDelayed(newMsg, 1000L); + } else { + if (mCurrentCmdRequestCallback != null) { + mCurrentCmdRequestCallback.onCmdTimeout(); + mCurrentCmdRequestCallback = null; + } + removeMessages(MSG_CMD_EXECUTE_COUNT_DOWN); + } + } else if (msg.what == MSG_CMD_EXECUTE_MOCK_SUCCESS) { + if (mCurrentCmdRequestCallback != null) { + if (mCurrentCmdRequestCallback.onCheckIfCmdSuccess(mCurrentCleanSystemState)) { + mCurrentCmdRequestCallback.onCmdSuccess(); + mCurrentCmdRequestCallback = null; + } + } + removeMessages(MSG_CMD_EXECUTE_COUNT_DOWN); + } + } + } + + interface CmdRequestCallback { + void onSendCmd(); + + void onCountDownTick(int senonds); + + boolean onCheckIfCmdSuccess(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState); + + void onCmdSuccess(); + + void onCmdFailed(); + + void onCmdTimeout(); + } + + /** + * 开始旋转 + */ + private void startRotation() { + if (objectAnimator == null) { + objectAnimator = ObjectAnimator.ofFloat(mLoadingView, "rotation", 0, 360f); + objectAnimator.setDuration(1500); + objectAnimator.setRepeatCount(-1); + objectAnimator.setInterpolator(new LinearInterpolator()); + objectAnimator.start(); + } + } + + /** + * 停止旋转 + */ + private void stopRotation() { + if (objectAnimator != null && objectAnimator.isRunning()) { + objectAnimator.end(); + objectAnimator = null; + } + } + + /** + * 模拟指令操作成功 + */ + private void mockCleanModeSuccess(SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd fuTianTaskCmd) { + ChassisStatesOuterClass.SweeperFuTianTaskSystemStates.Builder builder = ChassisStatesOuterClass.SweeperFuTianTaskSystemStates.newBuilder(); + chassis.SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd fuTianCleanCmd = fuTianTaskCmd.getRoboSweeperFutianCleanCmd(); + if (fuTianCleanCmd.getCleanOpenRequirement() == SweeperFutianCmdUtil.CLEAN_WORK_OPEN) {//打开 + builder.setSecuMotWorkSts(true); + builder.setSecuModWashSweepSts(false); + builder.setSecuModWashSts(false); + builder.setSecuWorkTonSts(false); + builder.setSecuWorkOnBothsidesSts(false); + builder.setSecuWorkLeftSts(false); + builder.setSecuWorkRightSts(false); + builder.setSecuWorkStandSts(true); + builder.setSecuWorkStrongSts(false); + mCurrentCleanSystemState = builder.build(); + mockSendCmdSuccess(); + return; + } else if (fuTianCleanCmd.getCleanOpenRequirement() == SweeperFutianCmdUtil.CLEAN_WORK_CLOSE) {//关闭 + builder.setSecuModWashSweepSts(false); + builder.setSecuModWashSts(false); + builder.setSecuWorkTonSts(false); + builder.setSecuWorkOnBothsidesSts(false); + builder.setSecuWorkLeftSts(false); + builder.setSecuWorkRightSts(false); + builder.setSecuWorkStandSts(true); + builder.setSecuWorkStrongSts(false); + builder.setSecuMotWorkSts(false); + mCurrentCleanSystemState = builder.build(); + mockSendCmdSuccess(); + return; + } + if (fuTianCleanCmd.getCleanModeRequirement() == SweeperFutianCmdUtil.CLEAN_MODE_PURE_SWEEP) {//纯扫 + builder.setSecuModWashSweepSts(false); + builder.setSecuModWashSts(false); + builder.setSecuWorkTonSts(false); + mCurrentCleanSystemState = builder.build(); + mockSendCmdSuccess(); + return; + } else if (fuTianCleanCmd.getCleanModeRequirement() == SweeperFutianCmdUtil.CLEAN_MODE_WASH_SWEEP) {//洗扫 + builder.setSecuModWashSweepSts(!mCurrentCleanSystemState.getSecuModWashSweepSts()); + mCurrentCleanSystemState = builder.build(); + mockSendCmdSuccess(); + return; + } else if (fuTianCleanCmd.getCleanModeRequirement() == SweeperFutianCmdUtil.CLEAN_MODE_PURE_WASH) {//纯洗 + builder.setSecuModWashSts(!mCurrentCleanSystemState.getSecuModWashSts()); + mCurrentCleanSystemState = builder.build(); + mockSendCmdSuccess(); + return; + } else if (fuTianCleanCmd.getCleanModeRequirement() == SweeperFutianCmdUtil.CLEAN_MODE_PURE_DRAW) {//纯吸 + builder.setSecuWorkTonSts(!mCurrentCleanSystemState.getSecuWorkTonSts()); + builder.setSecuWorkStandSts(true); + builder.setSecuWorkOnBothsidesSts(false); + builder.setSecuWorkLeftSts(false); + builder.setSecuWorkRightSts(false); + mCurrentCleanSystemState = builder.build(); + mockSendCmdSuccess(); + return; + } else if (fuTianCleanCmd.getCleanModeRequirement() == SweeperFutianCmdUtil.CLEAN_MODE_CLOSE) { + builder.setSecuModWashSweepSts(false); + builder.setSecuModWashSts(false); + builder.setSecuWorkTonSts(false); + builder.setSecuWorkOnBothsidesSts(false); + builder.setSecuWorkLeftSts(false); + builder.setSecuWorkRightSts(false); + builder.setSecuWorkStandSts(true); + builder.setSecuWorkStrongSts(false); + mCurrentCleanSystemState = builder.build(); + mockSendCmdSuccess(); + return; + } + if (fuTianCleanCmd.getCleanDirectionRequirement() == SweeperFutianCmdUtil.CLEAN_DIRECTION_BOTH_SIDE) {//两侧 + builder.setSecuWorkOnBothsidesSts(!mCurrentCleanSystemState.getSecuWorkOnBothsidesSts()); + builder.setSecuWorkStandSts(true); + builder.setSecuWorkStrongSts(false); + mCurrentCleanSystemState = builder.build(); + mockSendCmdSuccess(); + return; + } else if (fuTianCleanCmd.getCleanDirectionRequirement() == SweeperFutianCmdUtil.CLEAN_DIRECTION_LEFT_SIDE) {//左侧 + builder.setSecuWorkLeftSts(!mCurrentCleanSystemState.getSecuWorkLeftSts()); + builder.setSecuWorkStandSts(true); + builder.setSecuWorkStrongSts(false); + mCurrentCleanSystemState = builder.build(); + mockSendCmdSuccess(); + return; + } else if (fuTianCleanCmd.getCleanDirectionRequirement() == SweeperFutianCmdUtil.CLEAN_DIRECTION_RIGHT_SIDE) {//右侧 + builder.setSecuWorkRightSts(!mCurrentCleanSystemState.getSecuWorkRightSts()); + builder.setSecuWorkStandSts(true); + builder.setSecuWorkStrongSts(false); + mCurrentCleanSystemState = builder.build(); + mockSendCmdSuccess(); + return; + } else if (fuTianCleanCmd.getCleanDirectionRequirement() == SweeperFutianCmdUtil.CLEAN_DIRECTION_CLOSE) { + builder.setSecuWorkLeftSts(false); + builder.setSecuWorkRightSts(false); + builder.setSecuWorkOnBothsidesSts(false); + builder.setSecuWorkStandSts(true); + builder.setSecuWorkStrongSts(false); + mCurrentCleanSystemState = builder.build(); + mockSendCmdSuccess(); + return; + } + if (fuTianCleanCmd.getCleanIntensityRequirement() == SweeperFutianCmdUtil.CLEAN_INTENSITY_STRAND) { + builder.setSecuWorkStrongSts(true); + builder.setSecuWorkStandSts(false); + mCurrentCleanSystemState = builder.build(); + mockSendCmdSuccess(); + return; + } else if (fuTianCleanCmd.getCleanIntensityRequirement() == SweeperFutianCmdUtil.CLEAN_INTENSITY_STRONG) { + builder.setSecuWorkStandSts(true); + builder.setSecuWorkStrongSts(false); + mCurrentCleanSystemState = builder.build(); + mockSendCmdSuccess(); + } + + } + +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/dialog/SweeperCloudDialog.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/dialog/SweeperCloudDialog.kt new file mode 100644 index 0000000000..23deab9621 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/dialog/SweeperCloudDialog.kt @@ -0,0 +1,133 @@ +package com.mogo.och.sweepercloud.ui.dialog + +import android.animation.ObjectAnimator +import android.animation.ValueAnimator +import android.content.Context +import android.view.View +import android.view.animation.LinearInterpolator +import android.widget.ImageView +import android.widget.TextView +import androidx.lifecycle.LifecycleObserver +import com.mogo.eagle.core.function.hmi.dialog.BaseFloatDialog +import com.mogo.eagle.core.utilcode.util.ClickUtils +import com.mogo.och.sweepercloud.R +import com.mogo.och.sweepercloud.callback.SweeperCloudDialogClickListener +import com.mogo.och.sweepercloud.view.CountDownView + +/** + * 清扫车云控任务dialog基类 + */ + class SweeperCloudDialog : BaseFloatDialog, LifecycleObserver { + private var commonTitle: TextView? = null //标题 + private var commonLeft: TextView? = null//底部左边按钮 + private var commonMiddle: TextView? = null //底部中间按钮 + private var commonRight: TextView? = null //底部右边按钮 + private var commonCountDown: CountDownView? = null //倒计时 + private var commonContent: TextView? = null //内容 + private var commonTip: TextView? = null //文本提示 + private var countDownImage: ImageView? = null //内容 + private var objectAnimator: ObjectAnimator? = null + + constructor(builder: Builder, context: Context) : super(context) { + commonTitle?.text = builder.titleStr + commonContent?.text = builder.contentStr + if (builder.tipStr == "") { + commonTip?.visibility = View.GONE + } else { + commonTip?.text = builder.tipStr + } + if (builder.leftStr == "") { + commonLeft?.visibility = View.GONE + } else { + commonLeft?.text = builder.leftStr + } + if (builder.middleStr == "") { + commonMiddle?.visibility = View.GONE + } else { + commonMiddle?.text = builder.middleStr + } + if (builder.rightStr == "") { + commonRight?.visibility = View.GONE + } else { + commonRight?.text = builder.rightStr + } + if (builder.countDownTime == 0) { + commonCountDown?.visibility = View.GONE + } else { + commonCountDown?.startCountDown(builder.countDownTime) + } + commonLeft?.setOnClickListener { + //防止重复点击 + if(ClickUtils.isFastClick()){ + builder.listener?.onConfirm() + objectAnimator?.cancel() + commonCountDown?.stopCountDown() + dismiss() + } + } + commonMiddle?.setOnClickListener { + //防止重复点击 + if(ClickUtils.isFastClick()){ + builder.listener?.onNext() + objectAnimator?.cancel() + commonCountDown?.stopCountDown() + dismiss() + } + } + commonRight?.setOnClickListener { + //防止重复点击 + if(ClickUtils.isFastClick()){ + builder.listener?.onRefuseOrEnd() + objectAnimator?.cancel() + commonCountDown?.stopCountDown() + dismiss() + } + } + commonCountDown?.setCountDownListener(object : CountDownView.CountDownListener { + override fun stop() { + builder.listener?.onCountDownStop() + objectAnimator?.cancel() + commonCountDown?.stopCountDown() + dismiss() + } + + }) + countDownImage?.let { startAnima(it) } + } + + init { + setContentView(R.layout.dialog_sweeper_cloud_view) + setCanceledOnTouchOutside(false) + commonTitle = findViewById(R.id.sweeper_cloud_title) + commonContent = findViewById(R.id.sweeper_cloud_content) + commonTip = findViewById(R.id.sweeper_cloud_tip) + commonLeft = findViewById(R.id.sweeper_cloud_left) + commonMiddle = findViewById(R.id.sweeper_cloud_middle) + commonRight = findViewById(R.id.sweeper_cloud_right) + countDownImage = findViewById(R.id.sweeper_cloud_imageview) + commonCountDown = findViewById(R.id.sweeper_cloud_countdown) + } + class Builder { + var titleStr: String = "" + var contentStr: String = "" + var tipStr: String = "" + var leftStr: String = "" + var middleStr: String = "" + var rightStr: String = "" + var countDownTime: Int = 0 + var listener: SweeperCloudDialogClickListener? = null + fun build(context: Context): SweeperCloudDialog { + return SweeperCloudDialog(this, context) + } + } + /** + * 启动动画 + */ + private fun startAnima(imageView: ImageView) { + objectAnimator = ObjectAnimator.ofFloat(imageView, "rotation", 0f, 359f) + objectAnimator?.repeatCount = ValueAnimator.INFINITE + objectAnimator?.duration = 1500 + objectAnimator?.interpolator = LinearInterpolator() + objectAnimator?.start() + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/dialog/SweeperCloudLoadingDialog.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/dialog/SweeperCloudLoadingDialog.kt new file mode 100644 index 0000000000..3321382705 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/dialog/SweeperCloudLoadingDialog.kt @@ -0,0 +1,75 @@ +package com.mogo.och.sweepercloud.ui.dialog + +import android.animation.ObjectAnimator +import android.content.Context +import android.view.animation.LinearInterpolator +import androidx.lifecycle.LifecycleObserver +import com.elegant.utils.UiThreadHandler +import com.mogo.eagle.core.function.hmi.dialog.BaseFloatDialog +import com.mogo.eagle.core.utilcode.util.ToastUtils +import com.mogo.och.sweepercloud.R +import kotlinx.android.synthetic.main.dialog_sweeper_cloud_loading.* + +/** + * loading + */ +class SweeperCloudLoadingDialog : BaseFloatDialog, LifecycleObserver { + private var objectAnimator: ObjectAnimator? = null + private val mLoadingView by lazy { dialog_loading_view } + private val mLoadingText by lazy { dialog_loading_text } + private var mRunnable:Runnable= Runnable { + ToastUtils.showLong("超时未响应,操作失败") + hideLoading() + } + + constructor(context: Context) : super(context) + + init { + setContentView(R.layout.dialog_sweeper_cloud_loading) + setCanceledOnTouchOutside(false) + } + + /** + * 开始旋转 + */ + private fun startRotation() { + objectAnimator = ObjectAnimator.ofFloat(mLoadingView, "rotation", -720f, 0f) + objectAnimator?.let { + it.duration = 3000 + it.repeatCount = -1 + it.interpolator = LinearInterpolator() + it.start() + } + } + + /** + * 停止旋转 + */ + private fun stopRotation() { + objectAnimator?.let { + if (it.isRunning) { + it.end() + objectAnimator = null + } + } + } + + /** + * 显示dialog + */ + fun showLoading() { + mLoadingText.text = "加载中..." + startRotation() + show() + UiThreadHandler.getsUiHandler().postDelayed(mRunnable, 15000L) + } + + /** + * 隐藏dialog + */ + fun hideLoading() { + UiThreadHandler.getsUiHandler().removeCallbacks(mRunnable) + stopRotation() + dismiss() + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/dialog/SweeperManualDrivingDialog.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/dialog/SweeperManualDrivingDialog.kt new file mode 100644 index 0000000000..52e21df88c --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/dialog/SweeperManualDrivingDialog.kt @@ -0,0 +1,70 @@ +package com.mogo.och.sweepercloud.ui.dialog + +import android.content.Context +import android.widget.TextView +import androidx.lifecycle.LifecycleObserver +import com.mogo.eagle.core.function.hmi.dialog.BaseFloatDialog +import com.mogo.och.sweepercloud.R + +/** + * 不带带有title, tip,confirm,cancel的dialog + */ +class SweeperManualDrivingDialog: BaseFloatDialog, LifecycleObserver { + + private var commonConfirm : TextView? = null + private var commonTips : TextView? = null + + private var clickListener: ClickListener? = null + + constructor(builder: Builder,context: Context) : super(context) { + commonTips?.text = builder.tipsStr + commonConfirm?.text = builder.confirmStr + } + + init{ + setContentView(R.layout.dialog_sweeper_manual_driving) + + setCanceledOnTouchOutside(false) + + commonConfirm = findViewById(R.id.sweeper_common_confirm) + commonTips = findViewById(R.id.sweeper_common_tips) + + commonConfirm?.setOnClickListener{ + clickListener?.confirm() + dismiss() + } + } + + fun setClickListener(clickListener: ClickListener) { + this.clickListener = clickListener + } + + fun showUpgradeDialog(){ + if(isShowing){ + return + } + show() + } + + interface ClickListener{ + fun confirm() + } + + class Builder{ + var tipsStr:String = "" + var confirmStr:String = "" + fun tips(tips: String) : Builder{ + this.tipsStr = tips + return this + } + + fun confirmStr(commit: String) : Builder{ + this.confirmStr = commit + return this + } + fun build(context: Context): SweeperManualDrivingDialog? { + return SweeperManualDrivingDialog(this,context) + } + } + +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/dialog/SweeperNoTitleCommonDialog.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/dialog/SweeperNoTitleCommonDialog.kt new file mode 100644 index 0000000000..a2b41f4592 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/dialog/SweeperNoTitleCommonDialog.kt @@ -0,0 +1,85 @@ +package com.mogo.och.sweepercloud.ui.dialog + +import android.content.Context +import android.widget.TextView +import androidx.lifecycle.LifecycleObserver +import com.mogo.eagle.core.function.hmi.dialog.BaseFloatDialog +import com.mogo.och.sweepercloud.R + +/** + * 不带带有title, tip,confirm,cancel的dialog + */ +class SweeperNoTitleCommonDialog: BaseFloatDialog, LifecycleObserver { + + private var commonConfirm : TextView? = null + private var commonCancel : TextView? = null + private var commonTips : TextView? = null + + private var clickListener: ClickListener? = null + + constructor(builder: Builder,context: Context) : super(context) { + commonTips?.text = builder.tipsStr + commonCancel?.text = builder.cancelStr + commonConfirm?.text = builder.confirmStr + } + + init{ + setContentView(R.layout.dialog_sweeper_no_title) + + setCanceledOnTouchOutside(true) + + commonConfirm = findViewById(R.id.sweeper_common_confirm) + commonCancel = findViewById(R.id.sweeper_common_cancel) + commonTips = findViewById(R.id.sweeper_common_tips) + + commonConfirm?.setOnClickListener{ + clickListener?.confirm() + dismiss() + } + commonCancel?.setOnClickListener { + clickListener?.cancel() + dismiss() + } + } + + fun setClickListener(clickListener: ClickListener) { + this.clickListener = clickListener + } + + fun showUpgradeDialog(){ + if(isShowing){ + return + } + show() + } + + interface ClickListener{ + fun confirm() + fun cancel() + } + + class Builder{ + var tipsStr:String = "" + var confirmStr:String = "" + var cancelStr:String = "" + fun tips(tips: String) : Builder{ + this.tipsStr = tips + return this + } + + fun confirmStr(commit: String) : Builder{ + this.confirmStr = commit + return this + } + + fun cancelStr(cancel: String) : Builder{ + this.cancelStr = cancel + return this + } + + fun build(context: Context): SweeperNoTitleCommonDialog? { + return SweeperNoTitleCommonDialog(this,context) + } + } + +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/popwindow/SweeperOperatePanelPopWindow.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/popwindow/SweeperOperatePanelPopWindow.kt new file mode 100644 index 0000000000..4db379e1ac --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/ui/popwindow/SweeperOperatePanelPopWindow.kt @@ -0,0 +1,59 @@ +package com.mogo.och.sweepercloud.ui.popwindow + +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.PopupWindow +import chassis.ChassisStatesOuterClass +import com.mogo.och.sweepercloud.R +import com.mogo.och.sweepercloud.callback.ICleaningModeStateCallback +import com.mogo.och.sweepercloud.constant.OperateStateEnum +import com.mogo.och.sweepercloud.ui.SweeperOperatePanelView + +/** + * 清扫车面板浮窗 + */ +class SweeperOperatePanelPopWindow : PopupWindow{ + + private var mOperatePanelView: SweeperOperatePanelView? = null + + constructor(context: Context) : super(context) { + init(context) + } + private fun init(context: Context) { + setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + mOperatePanelView = LayoutInflater.from(context).inflate(R.layout.sweeper_popwindow_operate_panel, null) as SweeperOperatePanelView? + width = ViewGroup.LayoutParams.WRAP_CONTENT + height = ViewGroup.LayoutParams.WRAP_CONTENT + contentView = mOperatePanelView + } + + /** + * 设置清扫模式数据 + */ + fun setCleanSystemState( + cleanSystemState: ChassisStatesOuterClass.SweeperFuTianTaskSystemStates?, + cleaningModeStateCallback: ICleaningModeStateCallback + ) { + mOperatePanelView?.setSweeperFutianCleanSystemState(cleanSystemState, cleaningModeStateCallback) + } + + /**. + * + * 设置是否让popWindow消失 + */ + fun setIsOutsideTouchable(isOutsideTouchable:Boolean){ + this.isFocusable = isOutsideTouchable + this.isOutsideTouchable = isOutsideTouchable + this.isTouchable=isOutsideTouchable + } + + /** + * 设置是否展示状态同步中 + */ + fun showSyncing(operateState: OperateStateEnum){ + mOperatePanelView?.showSyncing(operateState) + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/AutopilotModeConfigManager.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/AutopilotModeConfigManager.java new file mode 100644 index 0000000000..f828af22a5 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/AutopilotModeConfigManager.java @@ -0,0 +1,127 @@ +package com.mogo.och.sweepercloud.util; + +import android.os.Environment; +import android.text.TextUtils; +import android.util.Pair; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.util.JsonFormat; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.atomic.AtomicBoolean; + +import mogo.telematics.pad.MessagePad; + +/** + * 读取启动自动驾驶配置 + */ +public class AutopilotModeConfigManager { + private final static String TAG = AutopilotModeConfigManager.class.getSimpleName(); + private final AtomicBoolean isReadConfig = new AtomicBoolean(false); + private OnReadAutopilotModeConfigListener listener; + + + public interface OnReadAutopilotModeConfigListener { + void onReadFailed(String err);//文件不存在或读取失败 + + void onParseFailed(String err);//配置文件解析失败 + + void onParse(MessagePad.SetAutopilotModeReq bean);//解析完成 + } + + public AutopilotModeConfigManager(OnReadAutopilotModeConfigListener listener) { + this.listener = listener; + } + + + public void registerListener(OnReadAutopilotModeConfigListener listener) { + this.listener = listener; + } + + public void unregisterListener() { + listener = null; + } + + /** + * 读取配置文件 + * + * @return 是否调用成功 + */ + public boolean read() { + if (!isReadConfig.get()) { + isReadConfig.set(true); + Runnable runnable = new Runnable() { + @Override + public void run() { + Pair config = readFilesToString(new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "AutopilotModeConfig.json")); + if (TextUtils.isEmpty(config.first)) { + if (listener != null) { + listener.onReadFailed(config.second); + } + } else { + MessagePad.SetAutopilotModeReq.Builder builder = MessagePad.SetAutopilotModeReq.newBuilder(); + String err = null; + try { + JsonFormat.parser().ignoringUnknownFields().merge(config.first, builder); + } catch (InvalidProtocolBufferException e) { + e.printStackTrace(); + err = e.getMessage(); + } + if (TextUtils.isEmpty(err)) { + MessagePad.SetAutopilotModeReq bean = builder.build(); + if (listener != null) { + listener.onParse(bean); + } + } else { + if (listener != null) { + listener.onParseFailed(err); + } + } + } + isReadConfig.set(false); + } + }; + new Thread(runnable).start(); + return true; + } + return false; + } + + /** + * @param file + * @return first:读取到的内容 second:失败信息 + */ + private Pair readFilesToString(File file) { + InputStream inputStream = null; + String err = null; + try { + inputStream = new FileInputStream(file); + byte[] buffer = new byte[1024]; + int length = -1; + StringBuilder stringBuilder = new StringBuilder(); + while ((length = inputStream.read(buffer)) != -1) { + stringBuilder.append(new String(buffer, 0, length)); + } + return new Pair(stringBuilder.toString(), err); + } catch (FileNotFoundException e) { + e.printStackTrace(); + err = e.toString(); + } catch (IOException e) { + e.printStackTrace(); + err = e.toString(); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return new Pair(null, err); + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/SweeperAnalyticsManager.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/SweeperAnalyticsManager.java new file mode 100644 index 0000000000..91b5820710 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/SweeperAnalyticsManager.java @@ -0,0 +1,149 @@ +package com.mogo.och.sweepercloud.util; + +import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_SWEEPER; + +import android.os.Build; +import android.text.TextUtils; + +import com.mogo.cloud.passport.MoGoAiCloudClientConfig; +import com.mogo.commons.debug.DebugConfig; +import com.mogo.commons.utils.MogoAnalyticUtils; +import com.mogo.eagle.core.data.app.AppConfigInfo; +import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; +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.DateTimeUtils; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; +import com.mogo.och.sweepercloud.constant.SweeperConst; + +import java.util.HashMap; + +/** + * OCH sweeper埋点工具 + * + * Created on 2022/3/24 + */ +public class SweeperAnalyticsManager { + + private static final class SingletonHolder { + private static final SweeperAnalyticsManager INSTANCE = new SweeperAnalyticsManager(); + } + + public static SweeperAnalyticsManager getInstance() { + return SweeperAnalyticsManager.SingletonHolder.INSTANCE; + } + + private String mStartAutopilotKey; + private HashMap mStartAutopilotParams = new HashMap<>(); + + private Runnable startAutopilotRunnable = () -> { + // 15s内未开启,上报失败埋点 + triggerStartAutopilotFailureEvent("", "15s后app等待超时"); + }; + + public void triggerStartAutopilotFailureEventByAdas(String failCode, String failMsg){ + removeWaitingCallback(); + triggerStartAutopilotFailureEvent(failCode, failMsg); + } + + private void triggerStartAutopilotFailureEvent(String failCode, String failMsg){ + if (mStartAutopilotParams.isEmpty()) return; + + CallerLogger.INSTANCE.e( M_SWEEPER + "triggerStartAutopilotFailureEvent", failMsg ); + + if (CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState() != + IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING){ + mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_FAILURE_CODE, failCode); + mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_FAILURE_MSG, failMsg); + } + mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_RESULT + , CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState() == + IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING); + + MogoAnalyticUtils.INSTANCE.track(mStartAutopilotKey, mStartAutopilotParams); + + clearStartAutopilotParams();//清空参数数据,防止误传 + } + + private void removeWaitingCallback() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + if (startAutopilotRunnable != null) { + UiThreadHandler.removeCallbacks(startAutopilotRunnable); + } + } + } + + public void clearStartAutopilotFailureMSG(){ + mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_FAILURE_CODE, ""); + mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_FAILURE_MSG, ""); + } + + private void clearStartAutopilotParams(){ + mStartAutopilotParams.clear(); + } + + /** + * 触发'开启自动驾驶'埋点流程 + * 开启自动驾驶,15s内成功则发送成功埋点,否则发送失败埋点 + * @param restart false(点击'滑动出发'启动)/true(接管后点击'自动驾驶'按钮启动) + * @param send 是否直接发送埋点(15s内开启成功则直接发送成功埋点) + */ + public void triggerStartAutopilotEvent( + boolean restart, boolean send, String startName, String endName, int lineId) { + mStartAutopilotKey = restart ? + SweeperConst.EVENT_KEY_RESTART_AUTOPILOT : SweeperConst.EVENT_KEY_START_SERVICE; + String sn = MoGoAiCloudClientConfig.getInstance().getSn(); + String plateNum = AppConfigInfo.INSTANCE.getPlateNumber(); + String dateTime = DateTimeUtils.getTimeText( + System.currentTimeMillis(), DateTimeUtils.yyyy_MM_dd_HH_mm_ss); + + mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_SN, sn); + mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_PLATE_NUM, TextUtils.isEmpty(plateNum) ? "" : plateNum); + mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_ENV_ONLINE, + DebugConfig.getNetMode() == DebugConfig.NET_MODE_RELEASE ? true : false); + mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_TIME, dateTime); + mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_NAME, startName); + mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_END_NAME, endName); + mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_LINE_ID, lineId); + + if (send) { + if (mStartAutopilotParams.isEmpty()) return; + // 开启成功,上报埋点 + clearStartAutopilotFailureMSG(); + removeWaitingCallback(); + mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_RESULT, true); + MogoAnalyticUtils.INSTANCE.track(mStartAutopilotKey, mStartAutopilotParams); + + clearStartAutopilotParams();//清空参数数据,防止误传 + } else { + UiThreadHandler.postDelayed(startAutopilotRunnable, SweeperConst.LOOP_PERIOD_15S); + } + } + + /** + * 触发"无法开启自驾已知异常"埋点 + * @param startName + * @param endName + * @param lineId + */ + public void triggerUnableStartAPReasonEvent(String startName, String endName, int lineId, + String reason) { + String sn = MoGoAiCloudClientConfig.getInstance().getSn(); + String plateNum = AppConfigInfo.INSTANCE.getPlateNumber(); + String dateTime = DateTimeUtils.getTimeText( + System.currentTimeMillis(), DateTimeUtils.yyyy_MM_dd_HH_mm_ss); + + HashMap params = new HashMap<>(); + + params.put(SweeperConst.EVENT_PARAM_SN, sn); + params.put(SweeperConst.EVENT_PARAM_PLATE_NUM, TextUtils.isEmpty(plateNum) ? "" : plateNum); + params.put(SweeperConst.EVENT_PARAM_ENV_ONLINE, + DebugConfig.getNetMode() == DebugConfig.NET_MODE_RELEASE ? true : false); + params.put(SweeperConst.EVENT_PARAM_TIME, dateTime); + params.put(SweeperConst.EVENT_PARAM_START_NAME, startName); + params.put(SweeperConst.EVENT_PARAM_END_NAME, endName); + params.put(SweeperConst.EVENT_PARAM_LINE_ID, lineId); + params.put(SweeperConst.EVENT_PARAM_UNABLE_START_REASON, reason); + MogoAnalyticUtils.INSTANCE.track(SweeperConst.EVENT_KEY_AP_UNABLE_START_REASON, params); + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/SweeperCloudTaskUtils.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/SweeperCloudTaskUtils.kt new file mode 100644 index 0000000000..25fb456c39 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/SweeperCloudTaskUtils.kt @@ -0,0 +1,348 @@ +package com.mogo.och.sweepercloud.util + +import android.content.Context +import com.elegant.utils.UiThreadHandler +import com.google.protobuf.MessageOrBuilder +import com.google.protobuf.TextFormat +import com.mogo.cloud.passport.MoGoAiCloudClientConfig +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import com.mogo.och.common.module.utils.DateTimeUtil +import com.mogo.och.common.module.voice.VoiceNotice +import com.mogo.och.sweepercloud.callback.SweeperCloudDialogClickListener +import com.mogo.och.sweepercloud.model.SweeperTaskModel +import com.mogo.och.sweepercloud.ui.dialog.SweeperCloudDialog +import com.zhjt.mogo.adas.data.sweeper.SweeperCloudTask.MessageType +import com.zhjt.mogo.adas.data.sweeper.bootable.SweeperBootable +import com.zhjt.mogo.adas.data.sweeper.common.SweeperCommon +import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask.* +import com.zhjt.mogo.adas.data.sweeper.task.big.SweeperBigTaskStatus +import com.zhjt.mogo.adas.data.sweeper.task.big.SweeperBigTaskStatus.BigTaskStatus +import com.zhjt.mogo.adas.data.sweeper.task.confirm.SweeperTaskConfirm.TaskConfirm +import com.zhjt.mogo.adas.data.sweeper.task.status.SweeperTaskStatus +import com.zhjt.mogo.adas.data.sweeper.task.stop.SweeperTaskStop +import java.util.* + +object SweeperCloudTaskUtils { + const val TAG = "SweeperCloudTaskUtils" + + /** + * 模拟发送查询当前任务的请求 + */ + @JvmStatic + fun mockQueryCurrentTaskInfo() { +// UiThreadHandler.getsUiHandler().postDelayed({ +// mockSendCloudTaskInfo(MessageType.PadSendGetTaskReq) +// },1000) + SweeperTaskModel.getInstance().getCurrentTask() + } + + /** + * 模拟云控发送任务给pad + */ + @JvmStatic + fun mockSendCloudTaskInfo(messageType: MessageType) { + val builder = TaskInfo.newBuilder() + builder.sn = getDriverSn() + builder.taskId = "10" + builder.taskName = "烟台清扫车作业任务" + builder.currentTime = System.currentTimeMillis() + builder.taskStartTime = 1683507615000 + builder.taskEndTime = 1683540015000 + //第一个子任务 + val subBuilder0 = SubTaskInfo.newBuilder() + subBuilder0.subTaskId = "1" + subBuilder0.subTaskName = "海水浴场-佛兴禅寺(前岛贴右)" + subBuilder0.taskModel = TaskModel.AUTO + subBuilder0.taskStatus = SweeperCommon.TaskStatus.TO_START + val startLocation0 = Location.newBuilder() + startLocation0.siteName = "自动驾驶子任务起点0" + startLocation0.wgsLongitude =112.56970262448544 + startLocation0.wgsLatitude = 26.817567832504274 + startLocation0.longitude = 112.57493487730413 + startLocation0.latitude = 26.81397095451884 + subBuilder0.startLocation = startLocation0.build() + val endLocation0 = Location.newBuilder() + endLocation0.siteName = "自动驾驶子任务终点0" + endLocation0.wgsLongitude = 112.57723562874442 + endLocation0.wgsLatitude = 26.819769725304003 + endLocation0.longitude = 112.5824598556873 + endLocation0.latitude = 26.81616501438377 + subBuilder0.endLocation = endLocation0.build() + subBuilder0.lineId = 123 + subBuilder0.lineName = "测试路线0" + builder.addSubList(subBuilder0.build()) + //第二个子任务 +// val subBuilder1 = SubTaskInfo.newBuilder() +// subBuilder1.subTaskId = "2" +// subBuilder1.subTaskName = "佛兴禅寺-海水浴场(前岛贴左)" +// subBuilder1.taskModel = TaskModel.AUTO +// subBuilder1.taskStatus = SweeperCommon.TaskStatus.TO_START +// val startLocation1 = Location.newBuilder() +// startLocation1.siteName = "自动驾驶子任务起点1" +// startLocation1.wgsLongitude = 112.57723562874442 +// startLocation1.wgsLatitude = 26.819769725304003 +// startLocation1.longitude = 112.5824598556873 +// startLocation1.latitude = 26.81616501438377 +// subBuilder1.startLocation = startLocation1.build() +// val endLocation1 = Location.newBuilder() +// endLocation1.siteName = "自动驾驶子任务终点1" +// endLocation1.wgsLongitude = 112.56970262448544 +// endLocation1.wgsLatitude = 26.817567832504274 +// endLocation1.longitude = 112.57493487730413 +// endLocation1.latitude = 26.81397095451884 +// subBuilder1.endLocation = endLocation1.build() +// subBuilder1.lineId = 124 +// subBuilder1.lineName = "测试路线1" +// builder.addSubList(subBuilder1.build()) +// //第三个子任务 +// val subBuilder2 = SubTaskInfo.newBuilder() +// subBuilder2.subTaskId = "3" +// subBuilder2.subTaskName = "海水浴场-佛兴禅寺(前岛贴左)" +// subBuilder2.taskModel = TaskModel.MANUAL +// subBuilder2.taskStatus = SweeperCommon.TaskStatus.TO_START +// val startLocation2 = Location.newBuilder() +// startLocation2.siteName = "人工驾驶子任务起点2" +// startLocation2.wgsLongitude = 121.31344761929978 +// startLocation2.wgsLatitude = 37.53205755535642 +// startLocation2.longitude = 121.3185679517558 +// startLocation2.latitude = 37.5329694887952 +// subBuilder2.startLocation = startLocation2.build() +// val endLocation2 = Location.newBuilder() +// endLocation2.siteName = "人工驾驶子任务终点2" +// endLocation2.wgsLongitude = 121.4551205070834 +// endLocation2.wgsLatitude = 37.47936696980237 +// endLocation2.longitude = 121.46030960742117 +// endLocation2.latitude = 37.48032689641474 +// subBuilder2.endLocation = endLocation2.build() +// subBuilder2.lineId = 125 +// subBuilder2.lineName = "测试路线2" +// builder.addSubList(subBuilder2.build()) +// //第四个子任务 +// val subBuilder3 = SubTaskInfo.newBuilder() +// subBuilder3.subTaskId = "4" +// subBuilder3.subTaskName = "海水浴场-佛兴禅寺(前岛贴左第四个任务)" +// subBuilder3.taskModel = TaskModel.MANUAL +// subBuilder3.taskStatus = SweeperCommon.TaskStatus.TO_START +// val startLocation3 = Location.newBuilder() +// startLocation3.siteName = "人工驾驶子任务起点3" +// startLocation3.wgsLongitude = 121.31344761929978 +// startLocation3.wgsLatitude = 37.53205755535642 +// startLocation3.longitude = 121.3185679517558 +// startLocation3.latitude = 37.5329694887952 +// subBuilder3.startLocation = startLocation3.build() +// val endLocation3 = Location.newBuilder() +// endLocation3.siteName = "人工驾驶子任务终点3" +// endLocation3.wgsLongitude = 121.4551205070834 +// endLocation3.wgsLatitude = 37.47936696980237 +// endLocation3.longitude = 121.46030960742117 +// endLocation3.latitude = 37.48032689641474 +// subBuilder3.endLocation = endLocation3.build() +// subBuilder3.lineId = 126 +// subBuilder3.lineName = "测试路线3" +// builder.addSubList(subBuilder3.build()) + SweeperTaskModel.getInstance().onSweeperFutianCloudTask( + messageType, + "${System.currentTimeMillis()}", + System.currentTimeMillis(), + builder.build() + ) + CallerLogger.d(SceneConstant.M_SWEEPER + TAG, "messageType:" + messageType.number + "taskInfo:" + printMessage(builder.build())) + } + + /** + * 模拟云控发送子任务开始确认信息 + */ + @JvmStatic + fun mockSendCloudSubTaskConfirm() { + val builder = TaskConfirm.newBuilder() + builder.sn = getDriverSn() + builder.taskId = "10" + builder.subTaskId = "1" + SweeperTaskModel.getInstance().onSweeperFutianCloudTaskConfirm( + MessageType.CloudPushTaskConfirm, "${System.currentTimeMillis()}", + System.currentTimeMillis(), builder.build() + ) + } + + /** + * 模拟下发更新子任务状态指令 + */ + @JvmStatic + fun mockSendCloudUpdateSubTaskStatus() { + val builder = SweeperTaskStatus.TaskStatusPush.newBuilder() + builder.sn = getDriverSn() + builder.taskId = "10" + builder.subTaskId = "1" + builder.taskStatus = SweeperCommon.TaskStatus.RUNNING + SweeperTaskModel.getInstance().onSweeperFutianCloudTaskStatus( + MessageType.CloudPushTaskStatus, "${System.currentTimeMillis()}", + System.currentTimeMillis(), builder.build() + ) + } + + /** + * 模拟云端发送大任务结束 + */ + @JvmStatic + fun mockSendCloudBigTaskEnd() { + val builder = SweeperTaskStop.StopTaskReq.newBuilder() + builder.sn = getDriverSn() + builder.taskId = "10" + builder.type = SweeperTaskStop.StopTaskType.ADVANCE + SweeperTaskModel.getInstance().onSweeperFutianCloudTaskStop( + MessageType.CloudPushTaskStop, "${System.currentTimeMillis()}", + System.currentTimeMillis(), builder.build() + ) + } + + /** + * 模拟云端发送大任务状态给pad + */ + @JvmStatic + fun mockSendCloudBigTaskStatus() { + val builder = SweeperBigTaskStatus.BigTaskStatusPush.newBuilder() + builder.sn = getDriverSn() + builder.taskId = "10" + builder.taskStatus = BigTaskStatus.FINISHED + builder.systemTime = System.currentTimeMillis() + SweeperTaskModel.getInstance().onSweeperFutianCloudBigTaskStatus( + MessageType.CloudPushBigTaskStatus, "${System.currentTimeMillis()}", + System.currentTimeMillis(), builder.build() + ) + } + + /** + * 模拟云端发送是否可以启动自驾 + */ + @JvmStatic + fun mockSendCloudBootable() { + val builder = SweeperBootable.IsBootableResp.newBuilder() + builder.sn = getDriverSn() + builder.taskId = "10" + builder.subTaskId = "1" + builder.code = SweeperCommon.Code.SUCCEED + UiThreadHandler.getsUiHandler().postDelayed({ + SweeperTaskModel.getInstance().onSweeperFutianCloudBootable( + MessageType.PadSendBootable, "${System.currentTimeMillis()}", + System.currentTimeMillis(), builder.build() + ) + }, 10000) + } + + private fun getDriverSn(): String? { + return MoGoAiCloudClientConfig.getInstance().sn + } + + /** + * 创建接收任务弹窗 + */ + @JvmStatic + fun createReceivedTaskInfoDialog(context: Context?, listener: SweeperCloudDialogClickListener?, taskInfo: TaskInfo): SweeperCloudDialog? { + var builder: SweeperCloudDialog.Builder = SweeperCloudDialog.Builder() + val startCalendar = DateTimeUtil.formatLongToCalendar(taskInfo.taskStartTime) + val endCalendar = DateTimeUtil.formatLongToCalendar(taskInfo.taskEndTime) + builder.titleStr = "任务接取" + builder.contentStr = "请确认是否接取${taskInfo.taskName}" + builder.tipStr = "(任务时间${DateTimeUtil.formatCalendarToString(startCalendar, DateTimeUtil.HH_mm)}-${ + DateTimeUtil.formatCalendarToString( + endCalendar, + DateTimeUtil.HH_mm + ) + })" + builder.leftStr = "确认" + builder.middleStr = "" + builder.rightStr = "拒绝" + builder.countDownTime = 15 + builder.listener = listener + return context?.let { it1 -> builder.build(it1) } + } + + /** + * 创建确认开始子任务弹窗 + */ + @JvmStatic + fun createConfirmStartSubTaskDialog( + context: Context?, + listener: SweeperCloudDialogClickListener?, + subTaskInfo: SubTaskInfo + ): SweeperCloudDialog? { + var builder: SweeperCloudDialog.Builder = SweeperCloudDialog.Builder() + builder.titleStr = "任务确认" + builder.contentStr = "请确认是否执行${subTaskInfo.subTaskName}" + builder.tipStr = + if (subTaskInfo.taskModel == TaskModel.MANUAL) "[需手动驾驶至终点${subTaskInfo.endLocation.siteName}]" else "[自动驾驶至终点${subTaskInfo.endLocation.siteName}]" + builder.leftStr = "确认" + builder.middleStr = "下一个" + builder.rightStr = "结束" + builder.countDownTime = 15 + builder.listener = listener + return context?.let { it1 -> builder.build(it1) } + } + + /** + * 创建结束任务弹窗 + */ + @JvmStatic + fun createSweeperTaskEndDialog( + context: Context?, + listener: SweeperCloudDialogClickListener?, + stopTaskType: SweeperTaskStop.StopTaskType, + timeoutStr: String + ): SweeperCloudDialog? { + var builder: SweeperCloudDialog.Builder = SweeperCloudDialog.Builder() + builder.titleStr = "任务结束" + when (stopTaskType) { + //任务提前结束 + SweeperTaskStop.StopTaskType.ADVANCE -> { + builder.contentStr = "云端请求终止任务,请确认" + builder.tipStr = "【确认后请接管停车】" + builder.leftStr = "确认" + builder.middleStr = "" + builder.rightStr = "拒绝" + VoiceNotice.showNotice("云端请求终止任务,请确认") + } + //任务超时结束 + SweeperTaskStop.StopTaskType.TIMEOUT -> { + builder.contentStr = "任务已超时${timeoutStr},请确认是否结束" + builder.tipStr = "【结束后请接管停车】" + builder.leftStr = "确认" + builder.middleStr = "" + builder.rightStr = "拒绝" + VoiceNotice.showNotice("任务已超时${timeoutStr},请确认是否结束") + } + } + builder.countDownTime = 15 + builder.listener = listener + return context?.let { it1 -> builder.build(it1) } + } + + /** + * 任务正常结束弹窗 + */ + @JvmStatic + fun createSweeperTaskNormalEndDialog( + context: Context?, + listener: SweeperCloudDialogClickListener? + ): SweeperCloudDialog? { + var builder: SweeperCloudDialog.Builder = SweeperCloudDialog.Builder() + builder.titleStr = "任务结束" + builder.contentStr = "任务已完成,干的漂亮!" + builder.tipStr = "" + builder.leftStr = "确认" + builder.middleStr = "" + builder.rightStr = "" + builder.countDownTime = 10 + builder.listener = listener + return context?.let { it1 -> builder.build(it1) } + } + + @JvmStatic + fun printMessage(message: MessageOrBuilder): String { + return "\n"+TextFormat.printer().escapingNonAscii(false).printToString(message) + } + @JvmStatic + fun getRequestId():String{ + return UUID.randomUUID().toString() + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/SweeperFutianCmdUtil.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/SweeperFutianCmdUtil.java new file mode 100644 index 0000000000..35e2a0963b --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/SweeperFutianCmdUtil.java @@ -0,0 +1,202 @@ +package com.mogo.och.sweepercloud.util; + +import chassis.ChassisStatesOuterClass; +import chassis.SpecialVehicleTaskCmdOuterClass; + +/** + * 清扫车-福田,构建业务命令数据的工具类 + */ +public class SweeperFutianCmdUtil { + public static final int CLEAN_WORK_OPEN = 1; //清扫作业-开启 + public static final int CLEAN_WORK_CLOSE = 2;//清扫作业-关闭 + public static final int CLEAN_MODE_PURE_SWEEP = 1;//作业模式-纯扫 + public static final int CLEAN_MODE_WASH_SWEEP = 2;//作业模式-洗扫 + public static final int CLEAN_MODE_PURE_WASH = 3;//作业模式-纯洗 + public static final int CLEAN_MODE_PURE_DRAW = 4;//作业模式-纯吸 + public static final int CLEAN_MODE_CLOSE = 5;//作业模式-关闭 + public static final int CLEAN_DIRECTION_BOTH_SIDE = 1;//清扫方向-两侧 + public static final int CLEAN_DIRECTION_LEFT_SIDE = 2;//清扫方向-左侧 + public static final int CLEAN_DIRECTION_RIGHT_SIDE = 3;//清扫方向-右侧 + public static final int CLEAN_DIRECTION_CLOSE = 4;//清扫方向-关闭 + public static final int CLEAN_INTENSITY_STRAND = 1;//作业强度-标准 + public static final int CLEAN_INTENSITY_STRONG = 2;//作业强度-加强 + + /** + * 清扫作业:打开 + * + * @return + */ + public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanWorkStartCmd() { + return buildCleanWorkCmd(CLEAN_WORK_OPEN); + } + + /** + * 清扫作业:关闭 + * + * @return + */ + public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanWorkStopCmd() { + return buildCleanWorkCmd(CLEAN_WORK_CLOSE); + } + + + private static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanWorkCmd(int startOrStop) { + SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder(); + builder.setCleanOpenRequirement(startOrStop); + return buildTaskCmd(builder.build()); + } + + /** + * 作业模式:传入具体的模式对应的值 + * + * @param value + * @return + */ + public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanModeCmd(int value) { + SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder(); + builder.setCleanModeRequirement(value); + return buildTaskCmd(builder.build()); + } + + /** + * 作业模式:纯吸 + * + * @return + */ + public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanModePureDrawCmd() { + SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder(); + builder.setCleanModeRequirement(CLEAN_MODE_PURE_DRAW); + //不用设置作业方向,自动设置作业强度为:标准 + builder.setCleanIntensityRequirement(CLEAN_INTENSITY_STRAND); + return buildTaskCmd(builder.build()); + } + + /** + * 作业模式:关闭作业模式 + * + * @return + */ + public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanModeCloseCmd() { + SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder(); + builder.setCleanModeRequirement(CLEAN_MODE_CLOSE); + //关闭清扫方向,待下次在选择 + builder.setCleanDirectionRequirement(CLEAN_DIRECTION_CLOSE); + //自动设置作业强度为:标准 + builder.setCleanIntensityRequirement(CLEAN_INTENSITY_STRAND); + return buildTaskCmd(builder.build()); + } + + /** + * 作业方向:根据具体的方向传入具体的值 + * + * @param value + * @return + */ + public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanDirectionCmd(int value) { + SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder(); + builder.setCleanDirectionRequirement(value); + builder.setCleanIntensityRequirement(CLEAN_INTENSITY_STRAND); + // 同时作业强度默认:标准 + return buildTaskCmd(builder.build()); + } + + /** + * 作业方向:关闭作业方向 + * + * @return + */ + public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanDirectionCloseCmd() { + SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder(); + builder.setCleanDirectionRequirement(CLEAN_DIRECTION_CLOSE); + //重置作业强度为标准 + builder.setCleanIntensityRequirement(CLEAN_INTENSITY_STRAND); + return buildTaskCmd(builder.build()); + } + + /** + * 作业强度:传入具体的值 + * + * @param value + * @return + */ + public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanIntensityCmd(int value) { + SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder(); + builder.setCleanIntensityRequirement(value); + return buildTaskCmd(builder.build()); + } + + private static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildTaskCmd( + SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd fuTianCleanCmd) { + return SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd.newBuilder() + .setRoboSweeperFutianCleanCmd(fuTianCleanCmd).build(); + } + + /** + * 判断是否有作业模式 + * @param cleanSystemState + * @return true:没有作业模式 false:有作业模式 + */ + public static boolean checkIfCleanMode(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState){ + return (!cleanSystemState.getSecuModWashSweepSts()&&!cleanSystemState.getSecuModWashSts()&&!cleanSystemState.getSecuWorkTonSts())&& + (!cleanSystemState.getSecuWorkLeftSts()&&!cleanSystemState.getSecuWorkRightSts()&&!cleanSystemState.getSecuWorkOnBothsidesSts()); + } + + /** + * 判断是否有清扫方向 + * @param cleanSystemState + * @return true:没有清扫方向 false:有清扫方向 + */ + public static boolean checkIfCleanDirection(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState){ + return !cleanSystemState.getSecuWorkLeftSts()&&!cleanSystemState.getSecuWorkRightSts()&&!cleanSystemState.getSecuWorkOnBothsidesSts(); + } + /** + * 判断是否有作业强度 + * @param cleanSystemState + * @return true:没有作业强度 false:有作业强度 + */ + public static boolean checkIfCleanIntensity(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState){ + return !cleanSystemState.getSecuWorkStandSts()&&!cleanSystemState.getSecuWorkStrongSts(); + } + /** + * 判断是否纯扫模式 + * + * @param cleanSystemState + * @return + */ + public static boolean checkIfCleanModePureSweep(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) { + // 作业模式状态 + // 洗扫 + boolean clean_mode_wash_sweep = cleanSystemState.getSecuModWashSweepSts(); + // 纯洗 + boolean clean_mode_pure_wash = cleanSystemState.getSecuModWashSts(); + // 纯吸 + boolean clean_mode_pure_draw = cleanSystemState.getSecuWorkTonSts(); + + // 清扫方向状态 + // 左侧 + boolean clean_direction_left_side = cleanSystemState.getSecuWorkLeftSts(); + // 右侧 + boolean clean_direction_right_side = cleanSystemState.getSecuWorkRightSts(); + // 两侧 + boolean clean_direction_both_side = cleanSystemState.getSecuWorkOnBothsidesSts(); + + // 纯扫 模式判断:不是另外其他3个模式,同时有清扫方向,说明开启了纯扫模式 + boolean clean_mode_pure_sweep = (clean_direction_left_side || clean_direction_right_side || clean_direction_both_side) + && (!clean_mode_wash_sweep && !clean_mode_pure_wash && !clean_mode_pure_draw); + return clean_mode_pure_sweep; + } + /** + * 构建底盘Mock数据 + * + * @return + */ + public static ChassisStatesOuterClass.SweeperFuTianTaskSystemStates buildSweeperFuTionCleanSystemStateMockData() { + ChassisStatesOuterClass.SweeperFuTianTaskSystemStates.Builder builder = ChassisStatesOuterClass.SweeperFuTianTaskSystemStates.newBuilder(); + builder.setSecuMotWorkSts(true); + builder.setSecuModWashSts(true); + builder.setSecuWorkOnBothsidesSts(true); + builder.setSecuWorkStrongSts(true); + return builder.build(); + } + +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/SweeperMapAssetStyleUtil.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/SweeperMapAssetStyleUtil.java new file mode 100644 index 0000000000..57d39a354b --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/util/SweeperMapAssetStyleUtil.java @@ -0,0 +1,61 @@ +package com.mogo.och.sweepercloud.util; + + +import android.content.Context; + +import java.io.IOException; +import java.io.InputStream; + +/** + * @author donghongyu + * @date 12/18/20 5:37 PM + */ +public class SweeperMapAssetStyleUtil { + + public static byte[] getAssetsStyle(Context context,String fileName) { + byte[] buffer1 = null; + InputStream is1 = null; + try { + is1 = context.getResources().getAssets().open(fileName); //eg. over_view_style.data + int lenght1 = is1.available(); + buffer1 = new byte[lenght1]; + is1.read(buffer1); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (is1 != null) { + is1.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return buffer1; + } + + + public static byte[] getAssetsExtraStyle(Context context, String fileName) { + byte[] buffer1 = null; + InputStream is1 = null; + try { + is1 = context.getResources().getAssets().open(fileName); //eg. over_view_style_extra.data + int lenght1 = is1.available(); + buffer1 = new byte[lenght1]; + is1.read(buffer1); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (is1 != null) { + is1.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return buffer1; + } + + +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/CountDownView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/CountDownView.kt new file mode 100644 index 0000000000..5790ef8072 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/CountDownView.kt @@ -0,0 +1,65 @@ +package com.mogo.och.sweepercloud.view + +import android.content.Context +import android.os.Handler +import android.os.Message +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView +/** + * 倒计时View + */ +class CountDownView : AppCompatTextView, Handler.Callback { + private val mHandler = Handler(this) + private var mCountDownTime = DEFAULT_COUNT_DOWN_TIME + private var listener: CountDownListener? = null + + constructor(context: Context?) : super(context!!) {} + constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs) {} + constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context!!, attrs, defStyleAttr) {} + + override fun handleMessage(message: Message): Boolean { + if (message.what == MSG_COUNT_DOWN) { + mCountDownTime-- + if (mCountDownTime > 0) { + text = "$mCountDownTime" + mHandler.sendEmptyMessageDelayed(MSG_COUNT_DOWN, DEFAULT_COUNT_DOWN_DELAY) + } else { + stopCountDown() + listener?.stop() + } + } + return false + } + + fun setCountDownListener(listener: CountDownListener?) { + this.listener = listener + } + + /** + * 启动倒计时 + */ + fun startCountDown(countDownTime:Int) { + mHandler.removeMessages(MSG_COUNT_DOWN) + text = "$countDownTime" + mCountDownTime=countDownTime + mHandler.sendEmptyMessageDelayed(MSG_COUNT_DOWN, DEFAULT_COUNT_DOWN_DELAY) + } + + /** + * 停止倒计时 + */ + fun stopCountDown() { + mHandler.removeMessages(MSG_COUNT_DOWN) + text = null + } + + interface CountDownListener { + fun stop() + } + + companion object { + private const val DEFAULT_COUNT_DOWN_TIME = 15 + private const val MSG_COUNT_DOWN = 1001 + private const val DEFAULT_COUNT_DOWN_DELAY = 1000L + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/FontAdaptionTextView.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/FontAdaptionTextView.java new file mode 100644 index 0000000000..816baff142 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/FontAdaptionTextView.java @@ -0,0 +1,47 @@ +package com.mogo.och.sweepercloud.view; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.widget.TextView; + +public class FontAdaptionTextView extends TextView { + public FontAdaptionTextView(Context context) { + super(context); + } + + public FontAdaptionTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public FontAdaptionTextView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (getMeasuredWidth() != 0) { + + //判断View字体行数 + if (getLayout().getLineCount() > 1) { + //获取view内部间隔 + int l = getPaddingLeft(); + int r = getPaddingRight(); + float pp = 0; + //计算字符串长度 + for (int i = 0; i < getLayout().getLineCount(); i++) { + pp = pp + l + r + getLayout().getLineWidth(i); + } + + //计算view的宽度与字符串长度的比例 + float f = getMeasuredWidth() / pp; + //获取缩放后的字体高度 + float s = getTextSize() * f; + //设置控件字体大小 + setTextSize(TypedValue.COMPLEX_UNIT_PX, s); + } + } + } + +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/LegendItemView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/LegendItemView.kt new file mode 100644 index 0000000000..b5598dce04 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/LegendItemView.kt @@ -0,0 +1,32 @@ +package com.mogo.och.sweepercloud.view + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.LinearLayout +import com.mogo.och.sweepercloud.R +import kotlinx.android.synthetic.main.sweeper_item_legend.view.* + +/** + * 任务路线全览图图例 + */ +class LegendItemView:LinearLayout { + constructor(context: Context) : super(context) {} + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + initView(context) + } + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {} + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {} + + private fun initView(context: Context) { + LayoutInflater.from(context).inflate(R.layout.sweeper_item_legend, this) + } + + /** + * 设置数据 + */ + fun setData(resId:Int,text:String){ + sweeperLegendIcon.setImageResource(resId) + sweeperLegendText.text = text + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/NoTouchConstraintLayout.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/NoTouchConstraintLayout.java new file mode 100644 index 0000000000..0e5714b7cf --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/NoTouchConstraintLayout.java @@ -0,0 +1,45 @@ +package com.mogo.och.sweepercloud.view; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import androidx.constraintlayout.widget.ConstraintLayout; + +/** + * 强制拦截所有touch时间的约束布局 + * + * @author tongchenfei + */ +public class NoTouchConstraintLayout extends ConstraintLayout { + private boolean interceptTouchEvent = false; + + public NoTouchConstraintLayout(Context context) { + super(context); + } + + public NoTouchConstraintLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public NoTouchConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (interceptTouchEvent) { + return true; + } + return false; + } + + /** + * 设置事件拦截 + * + * @param interceptTouchEvent + */ + public void setInterceptTouchEvent(boolean interceptTouchEvent) { + this.interceptTouchEvent = interceptTouchEvent; + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/NoTouchFrameLayout.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/NoTouchFrameLayout.java new file mode 100644 index 0000000000..10ff08d760 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/NoTouchFrameLayout.java @@ -0,0 +1,30 @@ +package com.mogo.och.sweepercloud.view; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.widget.FrameLayout; + +/** + * 强制拦截所有touch时间的约束布局 + * + * @author tongchenfei + */ +public class NoTouchFrameLayout extends FrameLayout { + public NoTouchFrameLayout(Context context) { + super(context); + } + + public NoTouchFrameLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public NoTouchFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return false; + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SubTaskView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SubTaskView.kt new file mode 100644 index 0000000000..32559b6bdc --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SubTaskView.kt @@ -0,0 +1,48 @@ +package com.mogo.och.sweepercloud.view + +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import androidx.constraintlayout.widget.ConstraintLayout +import com.mogo.och.sweepercloud.R +import com.zhjt.mogo.adas.data.sweeper.common.SweeperCommon +import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask.SubTaskInfo +import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask.TaskModel +import kotlinx.android.synthetic.main.sweeper_subtask_view.view.* + +/** + * 子任务View + */ +class SubTaskView : ConstraintLayout { + constructor(context: Context) : super(context) {} + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + initView(context) + } + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {} + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {} + + private fun initView(context: Context) { + LayoutInflater.from(context).inflate(R.layout.sweeper_subtask_view, this) + } + + /** + * 设置子任务信息 + */ + fun setData(taskInfo: SubTaskInfo,isLastTask: Boolean = false) { + tvSubTaskName.text = taskInfo.subTaskName + tvSubTaskName.setTextColor(if (taskInfo.taskStatus==SweeperCommon.TaskStatus.RUNNING) Color.parseColor("#3BD2FF") else Color.parseColor("#FFFFFF")) + if (taskInfo.taskModel == TaskModel.MANUAL) {//人工驾驶子任务 + ivManualDriving.visibility = View.VISIBLE + } else { + ivManualDriving.visibility = View.GONE + } + if (taskInfo.taskStatus==SweeperCommon.TaskStatus.RUNNING) { + ivSubTask.setImageResource(R.drawable.sweeper_icon_select_subtask) + } else { + ivSubTask.setImageResource(R.drawable.sweeper_icon_not_select_subtask) + } + ivRightDownArrow.visibility = if (isLastTask) View.GONE else View.VISIBLE + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperCurrentTaskInfoView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperCurrentTaskInfoView.kt new file mode 100644 index 0000000000..3bdbcea852 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperCurrentTaskInfoView.kt @@ -0,0 +1,128 @@ +package com.mogo.och.sweepercloud.view + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import com.mogo.och.common.module.utils.DateTimeUtil +import com.mogo.och.sweepercloud.R +import com.zhjt.mogo.adas.data.sweeper.common.SweeperCommon.TaskStatus +import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask.SubTaskInfo +import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask.TaskInfo +import kotlinx.android.synthetic.main.sweeper_current_task_info.view.* + +/** + * 清扫车当前任务信息展示 + */ +class SweeperCurrentTaskInfoView : ConstraintLayout { + private val TAG: String = "SweeperCurrentTaskInfoView" + + //当前任务操作菜单 + private var listTask: List? = null + + constructor(context: Context) : super(context) {} + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + initView(context) + } + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {} + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {} + + private fun initView(context: Context) { + LayoutInflater.from(context).inflate(R.layout.sweeper_current_task_info, this) + setSubTaskState(false) + } + + fun getAutoBtn(): TextView { + return tvStartAuto + } + + /** + * 设置当前任务数据 + */ + fun setData( + subTaskBean: TaskInfo?, + currentPosition: Int = -1 + ) { + subTaskBean?.apply { + this@SweeperCurrentTaskInfoView.listTask = subListList + tvTaskName.text = taskName + val calendarStart = DateTimeUtil.formatLongToCalendar(taskStartTime) + val calendarEnd = DateTimeUtil.formatLongToCalendar(taskEndTime) + tvTaskTime.text = "${DateTimeUtil.formatCalendarToString(calendarStart, DateTimeUtil.HH_mm)}-${ + DateTimeUtil.formatCalendarToString( + calendarEnd, + DateTimeUtil.HH_mm + ) + }" + } + listTask?.let { + //特殊处理当前暂无执行中任务的情况 + if (currentPosition == -1) { + setSubTaskState(false) + setCurrentData(currentPosition + 1) + } else { + setSubTaskState(it[currentPosition].taskStatus == TaskStatus.RUNNING) + setCurrentData(currentPosition) + } + } + } + + /** + * 设置子任务的状态 + */ + private fun setSubTaskState(isWorking: Boolean) { + if (isWorking) { + tvTaskState.text = "正在作业" + tvTaskState.setBackgroundResource(R.drawable.bg_shape_task_state_working) + } else { + tvTaskState.text = "暂未准备" + tvTaskState.setBackgroundResource(R.drawable.bg_shape_task_state_not_ready) + } + } + + /** + * 填充数据 + */ + private fun setCurrentData(currentPosition: Int) { + listTask?.let { + if (it.size == 1) { + preSubTask.setData(it[currentPosition], isLastTask = true) + currentSubTask.visibility = View.INVISIBLE + lastSubTask.visibility = View.INVISIBLE + } else if (it.size == 2) { + if (currentPosition == 0) { + preSubTask.setData(it[currentPosition]) + currentSubTask.setData(it[1], isLastTask = true) + } else { + preSubTask.setData(it[currentPosition - 1]) + currentSubTask.setData(it[currentPosition], isLastTask = true) + } + preSubTask.visibility = View.VISIBLE + currentSubTask.visibility = View.VISIBLE + lastSubTask.visibility = View.GONE + } else { + preSubTask.visibility = View.VISIBLE + currentSubTask.visibility = View.VISIBLE + lastSubTask.visibility = View.VISIBLE + //当前正在执行的任务是第一个子任务 + if (currentPosition == 0) { + preSubTask.setData(it[currentPosition]) + currentSubTask.setData(it[1]) + lastSubTask.setData(it[2], isLastTask = true) + //当前正在执行的任务是最后一个子任务 + } else if (currentPosition == it.size - 1) { + preSubTask.setData(it[currentPosition - 2]) + currentSubTask.setData(it[currentPosition - 1]) + lastSubTask.setData(it[currentPosition], isLastTask = true) + } else { + preSubTask.setData(it[currentPosition - 1]) + currentSubTask.setData(it[currentPosition]) + lastSubTask.setData(it[currentPosition + 1], isLastTask = true) + } + } + } + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperLimitingVelocityView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperLimitingVelocityView.kt new file mode 100644 index 0000000000..f7c2dff777 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperLimitingVelocityView.kt @@ -0,0 +1,59 @@ +package com.mogo.och.sweepercloud.view + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.LinearLayout +import com.mogo.eagle.core.data.enums.DataSourceType +import com.mogo.eagle.core.function.api.hmi.view.IViewControlListener +import com.mogo.eagle.core.function.api.hmi.view.IViewControlListener.Companion.LimitingVelocityView_TAG +import com.mogo.eagle.core.function.api.datacenter.union.ILimitingVelocityListener +import com.mogo.eagle.core.function.call.hmi.CallerHmiViewControlListenerManager +import com.mogo.eagle.core.function.call.v2x.CallerLimitingVelocityListenerManager +import com.mogo.eagle.core.utilcode.util.ThreadUtils +import com.mogo.och.sweepercloud.R +import kotlinx.android.synthetic.main.sweeper_limiting_speed.view.* + +class SweeperLimitingVelocityView( + context: Context, + attrs: AttributeSet? = null, +) : LinearLayout(context, attrs), ILimitingVelocityListener, IViewControlListener { + + companion object { + private const val TAG = "SweeperLimitingVelocityView" + } + + init { + LayoutInflater.from(context).inflate(R.layout.sweeper_limiting_speed, this, true) + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + CallerLimitingVelocityListenerManager.addListener(TAG, this) + CallerHmiViewControlListenerManager.addListener(LimitingVelocityView_TAG, this) + } + + override fun onLimitingVelocityChange(limitingVelocity: Int, sourceType: DataSourceType) { + ThreadUtils.runOnUiThread { + if (limitingVelocity > 0) { + this.visibility = View.VISIBLE + tvLimitingVelocity.text = "$limitingVelocity" + } else { + this.visibility = View.GONE + } + } + } + + override fun visible(v: Int) { + super.visible(v) + this.visibility = v + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + CallerLimitingVelocityListenerManager.removeListener(TAG) + CallerHmiViewControlListenerManager.removeListener(LimitingVelocityView_TAG) + } + +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperTrafficDataView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperTrafficDataView.kt new file mode 100644 index 0000000000..6ee2639db7 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperTrafficDataView.kt @@ -0,0 +1,196 @@ +package com.mogo.och.sweepercloud.view + +import android.annotation.SuppressLint +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.ImageView +import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import chassis.Chassis.GearPosition +import chassis.Chassis.LightSwitch +import chassis.ChassisStatesOuterClass.BMSSystemStates +import chassis.ChassisStatesOuterClass.SweeperFuTianTaskSystemStates +import com.elegant.utils.UiThreadHandler +import com.mogo.eagle.core.function.api.autopilot.* +import com.mogo.eagle.core.function.call.autopilot.* +import com.mogo.eagle.core.function.hmi.ui.widget.TapPositionView +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import com.mogo.eagle.core.utilcode.util.ThreadUtils +import com.mogo.och.sweepercloud.R +import planning.RoboSweeperTaskIndexOuterClass +import kotlin.math.roundToInt + +/** + * 车辆基本信息:方向盘下方的档位 转向灯 限速 速度 电量 水量 + */ +class SweeperTrafficDataView : ConstraintLayout, + IMoGoBatteryManagementSystemListener, + IMoGoChassisLamplightListener, + IMoGoChassisGearStateListener, + IMoGoSweeperFutianCleanSystemListener { + private var tapPositionView //方向盘下方的档位 + : TapPositionView? = null + private var speedImage //速度图标 + : ImageView? = null + private var speedTextView //速度值 + : TextView? = null + private var sweeperAutoState //自动驾驶状态 + : TextView? = null + private var tvBattery //电量百分比展示 + : TextView? = null + private var ivBgWaterWarning //水位预警背景图 + : ImageView? = null + private var ivWater //水位图标 + : ImageView? = null + + private val TAG = "SweeperTrafficDataView" + + // 底盘数据回调时间间隔 + private val VEHICLE_STATE_INTERVAL_MILLIS = 500L + + // 当前时间戳 + private var mCurrentTimeWaterMillis: Long = 0 + + private var mCurrentTimeBatteryMillis: Long = 0 + + constructor(context: Context) : super(context) {} + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + initView(context) + } + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {} + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {} + + private fun initView(context: Context) { + LayoutInflater.from(context).inflate(R.layout.sweeper_traffic_data, this) + tapPositionView = findViewById(R.id.sweeperTrafficPosition) + speedImage = findViewById(R.id.sweeperSpeedImage) + speedTextView = findViewById(R.id.sweeperSpeedText) + sweeperAutoState = findViewById(R.id.sweeperAutoState) + tvBattery = findViewById(R.id.tvBattery) + ivBgWaterWarning = findViewById(R.id.sweeperIvBgWaterWarning) + ivWater = findViewById(R.id.sweeperIvWater) + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + //电量 + CallerBatteryManagementSystemListenerManager.addListener(TAG, this) + //转向灯 + CallerChassisLamplightListenerManager.addListener(TAG, this) + //档位 + CallerChassisGearStateListenerManager.addListener(TAG, this) + //清扫车相关数据接口 + CallerSweeperFutianCleanSystemListenerManager.addListener(TAG, this) + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + CallerBatteryManagementSystemListenerManager.removeListener(TAG) + CallerChassisLamplightListenerManager.removeListener(TAG) + CallerChassisGearStateListenerManager.removeListener(TAG) + CallerSweeperFutianCleanSystemListenerManager.removeListener(TAG) + } + + override fun onSweeperFutianTaskIndexData(roboSweeperTaskIndex: RoboSweeperTaskIndexOuterClass.RoboSweeperTaskIndex) {} + override fun onSweeperFutianCleanSystemState(cleanSystemState: SweeperFuTianTaskSystemStates) { + val current = System.currentTimeMillis() + if (current - mCurrentTimeWaterMillis <= VEHICLE_STATE_INTERVAL_MILLIS) { + return + } + mCurrentTimeWaterMillis = current + d(SceneConstant.M_SWEEPER + TAG, "水位:${cleanSystemState.hasSecuCleanWaterTankLow()}") + UiThreadHandler.post { + if (cleanSystemState.hasSecuCleanWaterTankLow()) { //清水箱水位低不能清洗作业报警信号 + ivBgWaterWarning?.visibility = VISIBLE + ivWater?.isSelected = true + } else { + ivBgWaterWarning?.visibility = GONE + ivWater?.isSelected = false + } + } + + } + + @SuppressLint("SetTextI18n") + override fun onBatteryManagementSystemStates(states: BMSSystemStates) { + val current = System.currentTimeMillis() + if (current - mCurrentTimeBatteryMillis <= VEHICLE_STATE_INTERVAL_MILLIS) { + return + } + mCurrentTimeBatteryMillis = current + d(SceneConstant.M_SWEEPER + TAG, "电量:${states.bmsSoc}") + UiThreadHandler.post { + tvBattery?.text = "${states.bmsSoc.roundToInt()}%" + } + } + + /** + * 车辆转向灯 + * @param directionLight + */ + override fun onAutopilotLightSwitchData(lightSwitch: LightSwitch?) { + //转向灯状态 0是正常 1是左转 2是右转 + } + + /** + * 设置自动驾驶状态 + */ + fun setAutoState(state: Int) { + when (state) { + //不可自动驾驶 + IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE -> { + sweeperAutoState?.text="自动驾驶" + sweeperAutoState?.setBackgroundResource(R.drawable.icon_not_auto) + } + //人工驾驶 + IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE -> { + sweeperAutoState?.text="人工驾驶" + sweeperAutoState?.setBackgroundResource(R.drawable.icon_auto) + } + //自动驾驶中 + IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING -> { + sweeperAutoState?.text="自动驾驶" + sweeperAutoState?.setBackgroundResource(R.drawable.icon_auto) + } + //平行驾驶 + IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING -> { + sweeperAutoState?.text="平行驾驶" + sweeperAutoState?.setBackgroundResource(R.drawable.icon_auto) + } + } + } + + /** + * 刹车灯 + * @param brakeLight + */ + override fun onAutopilotBrakeLightData(brakeLight: Boolean) { + d(TAG, "刹车灯:$brakeLight") + } + + /** + * 方向盘下方的档位 + * @param gear + */ + override fun onAutopilotGearData(gear: GearPosition) { + d(TAG, "司机屏档位$gear") + ThreadUtils.runOnUiThread { + tapPositionView?.updateWithGear(gear) + } + } + + fun getSpeedImage(): ImageView? { + return speedImage + } + + /** + * 速度设置 + */ + fun updateSpeedWithValue(newSpeed: Int) { + speedTextView?.text = newSpeed.toString() + speedImage?.setBackgroundResource(if (newSpeed > 60) R.drawable.sweeper_traffic_data_speed_warning else R.drawable.sweeper_bg_traffic_data_speed) + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperTrafficLightView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperTrafficLightView.kt new file mode 100644 index 0000000000..96a5af1933 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperTrafficLightView.kt @@ -0,0 +1,148 @@ +package com.mogo.och.sweepercloud.view + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.LinearLayout +import com.mogo.eagle.core.data.enums.DataSourceType +import com.mogo.eagle.core.data.enums.TrafficLightEnum +import com.mogo.eagle.core.function.api.datacenter.union.IMoGoTrafficLightListener +import com.mogo.eagle.core.function.call.v2x.CallerTrafficLightListenerManager +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import com.mogo.eagle.core.utilcode.util.UiThreadHandler +import com.mogo.och.sweepercloud.R +import kotlinx.android.synthetic.main.sweeper_traffic_light_view.view.* + +/** + * 清扫车:红绿灯view- + * + * Created on 2022/3/29 + */ +class SweeperTrafficLightView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr), IMoGoTrafficLightListener { + + companion object { + private const val TAG = "SweeperTrafficLightView" + } + + private var mCurrentLightId = TrafficLightEnum.BLACK + + init { + init(context) + } + + private fun init(context: Context?) { + LayoutInflater.from(context).inflate(R.layout.sweeper_traffic_light_view, this, true) + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + CallerTrafficLightListenerManager.addListener(TAG, this) + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + CallerTrafficLightListenerManager.removeListener(TAG) + } + + /** + * 展示红绿灯预警 + * + * @param checkLightId 0-都是默认,1-红,2-黄,3-绿 + * @param lightSource 1:云端下发;2:自车感知 + */ + override fun showTrafficLight(checkLightId: TrafficLightEnum, lightSource: DataSourceType) { + mCurrentLightId = checkLightId + updateTrafficLightIcon(checkLightId) + CallerLogger.d(SceneConstant.M_SWEEPER + TAG,"灯态类型:"+checkLightId.name +" 灯态来源:"+DataSourceType.getName(lightSource)) + } + + /** + * 关闭红绿灯预警展示,并重制灯态 + */ + override fun disableTrafficLight() { + UiThreadHandler.post { + mCurrentLightId = TrafficLightEnum.BLACK + sweeper_traffic_light_iv.setImageResource(R.drawable.sweeper_light_gay_nor) + sweeper_traffic_light_time_tv.text = "" + this@SweeperTrafficLightView.visibility = VISIBLE + CallerLogger.d(SceneConstant.M_SWEEPER + TAG,"灯态类型:disableTrafficLight") + } + } + + /** + * @param redNum 红灯倒计时 + * @param yellowNum 黄灯倒计时 + * @param greenNum 绿灯倒计时 + */ + override fun changeCountdownTrafficLightNum(redNum: Int, yellowNum: Int, greenNum: Int) { + when (mCurrentLightId) { + TrafficLightEnum.RED -> changeCountdownRed(redNum) + TrafficLightEnum.YELLOW -> changeCountdownYellow(yellowNum) + TrafficLightEnum.GREEN -> changeCountdownGreen(greenNum) + else -> UiThreadHandler.post { sweeper_traffic_light_time_tv.text = "" } + } + } + + override fun changeCountdownRed(redNum: Int) { + UiThreadHandler.post { + if (redNum > 0) { + sweeper_traffic_light_time_tv.text = redNum.toString() + } else { + sweeper_traffic_light_time_tv.text = "" + } + } + } + + override fun changeCountdownGreen(greenNum: Int) { + UiThreadHandler.post { + if (greenNum > 0) { + sweeper_traffic_light_time_tv.text = greenNum.toString() + } else { + sweeper_traffic_light_time_tv.text = "" + } + } + } + + override fun changeCountdownYellow(yellowNum: Int) { + UiThreadHandler.post { + if (yellowNum > 0) { + sweeper_traffic_light_time_tv.text = yellowNum.toString() + } else { + sweeper_traffic_light_time_tv.text = "" + } + } + } + + /** + * 更新红绿灯icon + * + * @param lightId 0-都是默认,1-红,2-黄,3-绿 + */ + private fun updateTrafficLightIcon(lightId: TrafficLightEnum) { + UiThreadHandler.post { + when (lightId) { + TrafficLightEnum.RED -> { + sweeper_traffic_light_iv.setImageResource(R.drawable.sweeper_light_red_nor) + this@SweeperTrafficLightView.visibility = VISIBLE + } + TrafficLightEnum.YELLOW -> { + sweeper_traffic_light_iv.setImageResource(R.drawable.sweeper_lightyellow_nor) + this@SweeperTrafficLightView.visibility = VISIBLE + } + TrafficLightEnum.GREEN -> { + sweeper_traffic_light_iv.setImageResource(R.drawable.sweeper_light_green_nor) + this@SweeperTrafficLightView.visibility = VISIBLE + } + else -> { + sweeper_traffic_light_iv.setImageResource(R.drawable.sweeper_light_gay_nor) + this@SweeperTrafficLightView.visibility = VISIBLE + } + } + } + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperWorkModeView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperWorkModeView.kt new file mode 100644 index 0000000000..08dd7f348c --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/SweeperWorkModeView.kt @@ -0,0 +1,180 @@ +package com.mogo.och.sweepercloud.view + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import androidx.constraintlayout.widget.ConstraintLayout +import chassis.ChassisStatesOuterClass.SweeperFuTianTaskSystemStates +import com.elegant.utils.UiThreadHandler +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import com.mogo.och.sweepercloud.R +import com.mogo.och.sweepercloud.callback.ICleaningModeStateCallback +import com.mogo.och.sweepercloud.constant.OperateStateEnum +import com.mogo.och.sweepercloud.ui.popwindow.SweeperOperatePanelPopWindow +import com.mogo.och.sweepercloud.util.SweeperFutianCmdUtil +import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask.TaskModel +import kotlinx.android.synthetic.main.sweeper_work_mode.view.* + +/** + * 清扫车模式信息展示 + */ +class SweeperWorkModeView : ConstraintLayout,ICleaningModeStateCallback { + + private var isSelectPureSweepMode: Boolean = false + private val TAG = "SweeperWorkModeView" + //清扫模式选择面板 + private var mOperatePanelPopWindow: SweeperOperatePanelPopWindow? = null + + private var operateState: OperateStateEnum=OperateStateEnum.SYNCING_STATUS + + constructor(context: Context) : super(context) {} + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + initView(context) + } + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {} + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {} + + private fun initView(context: Context) { + LayoutInflater.from(context).inflate(R.layout.sweeper_work_mode, this) + mOperatePanelPopWindow = SweeperOperatePanelPopWindow(context) + setShowOrHideCleanSystemState(OperateStateEnum.SYNCING_STATUS,null) + } + + /** + * 设置view + */ + fun setTrafficDataView(trafficDataView: SweeperTrafficDataView){ + //清扫模式选择面板打开关闭处理 + ivOpenOperatePanel.setOnClickListener { + if (mOperatePanelPopWindow?.isShowing != true) { + mOperatePanelPopWindow?.showAsDropDown( + trafficDataView, + resources.getDimension(R.dimen.dp_600).toInt(), + 0 + ) + UiThreadHandler.postDelayed({ + d(SceneConstant.M_SWEEPER + TAG, "operateState:"+operateState.code) + mOperatePanelPopWindow?.showSyncing(operateState) + + },300) + } else { + mOperatePanelPopWindow?.dismiss() + } + } + } + /** + * 设置清扫模式面板 + */ + fun setSweeperFutianCleanSystemState(taskType: TaskModel, cleanSystemState: SweeperFuTianTaskSystemStates?) { + // TODO:传递清扫车底盘数据给上装面板 + //mOperatePanelPopWindow?.setCleanSystemState(cleanSystemState, this@SweeperWorkModeView) + if (this.operateState.code==OperateStateEnum.STARTING_STATUS.code){ + return + } + //如果状态是同步中,在底盘首次回调时把状态强制修改成成功 + if (this.operateState.code==OperateStateEnum.SYNCING_STATUS.code){ + this.operateState=OperateStateEnum.SUCCESS_STATUS + d(SceneConstant.M_SWEEPER + TAG, "SystemState operateState:"+operateState.code) + } + //清扫车暂未选择清扫模式或者任务类型是人工驾驶子任务,则暂无清扫模式 + if (SweeperFutianCmdUtil.checkIfCleanMode(cleanSystemState) || taskType==TaskModel.MANUAL||taskType==TaskModel.DEFAULT_MODEL) { + setShowOrHideCleanSystemState(OperateStateEnum.NO_STATUS, cleanSystemState) + } else { + setShowOrHideCleanSystemState(OperateStateEnum.SUCCESS_STATUS, cleanSystemState) + } + } + + /** + * 设置清扫模式状态显示和隐藏 + */ + private fun setShowOrHideCleanSystemState(operateState: OperateStateEnum, cleanSystemState: SweeperFuTianTaskSystemStates?) { + when (operateState.code) { + OperateStateEnum.SYNCING_STATUS.code -> { + groupWorkModelPanel?.visibility = View.GONE + tvNoDataDesc?.visibility = View.VISIBLE + tvNoDataDesc?.text = "状态同步中,请稍后" + mOperatePanelPopWindow?.setIsOutsideTouchable(true) + } + OperateStateEnum.FAIL_STATUS.code -> { + groupWorkModelPanel?.visibility = View.GONE + tvNoDataDesc?.visibility = View.VISIBLE + tvNoDataDesc?.text = "上装启动失败" + mOperatePanelPopWindow?.setIsOutsideTouchable(true) + } + OperateStateEnum.STARTING_STATUS.code -> { + groupWorkModelPanel?.visibility = View.GONE + tvNoDataDesc?.visibility = View.VISIBLE + tvNoDataDesc?.text = "上装启动中..." + mOperatePanelPopWindow?.setIsOutsideTouchable(false) + } + OperateStateEnum.NO_STATUS.code -> { + groupWorkModelPanel?.visibility = View.GONE + tvNoDataDesc?.visibility = View.VISIBLE + tvNoDataDesc?.text = "暂无" + mOperatePanelPopWindow?.setIsOutsideTouchable(true) + } + else -> { + groupWorkModelPanel?.visibility = View.VISIBLE + tvNoDataDesc?.visibility = View.GONE + setCleanModeData(cleanSystemState) + mOperatePanelPopWindow?.setIsOutsideTouchable(true) + } + + } + } + + override fun cleaningModeState(operateState: OperateStateEnum, cleanSystemState: SweeperFuTianTaskSystemStates?, isSelectPureSweepMode: Boolean) { + this.isSelectPureSweepMode = isSelectPureSweepMode + this.operateState=operateState + setShowOrHideCleanSystemState(operateState, cleanSystemState) + } + + /** + * 设置清扫模式数据 + */ + private fun setCleanModeData(cleanSystemState: SweeperFuTianTaskSystemStates?) { + if (isSelectPureSweepMode) { + tvCleaningMode?.text = "纯扫模式" + groupWorkModelPanel?.visibility = View.VISIBLE + tvNoDataDesc?.visibility = View.GONE + } else { + if (SweeperFutianCmdUtil.checkIfCleanMode(cleanSystemState)) { + groupWorkModelPanel?.visibility = View.GONE + tvNoDataDesc?.visibility = View.VISIBLE + tvNoDataDesc?.text = "暂无" + return + } else { + groupWorkModelPanel?.visibility = View.VISIBLE + tvNoDataDesc?.visibility = View.GONE + // 作业模式 + if (cleanSystemState?.secuModWashSweepSts == true) tvCleaningMode?.text = "洗扫模式" + if (cleanSystemState?.secuModWashSts == true) tvCleaningMode?.text = "纯洗模式" + if (cleanSystemState?.secuWorkTonSts == true) tvCleaningMode?.text = "纯吸模式" + if (SweeperFutianCmdUtil.checkIfCleanModePureSweep(cleanSystemState)) tvCleaningMode?.text = "纯扫模式" + } + } + //清扫方向 + if (SweeperFutianCmdUtil.checkIfCleanDirection(cleanSystemState)) { + tvCleaningDirection.visibility = View.GONE + } else { + tvCleaningDirection.visibility = View.VISIBLE + // 左侧 + if (cleanSystemState?.secuWorkLeftSts == true) tvCleaningDirection?.text = "左侧" + // 右侧 + if (cleanSystemState?.secuWorkRightSts == true) tvCleaningDirection?.text = "右侧" + // 两侧 + if (cleanSystemState?.secuWorkOnBothsidesSts == true) tvCleaningDirection?.text = "两侧" + } + if (SweeperFutianCmdUtil.checkIfCleanIntensity(cleanSystemState)) { + tvCleaningIntensity.visibility = View.GONE + } else { + tvCleaningIntensity.visibility = View.VISIBLE + // 作业强度 + if (cleanSystemState?.secuWorkStandSts == true) tvCleaningIntensity?.text = "标准" + if (cleanSystemState?.secuWorkStrongSts == true) tvCleaningIntensity?.text = "强力" + } + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/TurnSignalView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/TurnSignalView.kt new file mode 100644 index 0000000000..59bbe0788d --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/TurnSignalView.kt @@ -0,0 +1,90 @@ +package com.mogo.och.sweepercloud.view + +import android.animation.AnimatorSet +import android.animation.ObjectAnimator +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.ImageView +import android.widget.LinearLayout +import chassis.Chassis +import com.mogo.och.sweepercloud.R +import kotlinx.android.synthetic.main.sweeper_turn_signal.view.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch + +class TurnSignalView : LinearLayout { + constructor(context: Context?) : super(context) {} + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + initView(context) + } + + private var init: Boolean = false + + constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) { + } + + constructor( + context: Context?, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) : super(context, attrs, defStyleAttr, defStyleRes) { + } + + private fun initView(context: Context) { + LayoutInflater.from(context).inflate(R.layout.sweeper_turn_signal, this) + init = true + } + + /** + * 转向灯动画 + */ + fun setTurnLight(directionLight: Chassis.LightSwitch?) { + GlobalScope.launch(Dispatchers.Main) { + if (!init) { + return@launch + } + //根据左右进行显示和隐藏,实际要判断每个来的时间和频度 + when (directionLight) { + Chassis.LightSwitch.LIGHT_LEFT -> { //左转向 + leftSelectImage.visibility = View.VISIBLE + rightSelectImage.visibility = View.GONE + rightSelectImage.clearAnimation() + setAnimation(leftSelectImage) + } + Chassis.LightSwitch.LIGHT_RIGHT -> { //右转向 + leftSelectImage.visibility = View.GONE + rightSelectImage.visibility = View.VISIBLE + leftSelectImage.clearAnimation() + setAnimation(rightSelectImage) + } + else -> { //消失 + leftSelectImage.clearAnimation() + rightSelectImage.clearAnimation() + leftSelectImage.visibility = View.GONE + rightSelectImage.visibility = View.GONE + } + } + } + } + + //实现图片闪烁效果 + private fun setAnimation(imageView: ImageView) { + val animationSet = AnimatorSet() + val valueAnimator = ObjectAnimator.ofFloat(imageView, "alpha", 0f, 1.0f) + val valueAnimatorDisappare = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0f) + valueAnimator.duration = 1000 + valueAnimatorDisappare.duration = 800 + valueAnimator.repeatCount = -1 + valueAnimatorDisappare.repeatCount = -1 + animationSet.playTogether(valueAnimatorDisappare, valueAnimator) + animationSet.start() + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/VerticalDashLineView.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/VerticalDashLineView.java new file mode 100644 index 0000000000..bc6aae4605 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/VerticalDashLineView.java @@ -0,0 +1,64 @@ +package com.mogo.och.sweepercloud.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/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/WeltMapOverView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/WeltMapOverView.kt new file mode 100644 index 0000000000..5f157e0d67 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/WeltMapOverView.kt @@ -0,0 +1,342 @@ +package com.mogo.och.sweepercloud.view + +import android.content.Context +import android.graphics.Color +import android.os.Bundle +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.ImageView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat +import com.amap.api.maps.AMap +import com.amap.api.maps.CameraUpdateFactory +import com.amap.api.maps.model.* +import com.mogo.eagle.core.data.map.MogoLocation +import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener +import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager +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.CoordinateUtils +import com.mogo.eagle.core.utilcode.util.ThreadUtils +import com.mogo.och.sweepercloud.R +import com.mogo.och.sweepercloud.bean.SweeperRoutePlanningUpdateReqBean +import com.mogo.och.sweepercloud.constant.SweeperConst +import com.mogo.och.sweepercloud.database.bean.WeltDataBean +import com.mogo.och.sweepercloud.util.SweeperMapAssetStyleUtil +import kotlinx.android.synthetic.main.sweeper_welt_map_overview.view.* + + +/** + * 作业任务全览图 + */ +class WeltMapOverView : ConstraintLayout, IMoGoChassisLocationGCJ02Listener { + private var mTaskCoordinatesLatLng: MutableList = mutableListOf() //当前大任务的所有起终点集合 + private var mCarMarker: Marker? = null + private var mAMap: AMap? = null + private var mWeltPolylines: Polyline? = null + private var mRoutePolylines: Polyline?=null +// private val mLineMarkers: MutableList = mutableListOf() + private var mEndStationMarker: Marker? = null + private var mFirst: Boolean = false + + //清扫车任务地图 + private val TAG = "WeltMapOverView" + + constructor(context: Context) : super(context) {} + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + initView(context) + } + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {} + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {} + + private fun initView(context: Context) { + LayoutInflater.from(context).inflate(R.layout.sweeper_welt_map_overview, this) + initAMapView() + // 注册定位监听 + CallerChassisLocationGCJ02ListenerManager.addListener(TAG, this) + CallerChassisLocationGCJ02ListenerManager.setListenerHz(TAG,5) + } + + private fun initAMapView() { + mAMap = sweeperTextureMapView.map + // 地图文字标注 + mAMap?.showMapText(true) + //显示3D建筑物 + mAMap?.showBuildings(true) + // 设置导航地图模式,aMap是地图控制器对象。 + mAMap?.mapType = AMap.MAP_TYPE_NIGHT + // 关闭显示实时路况图层,aMap是地图控制器对象。 + mAMap?.isTrafficEnabled = false + // 设置 锚点 图标 + mCarMarker = mAMap?.addMarker( + MarkerOptions() + .icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_car_big)) + .anchor(0.5f, 0.5f) + ) + // 设置地图的样式 + val uiSettings = mAMap?.uiSettings + uiSettings?.isZoomControlsEnabled = false // 地图缩放级别的交换按钮 + uiSettings?.setAllGesturesEnabled(false) // 所有手势 + uiSettings?.isMyLocationButtonEnabled = false // 显示默认的定位按钮 + uiSettings?.setLogoBottomMargin(-150) //设置Logo下边界距离屏幕底部的边距,设置为负值即可 + // 加载自定义样式 + val customMapStyleOptions = CustomMapStyleOptions() + .setEnable(true) + .setStyleData(SweeperMapAssetStyleUtil.getAssetsStyle(context, "map_style.data")) + .setStyleExtraData(SweeperMapAssetStyleUtil.getAssetsExtraStyle(context, "map_style_extra.data")) + // 设置自定义样式 + mAMap?.setCustomMapStyle(customMapStyleOptions) + //mAMap?.moveCamera(CameraUpdateFactory.zoomTo(15f)) + mAMap?.setOnMapLoadedListener(AMap.OnMapLoadedListener { + //mAMap?.moveCamera(CameraUpdateFactory.zoomTo(15f)) + CallerLogger.d(SceneConstant.M_SWEEPER + TAG, "WeltView---onMapLoaded") + // 加载自定义样式 + val customMapStyleOptions = CustomMapStyleOptions() + .setEnable(true) + .setStyleData(SweeperMapAssetStyleUtil.getAssetsStyle(context, "map_style.data")) + .setStyleExtraData(SweeperMapAssetStyleUtil.getAssetsExtraStyle(context, "map_style_extra.data")) + // 设置自定义样式 + mAMap?.setCustomMapStyle(customMapStyleOptions) + // 实时路况图层关闭,必须添加在loaded结束之后,其他位置不生效 + mAMap?.isTrafficEnabled = false + mAMap?.showBuildings(true) + }) + } + + /** + * 添加画线颜色值 + */ + private fun getRouteColorList(weltData: MutableList):MutableList { + val colorList= mutableListOf() + var nextWeltDataBean:WeltDataBean?=null + for (i in weltData.indices) { + val weltDataBean = weltData[i] + if(i+110){ + colorList.add(Color.TRANSPARENT) + continue + } + } + if (weltDataBean.weltDistance == SweeperConst.NONWELT) {//非贴边 + colorList.add(ContextCompat.getColor(context,R.color.sweeper_236299)) + } else if (weltDataBean.weltDistance < 0) { + colorList.add(ContextCompat.getColor(context,R.color.sweeper_c22101)) + } else if (weltDataBean.weltDistance >= 0 && weltDataBean.weltDistance < 0.1) { + colorList.add(ContextCompat.getColor(context,R.color.sweeper_4dffa4)) + } else if (weltDataBean.weltDistance >= 0.1 && weltDataBean.weltDistance < 0.2) { + colorList.add(ContextCompat.getColor(context,R.color.sweeper_ffdd4d)) + } else if (weltDataBean.weltDistance >= 0.2) { + colorList.add(ContextCompat.getColor(context,R.color.sweeper_ff912b)) + } + } + return colorList + } + + override fun onChassisLocationGCJ02(mogoLocation: MogoLocation?) { + ThreadUtils.getSinglePool().run { + mogoLocation?.let { gnssInfo -> + val currentLatLng = LatLng(gnssInfo.latitude, gnssInfo.longitude) + //更新车辆位置 + mCarMarker?.rotateAngle = (360 - gnssInfo.heading).toFloat() + mCarMarker?.position = currentLatLng + mCarMarker?.setToTop() + //圈定地图显示范围 + val boundsBuilder = LatLngBounds.Builder() + if (mTaskCoordinatesLatLng.size > 0) { + //存放经纬度 + for (i in mTaskCoordinatesLatLng.indices) { + val latLng = mTaskCoordinatesLatLng[i] + boundsBuilder.include(latLng) + } + } + mRoutePolylines?.points?.forEach {latLng-> + boundsBuilder.include(latLng) + } + boundsBuilder.include(currentLatLng) + mAMap?.moveCamera(CameraUpdateFactory.newLatLngBoundsRect(boundsBuilder.build(), 100, 100, 100, 100)) + + } + } + } + + /** + * 根据贴边数据绘制任务路线 + */ + fun drawablePolyline(weltDatas: MutableList?) { + weltDatas?.let { + val colorList=getRouteColorList(it) + val coordinatesLatLngs= mutableListOf() + for (i in it.indices) { + coordinatesLatLngs.add(LatLng(it[i].locLat,it[i].locLon)) + } + if (coordinatesLatLngs.size > 2) { + //设置线段纹理 + mWeltPolylines?.remove() + val polylineOptions = PolylineOptions() + polylineOptions.addAll(coordinatesLatLngs) + polylineOptions.width(14f) //线段宽度 + polylineOptions.isUseTexture = false + polylineOptions.lineCapType(PolylineOptions.LineCapType.LineCapSquare) + polylineOptions.colorValues(colorList) + polylineOptions.visible(true) + // 绘制线 + mWeltPolylines = mAMap?.addPolyline(polylineOptions) + } + } + } + + /** + * 绘制起点和终点的marker + */ + private fun drawStartAndEndMarker(startPoint: LatLng, endPoint: LatLng) { +// val startMarker = mAMap?.addMarker(MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_big_start_maker_icon))) +// startMarker?.position = startPoint +// mLineMarkers.add(startMarker) +// val endMarker = mAMap?.addMarker(MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_big_end_maker_icon))) +// endMarker?.position = endPoint +// mLineMarkers.add(endMarker) + } + + private fun drawEndMarker(endPoint: LatLng){ + mEndStationMarker?.remove() + mEndStationMarker = mAMap?.addMarker(MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_big_end_maker_icon))) + mEndStationMarker?.position = endPoint + } + + /** + * 清除所有标记和路线 + */ + fun clearAllMarkerAndPolyline() { +// for (i in mLineMarkers.indices) { +// mLineMarkers[i]?.isVisible = false +// mLineMarkers[i]?.remove() +// } + mEndStationMarker?.remove() + mWeltPolylines?.remove() + mRoutePolylines?.remove() +// mLineMarkers.clear() + //mFirst = false + //showOrHiddenLegendData(false) + } + + /** + * 设置贴边数据 + */ + fun setWeltData(weltDatas: MutableList?, isWeltData: Boolean, distance: String?) { + drawablePolyline(weltDatas) + ThreadUtils.runOnUiThread { + distance?.let { + setDistance(it) + } + } + //if (!mFirst && isWeltData) { + // mFirst = true + // showOrHiddenLegendData(true) + //} + } + + /** + * 任务轨迹数据 + */ + fun setRouteList(routeList: ArrayList) { + val routeCoordinatesLatLngs= mutableListOf() + for (i in routeList.indices) { + routeCoordinatesLatLngs.add(LatLng(routeList[i].latitude,routeList[i].longitude)) + } + ThreadUtils.runOnUiThread { + drawRouteListPolyline(routeCoordinatesLatLngs) + } + } + + private fun drawRouteListPolyline(routeList: MutableList) { + mRoutePolylines?.remove() + val polylineOptions = PolylineOptions() + polylineOptions.width(14f) //线段宽度 + polylineOptions.isUseTexture = false + polylineOptions.lineCapType(PolylineOptions.LineCapType.LineCapSquare) + polylineOptions.color(ContextCompat.getColor(context,R.color.sweeper_3ba1cc)) + polylineOptions.addAll(routeList) + polylineOptions.visible(true) + mRoutePolylines=mAMap?.addPolyline(polylineOptions) + } + + /** + * 设置当前大任务的所有子任务起终点集合 + */ + fun setTaskListCoordinatesLatLng(coordinatesLatLng: MutableList) { + ThreadUtils.runOnUiThread { + this.mTaskCoordinatesLatLng = coordinatesLatLng + if (mTaskCoordinatesLatLng.size > 0) { + drawStartAndEndMarker(mTaskCoordinatesLatLng[0], mTaskCoordinatesLatLng[mTaskCoordinatesLatLng.size - 1]) + } + } + } + /** + * 设置当前任务终点 + */ + fun setCurrentTaskCoordinatesLatLng(coordinatesLatLng: LatLng) { + ThreadUtils.runOnUiThread { + drawEndMarker(coordinatesLatLng) + } + } + + /** + * 设置图例数据 + */ + private fun showOrHiddenLegendData(isShow: Boolean) { + groupLegend.visibility = if (isShow) View.VISIBLE else View.GONE + sweeperLegend1.setData(R.drawable.sweeper_legend1, "a<0") + sweeperLegend2.setData(R.drawable.sweeper_legend2, "0≤a<10") + sweeperLegend3.setData(R.drawable.sweeper_legend3, "10≤a<20") + sweeperLegend4.setData(R.drawable.sweeper_legend4, "a≥20") + sweeperLegend5.setData(R.drawable.sweeper_legend5, "非贴边") + sweeperLegend6.setData(R.drawable.sweeper_legend6, "未经过") + } + + private fun setDistance(distance: String) { + taskWeltDistanceTv.text="贴边:${distance}" + } + + fun setProgress(progress: String?) { + progress?.let { + if ("0" == progress) { + taskProgressTv.visibility = View.GONE + taskWeltDistanceTv.visibility = View.GONE + showOrHiddenLegendData(false) + } else { + taskProgressTv.visibility = View.VISIBLE + taskWeltDistanceTv.visibility = View.VISIBLE + taskProgressTv.text = it + showOrHiddenLegendData(true) + } + } + } + fun onCreateView(savedInstanceState: Bundle?) { + sweeperTextureMapView.onCreate(savedInstanceState) + } + + fun onResume() { + sweeperTextureMapView.onResume() + } + + fun onPause() { + sweeperTextureMapView.onPause() + } + + fun onDestroy() { + sweeperTextureMapView.onDestroy() + } + + fun getSweeperSwitchToSmall(): ImageView { + return sweeperSwitchToSmall + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/WeltSmallMapView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/WeltSmallMapView.kt new file mode 100644 index 0000000000..4db516bb7a --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweepercloud/view/WeltSmallMapView.kt @@ -0,0 +1,304 @@ +package com.mogo.och.sweepercloud.view + +import android.content.Context +import android.graphics.Color +import android.os.Bundle +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.ImageView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat +import com.amap.api.maps.AMap +import com.amap.api.maps.CameraUpdateFactory +import com.amap.api.maps.model.* +import com.mogo.eagle.core.data.map.MogoLocation +import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener +import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import com.mogo.eagle.core.utilcode.util.CoordinateUtils +import com.mogo.eagle.core.utilcode.util.ThreadUtils +import com.mogo.och.sweepercloud.R +import com.mogo.och.sweepercloud.bean.SweeperRoutePlanningUpdateReqBean +import com.mogo.och.sweepercloud.constant.SweeperConst +import com.mogo.och.sweepercloud.database.bean.WeltDataBean +import com.mogo.och.sweepercloud.util.SweeperMapAssetStyleUtil +import kotlinx.android.synthetic.main.sweeper_welt_small_map_view.view.* + + +/** + * 作业任务小地图 + */ +class WeltSmallMapView : ConstraintLayout, IMoGoChassisLocationGCJ02Listener { + private var mTaskCoordinatesLatLng: MutableList = mutableListOf() //当前大任务的所有起终点集合 + private var mCarMarker: Marker? = null + private var mAMap: AMap? = null + private var mWeltPolylines: Polyline? = null + private var mRoutePolylines: Polyline?=null +// private val mLineMarkers: MutableList = mutableListOf() + private var endStationMarker:Marker? = null + + //清扫车任务地图 + private val TAG = "WeltMapView" + + constructor(context: Context) : super(context) {} + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + initView(context) + } + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {} + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {} + + private fun initView(context: Context) { + LayoutInflater.from(context).inflate(R.layout.sweeper_welt_small_map_view, this) + initAMapView() + // 注册定位监听 + CallerChassisLocationGCJ02ListenerManager.addListener(TAG, this) + CallerChassisLocationGCJ02ListenerManager.setListenerHz(TAG,5) + } + + override fun onChassisLocationGCJ02(mogoLocation: MogoLocation?) { + d(SceneConstant.M_SWEEPER + TAG, "mogoLocation:$mogoLocation") + ThreadUtils.getSinglePool().run { + mogoLocation?.let { + val currentLatLng = LatLng(it.latitude, it.longitude) + drawCarMarker(mogoLocation) + //圈定地图显示范围 + val boundsBuilder = LatLngBounds.Builder() + if (mTaskCoordinatesLatLng.size > 0) { + //存放经纬度 + for (i in mTaskCoordinatesLatLng.indices) { + boundsBuilder.include(mTaskCoordinatesLatLng[i]) + } + } + mRoutePolylines?.points?.forEach {latLng-> + boundsBuilder.include(latLng) + } + boundsBuilder.include(currentLatLng) + mAMap!!.moveCamera(CameraUpdateFactory.newLatLngBoundsRect(boundsBuilder.build(), 100, 100, 100, 100)) + } + } + } + + /** + * 绘制自车 + * + * @param location + */ + private fun drawCarMarker(location: MogoLocation?) { + if (location == null) return + val currentLatLng = LatLng(location.latitude, location.longitude) + //更新车辆位置 + if (mCarMarker != null) { + mCarMarker!!.rotateAngle = (360 - location.heading).toFloat() + mCarMarker!!.position = currentLatLng + mCarMarker!!.setToTop() + } + } + + private fun initAMapView() { + mAMap = sweeperSmallTextureMapView?.map + // 地图文字标注 + mAMap?.showMapText(true) + // 设置导航地图模式,aMap是地图控制器对象。 + mAMap?.mapType = AMap.MAP_TYPE_NIGHT + // 关闭显示实时路况图层,aMap是地图控制器对象。 + mAMap?.isTrafficEnabled = false + // 设置 锚点 图标 + mCarMarker = mAMap?.addMarker( + MarkerOptions() + .icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_car_small)) + .anchor(0.5f, 0.5f) + ) + // 设置地图的样式 + val uiSettings = mAMap?.uiSettings + uiSettings?.isZoomControlsEnabled = false // 地图缩放级别的交换按钮 + uiSettings?.setAllGesturesEnabled(false) // 所有手势 + uiSettings?.isMyLocationButtonEnabled = false // 显示默认的定位按钮 + uiSettings?.setLogoBottomMargin(-150) //设置Logo下边界距离屏幕底部的边距,设置为负值即可 + // 加载自定义样式 + val customMapStyleOptions = CustomMapStyleOptions() + .setEnable(true) + .setStyleData(SweeperMapAssetStyleUtil.getAssetsStyle(context, "map_style.data")) + .setStyleExtraData(SweeperMapAssetStyleUtil.getAssetsExtraStyle(context, "map_style_extra.data")) + // 设置自定义样式 + mAMap?.setCustomMapStyle(customMapStyleOptions) + mAMap?.setOnMapLoadedListener(AMap.OnMapLoadedListener { + d(SceneConstant.M_SWEEPER + TAG, "WeltView---onMapLoaded") + // 加载自定义样式 + val customMapStyleOptions = CustomMapStyleOptions() + .setEnable(true) + .setStyleData(SweeperMapAssetStyleUtil.getAssetsStyle(context, "map_style.data")) + .setStyleExtraData(SweeperMapAssetStyleUtil.getAssetsExtraStyle(context, "map_style_extra.data")) + // 设置自定义样式 + mAMap?.setCustomMapStyle(customMapStyleOptions) + mAMap?.setPointToCenter(sweeperSmallTextureMapView.width / 2, sweeperSmallTextureMapView.height / 2) + }) + } + + /** + * 根据贴边数据绘制任务路线 + */ + private fun drawablePolyline(weltDatas: MutableList?) { + weltDatas?.let { + val colorList = getRouteColorList(it) + val coordinatesLatLngs = mutableListOf() + for (i in it.indices) { + coordinatesLatLngs.add(LatLng(it[i].locLat,it[i].locLon)) + } + if (coordinatesLatLngs.size > 2) { + //设置线段纹理 + mWeltPolylines?.remove() + val polylineOptions = PolylineOptions() + polylineOptions.addAll(coordinatesLatLngs) + polylineOptions.width(14f) //线段宽度 + polylineOptions.isUseTexture = false + polylineOptions.lineCapType(PolylineOptions.LineCapType.LineCapSquare) + polylineOptions.colorValues(colorList) + polylineOptions.visible(true) + // 绘制线 + mWeltPolylines = mAMap?.addPolyline(polylineOptions) + } + } + } + + /** + * 添加画线颜色值 + */ + private fun getRouteColorList(weltData: MutableList): MutableList { + val colorList = mutableListOf() + var nextWeltDataBean:WeltDataBean?=null + for (i in weltData.indices) { + val weltDataBean = weltData[i] + if(i+110){ + colorList.add(Color.TRANSPARENT) + continue + } + } + + if (weltDataBean.weltDistance == SweeperConst.NONWELT) {//非贴边 + colorList.add(ContextCompat.getColor(context,R.color.sweeper_236299)) + } else if (weltDataBean.weltDistance < 0) { + colorList.add(ContextCompat.getColor(context,R.color.sweeper_c22101)) + } else if (weltDataBean.weltDistance >= 0 && weltDataBean.weltDistance < 0.1) { + colorList.add(ContextCompat.getColor(context,R.color.sweeper_4dffa4)) + } else if (weltDataBean.weltDistance >= 0.1 && weltDataBean.weltDistance < 0.2) { + colorList.add(ContextCompat.getColor(context,R.color.sweeper_ffdd4d)) + } else if (weltDataBean.weltDistance >= 0.2) { + colorList.add(ContextCompat.getColor(context,R.color.sweeper_ff912b)) + } + } + return colorList + } + + /** + * 设置当前大任务的所有子任务起终点集合 + */ + fun setTaskListCoordinatesLatLng(coordinatesLatLng: MutableList) { + ThreadUtils.runOnUiThread { + this.mTaskCoordinatesLatLng = coordinatesLatLng + } + } + + /** + * 设置当前任务的终点 + */ + fun setCurrentTaskCoordinatesLatLng(coordinatesLatLng: LatLng) { + ThreadUtils.runOnUiThread { + endStationMarker?.remove() + endStationMarker = mAMap?.addMarker(MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_small_end_marker_icon))) + endStationMarker?.position = coordinatesLatLng + } + } + + /** + * 清除所有标记和路线 + */ + fun clearAllMarkerAndPolyline() { + endStationMarker?.remove() + mWeltPolylines?.remove() + mRoutePolylines?.remove() + } + + fun getSwitchToBig(): ImageView = sweeperSwitchToBig + /** + * 设置贴边数据 + */ + fun setWeltData(weltDatas: MutableList, isWeltData: Boolean, distance: String) { + drawablePolyline(weltDatas) + ThreadUtils.runOnUiThread { + setWeltDistance(distance) + } + } + + /** + * 设置贴边距离 + */ + private fun setWeltDistance(distance: String) { + taskWeltDistanceTv.text = "贴边:${distance}" + } + + /** + * 设置任务轨迹数据 + */ + fun setRouteList(routeList: ArrayList) { + val routeCoordinatesLatLngs = mutableListOf() + for (i in routeList.indices) { + routeCoordinatesLatLngs.add(LatLng(routeList[i].latitude, routeList[i].longitude)) + } + ThreadUtils.runOnUiThread { + drawRouteListPolyline(routeCoordinatesLatLngs) + } + } + + private fun drawRouteListPolyline(routeList: MutableList) { + mRoutePolylines?.remove() + val polylineOptions = PolylineOptions() + polylineOptions.addAll(routeList) + polylineOptions.width(14f) //线段宽度 + polylineOptions.isUseTexture = false + polylineOptions.lineCapType(PolylineOptions.LineCapType.LineCapSquare) + polylineOptions.color(ContextCompat.getColor(context,R.color.sweeper_3ba1cc)) + polylineOptions.visible(true) + mRoutePolylines=mAMap?.addPolyline(polylineOptions) + } + + /** + * 设置任务进度 + */ + fun setTaskProgress(progress: String?) { + if (progress == "0") { + taskWeltDistanceTv.visibility = View.GONE + taskProgressTv.visibility = View.GONE + } else { + taskWeltDistanceTv.visibility = View.VISIBLE + taskProgressTv.visibility = View.VISIBLE + taskProgressTv.text = progress + } + + } + + fun onCreateView(savedInstanceState: Bundle?) { + sweeperSmallTextureMapView?.onCreate(savedInstanceState) + } + + fun onResume() { + sweeperSmallTextureMapView?.onResume() + } + + fun onPause() { + sweeperSmallTextureMapView?.onPause() + } + + fun onDestroy() { + sweeperSmallTextureMapView?.onDestroy() + } +} \ No newline at end of file diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/bg_shape_work_mode.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/bg_shape_work_mode.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/bg_shape_work_mode.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/bg_shape_work_mode.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/bg_sweeper_operate_panel.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/bg_sweeper_operate_panel.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/bg_sweeper_operate_panel.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/bg_sweeper_operate_panel.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_ai_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_ai_normal.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_ai_normal.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_ai_normal.png diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_auto.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_auto.png new file mode 100755 index 0000000000..b76ce3dd2b Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_auto.png differ diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_battery.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_battery.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_battery.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_battery.png diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_manual_driving.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_manual_driving.png new file mode 100755 index 0000000000..8e1fa65d96 Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_manual_driving.png differ diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_message_box.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_message_box.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_message_box.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_message_box.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_message_box_pressed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_message_box_pressed.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_message_box_pressed.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_message_box_pressed.png diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_not_auto.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_not_auto.png new file mode 100755 index 0000000000..3cb8679a55 Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_not_auto.png differ diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_right_down_arrow.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_right_down_arrow.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_right_down_arrow.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_right_down_arrow.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_water_level_warning.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_level_warning.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_water_level_warning.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_level_warning.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_water_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_nor.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_water_nor.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_nor.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_water_select.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_select.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_water_select.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_select.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/no_task_data.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/no_task_data.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/no_task_data.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/no_task_data.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_slide_block.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_base_slide_block.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_slide_block.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_base_slide_block.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data_speed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data_speed.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data_speed.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data_speed.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_big_end_maker_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_big_end_maker_icon.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_big_end_maker_icon.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_big_end_maker_icon.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_big_start_maker_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_big_start_maker_icon.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_big_start_maker_icon.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_big_start_maker_icon.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_car_big.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_car_big.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_car_big.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_car_big.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_car_small.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_car_small.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_car_small.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_car_small.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_card_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_card_normal.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_card_normal.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_card_normal.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_card_pressed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_card_pressed.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_card_pressed.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_card_pressed.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_clean_mode_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_clean_mode_icon.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_clean_mode_icon.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_clean_mode_icon.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_close_navi_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_close_navi_icon.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_close_navi_icon.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_close_navi_icon.png diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_cloud_loading.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_cloud_loading.png new file mode 100644 index 0000000000..0c2d84f448 Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_cloud_loading.png differ diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_cloud_rotate.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_cloud_rotate.png new file mode 100755 index 0000000000..3e49a07b00 Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_cloud_rotate.png differ diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_cloud_rotation.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_cloud_rotation.png new file mode 100644 index 0000000000..9f33e0d8dd Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_cloud_rotation.png differ diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_cloud_rotation_background.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_cloud_rotation_background.png new file mode 100755 index 0000000000..8d3650e9ba Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_cloud_rotation_background.png differ diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_collect_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_collect_normal.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_collect_normal.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_collect_normal.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_collect_pressed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_collect_pressed.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_collect_pressed.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_collect_pressed.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_full_screen_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_full_screen_icon.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_full_screen_icon.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_full_screen_icon.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_ai_select.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_ai_select.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_ai_select.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_ai_select.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_normal.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_normal.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_normal.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_select.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_select.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_select.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_select.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_close.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_close.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_close.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_close.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_open.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_open.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_open.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_open.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_not_select_subtask.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_not_select_subtask.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_not_select_subtask.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_not_select_subtask.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_select_subtask.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_select_subtask.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_select_subtask.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_select_subtask.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_light_gay_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_gay_nor.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_light_gay_nor.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_gay_nor.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_light_green_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_green_nor.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_light_green_nor.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_green_nor.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_light_red_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_red_nor.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_light_red_nor.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_red_nor.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_lightyellow_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_lightyellow_nor.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_lightyellow_nor.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_lightyellow_nor.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_line.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_line.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_line.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_line.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_loading_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_loading_nor.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_loading_nor.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_loading_nor.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_navi_refresh.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_navi_refresh.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_navi_refresh.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_navi_refresh.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_och_dot_line.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_och_dot_line.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_och_dot_line.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_och_dot_line.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_setting_btn_bg.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_btn_bg.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_setting_btn_bg.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_btn_bg.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_setting_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_normal.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_setting_normal.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_normal.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_setting_pressed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_pressed.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_setting_pressed.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_pressed.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_small_end_marker_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_small_end_marker_icon.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_small_end_marker_icon.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_small_end_marker_icon.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_small_start_marker_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_small_start_marker_icon.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_small_start_marker_icon.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_small_start_marker_icon.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_big_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_big_normal.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_big_normal.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_big_normal.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_big_pressed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_big_pressed.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_big_pressed.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_big_pressed.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_long.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_long.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_long.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_long.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_medium.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_medium.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_medium.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_medium.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_small_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_small_normal.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_small_normal.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_small_normal.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_small_pressed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_small_pressed.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_small_pressed.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_small_pressed.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_task_list_left_select_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_list_left_select_icon.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_task_list_left_select_icon.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_list_left_select_icon.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_task_not_working.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_not_working.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_task_not_working.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_not_working.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_task_working.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_working.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_task_working.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_working.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_traffic_data_speed_warning.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_traffic_data_speed_warning.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_traffic_data_speed_warning.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_traffic_data_speed_warning.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_unselect_btn.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_unselect_btn.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_unselect_btn.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_unselect_btn.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/turn_signal_left_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_left_nor.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/turn_signal_left_nor.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_left_nor.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/turn_signal_left_select.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_left_select.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/turn_signal_left_select.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_left_select.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/turn_signal_right_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_right_nor.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/turn_signal_right_nor.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_right_nor.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/turn_signal_right_select.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_right_select.png similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/turn_signal_right_select.png rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_right_select.png diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_bubble.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_bubble.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_bubble.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_bubble.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_clean_mode.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_clean_mode.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_clean_mode.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_clean_mode.xml diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_dialog_cloud_view.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_dialog_cloud_view.xml new file mode 100644 index 0000000000..a0f105b0ac --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_dialog_cloud_view.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_dialog_no_title.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_dialog_no_title.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_dialog_no_title.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_dialog_no_title.xml diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_left_bottom_round.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_left_bottom_round.xml new file mode 100644 index 0000000000..5d247295b3 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_left_bottom_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_left_right_bottom_round.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_left_right_bottom_round.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_left_right_bottom_round.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_left_right_bottom_round.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_right_bottom_round.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_right_bottom_round.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_right_bottom_round.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_right_bottom_round.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_task_panel.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_panel.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_task_panel.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_panel.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_task_state_not_ready.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_state_not_ready.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_task_state_not_ready.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_state_not_ready.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_task_state_working.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_state_working.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_task_state_working.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_state_working.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_welt_panel.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_welt_panel.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_shape_welt_panel.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_welt_panel.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_close.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_close.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_close.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_close.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_default.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_default.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_default.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_default.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_disabled.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_disabled.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_disabled.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_disabled.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_open.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_open.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_open.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_open.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_pressed.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_pressed.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_pressed.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_pressed.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_task_menu.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_task_menu.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/bg_task_menu.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_task_menu.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/icon_more.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/icon_more.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/icon_more.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/icon_more.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_ai_collect_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_ai_collect_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_ai_collect_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_ai_collect_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_bad_case_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_bad_case_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_bad_case_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_bad_case_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_bg_waring_limiting_velocity.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_bg_waring_limiting_velocity.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_bg_waring_limiting_velocity.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_bg_waring_limiting_velocity.xml diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_cloud_rotation_layer.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_cloud_rotation_layer.xml new file mode 100644 index 0000000000..b4793b37ad --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_cloud_rotation_layer.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_collect_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_collect_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_collect_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_collect_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_legend1.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend1.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_legend1.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend1.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_legend2.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend2.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_legend2.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend2.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_legend3.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend3.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_legend3.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend3.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_legend4.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend4.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_legend4.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend4.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_legend5.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend5.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_legend5.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend5.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_legend6.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend6.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_legend6.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend6.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_list_left_top_line.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_list_left_top_line.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_list_left_top_line.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_list_left_top_line.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_message_box.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_message_box.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_message_box.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_message_box.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operate_panel_btn1_bg_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operate_panel_btn1_bg_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operate_panel_btn1_bg_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operate_panel_btn1_bg_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operate_panel_btn2_bg_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operate_panel_btn2_bg_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operate_panel_btn2_bg_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operate_panel_btn2_bg_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_bg.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_bg.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_bg.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_bg.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_bg_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_bg_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_bg_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_bg_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_select_bg.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_select_bg.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_select_bg.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_select_bg.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_oprate_panel_cancel_btn.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_oprate_panel_cancel_btn.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_oprate_panel_cancel_btn.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_oprate_panel_cancel_btn.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_oprate_panel_reset_btn.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_oprate_panel_reset_btn.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_oprate_panel_reset_btn.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_oprate_panel_reset_btn.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_panel_anchor_bkg.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_panel_anchor_bkg.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_panel_anchor_bkg.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_panel_anchor_bkg.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_panel_bkg.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_panel_bkg.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_panel_bkg.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_panel_bkg.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_refresh.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_refresh.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_refresh.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_refresh.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_selector_msg_box.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_selector_msg_box.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_selector_msg_box.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_selector_msg_box.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_setting_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_setting_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_setting_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_setting_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_station_green_dash_line.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_station_green_dash_line.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_station_green_dash_line.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_station_green_dash_line.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_station_v_green_dash.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_station_v_green_dash.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_station_v_green_dash.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_station_v_green_dash.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_card_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_card_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_card_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_card_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_map_bg.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_bg.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_map_bg.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_bg.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_map_big_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_big_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_map_big_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_big_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_map_small_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_small_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_map_small_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_small_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_task_dividing_line1_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_dividing_line1_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_task_dividing_line1_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_dividing_line1_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_task_dividing_line2_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_dividing_line2_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_task_dividing_line2_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_dividing_line2_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_task_list_selected.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_upload_autopoiltstate.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_task_list_selected.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_upload_autopoiltstate.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_water_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_water_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_water_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_water_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/turn_signal_left_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/turn_signal_left_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/turn_signal_left_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/turn_signal_left_selector.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/turn_signal_right_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/turn_signal_right_selector.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/drawable/turn_signal_right_selector.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/drawable/turn_signal_right_selector.xml diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_cloud_loading.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_cloud_loading.xml new file mode 100644 index 0000000000..c2154df812 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_cloud_loading.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_cloud_view.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_cloud_view.xml new file mode 100644 index 0000000000..a0b0c6a17b --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_cloud_view.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-sweeper/src/main/res/layout/dialog_sweeper_manual_driving.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_manual_driving.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/layout/dialog_sweeper_manual_driving.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_manual_driving.xml diff --git a/OCH/mogo-och-sweeper/src/main/res/layout/dialog_sweeper_no_title.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_no_title.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/layout/dialog_sweeper_no_title.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_no_title.xml diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/fragment_och_sweeper.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/fragment_och_sweeper.xml new file mode 100644 index 0000000000..0c276dceb1 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/fragment_och_sweeper.xml @@ -0,0 +1,36 @@ + + + + + + + + + + \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/fragment_welt_map_overview.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/fragment_welt_map_overview.xml new file mode 100644 index 0000000000..b59e5e23eb --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/fragment_welt_map_overview.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_amap_navi_view.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_amap_navi_view.xml similarity index 100% rename from OCH/mogo-och-sweeper/src/main/res/layout/sweeper_amap_navi_view.xml rename to OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_amap_navi_view.xml diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_base_fragment.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_base_fragment.xml new file mode 100644 index 0000000000..f600703e61 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_base_fragment.xml @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +