Merge branch 'release_sweeper-d_230423_3.1.0.2' into 'master'
[Publish] Sweeper-Cloud 司机端 V3.1.0 对接云控需求 See merge request SCA/L4HA/AndroidApp/MoGoEagleEye!781
@@ -45,10 +45,6 @@ public class MogoOCHBusPassenger implements IMogoOCH {
|
|||||||
this.mActivity = activity;
|
this.mActivity = activity;
|
||||||
this.mContainerId = containerId;
|
this.mContainerId = containerId;
|
||||||
showFragment();
|
showFragment();
|
||||||
|
|
||||||
if (AppIdentityModeUtils.isJL(FunctionBuildConfig.appIdentityMode)) {
|
|
||||||
MultiDisplayUtils.INSTANCE.startActWithSecond(activity, VideoPlayerActivity.class);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ class OchCommonConst {
|
|||||||
fun getShuttleUrl(): String {
|
fun getShuttleUrl(): String {
|
||||||
return FunctionBuildConfig.urlJson.shuttleUrl
|
return FunctionBuildConfig.urlJson.shuttleUrl
|
||||||
}
|
}
|
||||||
|
@JvmStatic
|
||||||
|
fun getSweeperUrl(): String {
|
||||||
|
return FunctionBuildConfig.urlJson.sweeperUrl
|
||||||
|
}
|
||||||
// token 失效 重新获取token
|
// token 失效 重新获取token
|
||||||
const val WAIT_TAKEN = 100046
|
const val WAIT_TAKEN = 100046
|
||||||
|
|
||||||
|
|||||||
@@ -52,11 +52,6 @@ android {
|
|||||||
dimension "vehicle"
|
dimension "vehicle"
|
||||||
buildConfigField 'int', 'NEW_TEST', '0'
|
buildConfigField 'int', 'NEW_TEST', '0'
|
||||||
}
|
}
|
||||||
// 车型:金旅m1 小巴业务
|
|
||||||
m1 {
|
|
||||||
dimension "vehicle"
|
|
||||||
buildConfigField 'int', 'NEW_TEST', '1'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 车型:金旅m1 小巴业务
|
// 车型:金旅m1 小巴业务
|
||||||
m2 {
|
m2 {
|
||||||
|
|||||||
38
OCH/sweeper/sweeper-cloud/AutopilotModeConfig.json
Normal file
@@ -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": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
16
OCH/sweeper/sweeper-cloud/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.mogo.och.sweepercloud">
|
||||||
|
|
||||||
|
<application>
|
||||||
|
<!--这里是为了测试增加的广播-->
|
||||||
|
<receiver android:name="com.mogo.och.sweepercloud.receiver.TestSweeperBroadcastReceiver">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.bus.test_control" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<Result> points;
|
||||||
|
|
||||||
|
public static class Result implements Serializable{
|
||||||
|
public Double latitude;
|
||||||
|
public Double longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SweeperRoutePlanningUpdateReqBean(String sn, int lineId, int startSiteId
|
||||||
|
, int endSiteId, ArrayList<Result> points) {
|
||||||
|
this.sn = sn;
|
||||||
|
this.lineId = lineId;
|
||||||
|
this.startSiteId = startSiteId;
|
||||||
|
this.endSiteId = endSiteId;
|
||||||
|
this.points = points;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.mogo.och.sweepercloud.callback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created on 2021/9/8
|
||||||
|
*
|
||||||
|
* Model->Presenter回调:ADAS相关(自动驾驶状态回调,到达终点等等)
|
||||||
|
*/
|
||||||
|
public interface ISweeperADASStatusCallback {
|
||||||
|
//自驾返回失败
|
||||||
|
void onStartAdasFailure();
|
||||||
|
}
|
||||||
@@ -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<SweeperRoutePlanningUpdateReqBean.Result>)
|
||||||
|
/**
|
||||||
|
* 贴边数据回传
|
||||||
|
*/
|
||||||
|
fun setWeltDataToMap(weltDataBeans: ArrayList<WeltDataBean?>, isWeltData: Boolean, distance: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 底盘清扫模式数据回传
|
||||||
|
*/
|
||||||
|
fun onSweeperFutianCleanSystemState(cleanSystemState: ChassisStatesOuterClass.SweeperFuTianTaskSystemStates)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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<SweeperRoutePlanningUpdateReqBean.Result>)
|
||||||
|
fun setWeltData(weltDatas: ArrayList<WeltDataBean>?, distance: String)
|
||||||
|
fun clearAllMarkerAndPolyline()
|
||||||
|
fun setProgress(progress:String)
|
||||||
|
fun setTaskListCoordinatesLatLng(coordinatesLatLng: ArrayList<LatLng>)
|
||||||
|
fun setCurrentTaskCoordinatesLatLng(coordinatesLatLng: LatLng)
|
||||||
|
}
|
||||||
@@ -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<SweeperRoutePlanningUpdateReqBean.Result>)
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.mogo.och.sweepercloud.callback
|
||||||
|
|
||||||
|
interface IWeltMapSwitchToSmallCallback {
|
||||||
|
fun onWeltMapSwitchToSmall()
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.mogo.och.sweepercloud.callback
|
||||||
|
|
||||||
|
interface SweeperCloudDialogClickListener {
|
||||||
|
fun onConfirm()
|
||||||
|
fun onRefuseOrEnd()
|
||||||
|
fun onCountDownStop()
|
||||||
|
fun onNext()
|
||||||
|
}
|
||||||
@@ -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);//暂无模式
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<WeltDataBean> loadAllWeltDataInfo();
|
||||||
|
}
|
||||||
@@ -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,主要负责布局通用界面,处理站点面板和通话面板互斥情况
|
||||||
|
* <p>
|
||||||
|
* 部分业务放在了此处处理
|
||||||
|
*
|
||||||
|
* @author tongchenfei
|
||||||
|
*/
|
||||||
|
public abstract class BaseSweeperTabFragment<V extends IView, P extends Presenter<V>> extends MvpFragment<V, P> 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<WeltDataBean> mWeltDataBeanList;//存储贴边数据
|
||||||
|
private ArrayList<LatLng> mSubTaskCoordinates;//存储当前大任务的所有子任务起点和终点
|
||||||
|
// 当前子任务的终点坐标
|
||||||
|
protected LatLng mCurrentTaskEndStation;
|
||||||
|
private ArrayList<SweeperRoutePlanningUpdateReqBean.Result> 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<WeltDataBean> 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<LatLng> 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<SweeperRoutePlanningUpdateReqBean.Result> 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<SweeperRoutePlanningUpdateReqBean.Result> resultArrayList = tempData();
|
||||||
|
setTaskRouteList(resultArrayList);
|
||||||
|
UiThreadHandler.postDelayed(() -> {
|
||||||
|
ArrayList<SweeperRoutePlanningUpdateReqBean.Result> routeList = tempData1();
|
||||||
|
ArrayList<WeltDataBean> weltDataBeans = new ArrayList<>();
|
||||||
|
ArrayList<LatLng> 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<SweeperRoutePlanningUpdateReqBean.Result> tempData() {
|
||||||
|
ArrayList<SweeperRoutePlanningUpdateReqBean.Result> 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<SweeperRoutePlanningUpdateReqBean.Result> tempData1() {
|
||||||
|
ArrayList<SweeperRoutePlanningUpdateReqBean.Result> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车道信息说明:
|
||||||
|
* <p>
|
||||||
|
* 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 = {
|
||||||
|
"直行"
|
||||||
|
, "左转"
|
||||||
|
, "左转或直行"
|
||||||
|
, "右转"
|
||||||
|
, "右转或这行"
|
||||||
|
, "左掉头"
|
||||||
|
, "左转或者右转"
|
||||||
|
, " 左转或右转或直行"
|
||||||
|
, "右转掉头"
|
||||||
|
, "直行或左转掉头"
|
||||||
|
, "直行或右转掉头"
|
||||||
|
, "左转或左掉头"
|
||||||
|
, "右转或右掉头"
|
||||||
|
, "直行并且车道扩展"
|
||||||
|
, "左转+左掉头+扩展"
|
||||||
|
, "不可以选择"
|
||||||
|
, "直行+左转+左掉头"
|
||||||
|
, "右转+左掉头"
|
||||||
|
, "左转+右转+左掉头"
|
||||||
|
, "直行+右转+左掉头"
|
||||||
|
, "左转+右掉头"
|
||||||
|
, "公交车道"
|
||||||
|
, "空车道"
|
||||||
|
, "可变车道"
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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<SweeperFragment?, SweeperPresenter?>() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "SweeperFragment"
|
||||||
|
}
|
||||||
|
|
||||||
|
private var mSubMutableList: MutableList<SubTaskInfo>? = 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<LatLng>()
|
||||||
|
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<SweeperRoutePlanningUpdateReqBean.Result>) {
|
||||||
|
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}分钟"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<LatLng>
|
||||||
|
val latLng = bundle.getParcelable<LatLng>("subTaskEndCoordinates")
|
||||||
|
val weltDataList = bundle.getSerializable("weltDataList") as? ArrayList<WeltDataBean>
|
||||||
|
val routeList = bundle.getSerializable("routeList") as? ArrayList<SweeperRoutePlanningUpdateReqBean.Result>
|
||||||
|
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<WeltDataBean>?,
|
||||||
|
latLngs: ArrayList<LatLng>?,
|
||||||
|
routeList: ArrayList<SweeperRoutePlanningUpdateReqBean.Result>?,
|
||||||
|
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<LatLng>) {
|
||||||
|
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<SweeperRoutePlanningUpdateReqBean.Result>) {
|
||||||
|
weltMapOverView?.setRouteList(routeList)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setWeltData(weltDatas: java.util.ArrayList<WeltDataBean>?, distance: String) {
|
||||||
|
weltMapOverView?.setWeltData(weltDatas,true,distance)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
* <p>
|
||||||
|
* 清扫车任务管理
|
||||||
|
*/
|
||||||
|
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<SweeperRoutePlanningUpdateReqBean.Result> 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<Integer, String> 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<Throwable>() {
|
||||||
|
@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<SweeperRoutePlanningUpdateReqBean.Result> coordinateConverterWgsToGcjList(Context mContext,
|
||||||
|
List<MessagePad.Location> mogoLatLngList) {
|
||||||
|
List<SweeperRoutePlanningUpdateReqBean.Result> 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<WeltDataBean>) 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<SweeperFragment>
|
||||||
|
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<SweeperRoutePlanningUpdateReqBean.Result> 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<WeltDataBean> 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<String, String> 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<String, String> 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<String, String>(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<String, String>(null, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<String, Object> 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<String, Object> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<SubTaskInfo>? = 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 = "强力"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<LatLng> = 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<Marker?> = 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<WeltDataBean>):MutableList<Int> {
|
||||||
|
val colorList= mutableListOf<Int>()
|
||||||
|
var nextWeltDataBean:WeltDataBean?=null
|
||||||
|
for (i in weltData.indices) {
|
||||||
|
val weltDataBean = weltData[i]
|
||||||
|
if(i+1<weltData.size){
|
||||||
|
nextWeltDataBean = weltData[i+1]
|
||||||
|
val calculateLineDistance = CoordinateUtils.calculateLineDistance(
|
||||||
|
nextWeltDataBean.locLon, nextWeltDataBean.locLat,
|
||||||
|
weltDataBean.locLon, weltDataBean.locLat
|
||||||
|
)
|
||||||
|
// 大于10m
|
||||||
|
if(calculateLineDistance>10){
|
||||||
|
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<WeltDataBean>?) {
|
||||||
|
weltDatas?.let {
|
||||||
|
val colorList=getRouteColorList(it)
|
||||||
|
val coordinatesLatLngs= mutableListOf<LatLng>()
|
||||||
|
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<WeltDataBean>?, isWeltData: Boolean, distance: String?) {
|
||||||
|
drawablePolyline(weltDatas)
|
||||||
|
ThreadUtils.runOnUiThread {
|
||||||
|
distance?.let {
|
||||||
|
setDistance(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if (!mFirst && isWeltData) {
|
||||||
|
// mFirst = true
|
||||||
|
// showOrHiddenLegendData(true)
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务轨迹数据
|
||||||
|
*/
|
||||||
|
fun setRouteList(routeList: ArrayList<SweeperRoutePlanningUpdateReqBean.Result>) {
|
||||||
|
val routeCoordinatesLatLngs= mutableListOf<LatLng>()
|
||||||
|
for (i in routeList.indices) {
|
||||||
|
routeCoordinatesLatLngs.add(LatLng(routeList[i].latitude,routeList[i].longitude))
|
||||||
|
}
|
||||||
|
ThreadUtils.runOnUiThread {
|
||||||
|
drawRouteListPolyline(routeCoordinatesLatLngs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun drawRouteListPolyline(routeList: MutableList<LatLng>) {
|
||||||
|
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<LatLng>) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<LatLng> = 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<Marker?> = 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<WeltDataBean>?) {
|
||||||
|
weltDatas?.let {
|
||||||
|
val colorList = getRouteColorList(it)
|
||||||
|
val coordinatesLatLngs = mutableListOf<LatLng>()
|
||||||
|
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<WeltDataBean>): MutableList<Int> {
|
||||||
|
val colorList = mutableListOf<Int>()
|
||||||
|
var nextWeltDataBean:WeltDataBean?=null
|
||||||
|
for (i in weltData.indices) {
|
||||||
|
val weltDataBean = weltData[i]
|
||||||
|
if(i+1<weltData.size){
|
||||||
|
nextWeltDataBean = weltData[i+1]
|
||||||
|
val calculateLineDistance = CoordinateUtils.calculateLineDistance(
|
||||||
|
nextWeltDataBean.locLon, nextWeltDataBean.locLat,
|
||||||
|
weltDataBean.locLon, weltDataBean.locLat
|
||||||
|
)
|
||||||
|
// 大于10m
|
||||||
|
if(calculateLineDistance>10){
|
||||||
|
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<LatLng>) {
|
||||||
|
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<WeltDataBean>, isWeltData: Boolean, distance: String) {
|
||||||
|
drawablePolyline(weltDatas)
|
||||||
|
ThreadUtils.runOnUiThread {
|
||||||
|
setWeltDistance(distance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置贴边距离
|
||||||
|
*/
|
||||||
|
private fun setWeltDistance(distance: String) {
|
||||||
|
taskWeltDistanceTv.text = "贴边:${distance}"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置任务轨迹数据
|
||||||
|
*/
|
||||||
|
fun setRouteList(routeList: ArrayList<SweeperRoutePlanningUpdateReqBean.Result>) {
|
||||||
|
val routeCoordinatesLatLngs = mutableListOf<LatLng>()
|
||||||
|
for (i in routeList.indices) {
|
||||||
|
routeCoordinatesLatLngs.add(LatLng(routeList[i].latitude, routeList[i].longitude))
|
||||||
|
}
|
||||||
|
ThreadUtils.runOnUiThread {
|
||||||
|
drawRouteListPolyline(routeCoordinatesLatLngs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun drawRouteListPolyline(routeList: MutableList<LatLng>) {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 622 KiB After Width: | Height: | Size: 622 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
BIN
OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_auto.png
Executable file
|
After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 544 B |
BIN
OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_manual_driving.png
Executable file
|
After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
BIN
OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_not_auto.png
Executable file
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 351 B After Width: | Height: | Size: 351 B |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 807 B After Width: | Height: | Size: 807 B |
|
Before Width: | Height: | Size: 1000 B After Width: | Height: | Size: 1000 B |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 484 B After Width: | Height: | Size: 484 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 24 KiB |
BIN
OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_cloud_rotate.png
Executable file
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |