markers) {
+ this.markers = markers;
+ }
+
+ public String getDistance() {
+ return distance;
+ }
+
+ public void setDistance(String distance) {
+ this.distance = distance;
+ }
+
+ public String getProgress() {
+ return progress;
+ }
+
+ public void setProgress(String progress) {
+ this.progress = progress;
+ }
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperTabFragment.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperTabFragment.java
new file mode 100644
index 0000000000..5832c58081
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperTabFragment.java
@@ -0,0 +1,604 @@
+package com.mogo.och.sweeper.fragment;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.amap.api.maps.model.LatLng;
+import com.amap.api.navi.model.NaviLatLng;
+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.function.api.autopilot.IMoGoAutopilotStatusListener;
+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.view.OnPreventFastClickListener;
+import com.mogo.eagle.core.utilcode.util.ThreadUtils;
+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.map.AmapNaviToDestinationModel;
+import com.mogo.och.sweeper.R;
+import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean;
+import com.mogo.och.sweeper.callback.ISweeperTaskDataToFragmentCallback;
+import com.mogo.och.sweeper.callback.IWeltMapSwitchToSmallCallback;
+import com.mogo.och.sweeper.database.bean.WeltDataBean;
+import com.mogo.och.sweeper.view.SweeperTrafficDataView;
+import com.mogo.och.sweeper.view.WeltSmallMapView;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.Group;
+import androidx.fragment.app.FragmentTransaction;
+
+/**
+ * 网约车基础Fragment,主要负责布局通用界面,处理站点面板和通话面板互斥情况
+ *
+ * 部分业务放在了此处处理
+ *
+ * @author tongchenfei
+ */
+public abstract class BaseSweeperTabFragment> extends MvpFragment implements IMogoMapListener,
+ View.OnClickListener, 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;
+ //人工驾驶地图View组控制
+ private Group mGroupNaviPanel;
+ //人工驾驶地图Fragment
+ private SweeperAmapNaviFragment mOchAmapNaviFragment;
+ //关闭人工驾驶小地图
+ private ImageView mCloseNavIcon;
+ //刷新人工驾驶地图按钮
+ private ImageView mRefreshNavi;
+ //作业任务贴边数据展示图
+ private WeltSmallMapView mMapWeltView;
+ //任务作业全览图
+ private WeltMapOverViewFragment mWeltMapOverViewFragment;
+ private FrameLayout mFlWeltMapOverView;
+ private DriverMsgBoxButtonView mViewDriverMsgBoxButton;
+ private DriverMsgBoxListView mViewDriverMsgBoxList;
+ private DriverMsgBoxBubbleView mViewDriverMsgBoxBubble;
+ private ArrayList mWeltDataBeanList;//存储贴边数据
+ private ArrayList mSubTaskCoordinates;//存储当前大任务的所有子任务起点和终点
+ // 当前子任务的终点坐标
+ protected LatLng mCurrentTaskEndStation;
+ private ArrayList mRouteList;//存储任务的坐标轨迹
+ private String mProgress;
+ private ISweeperTaskDataToFragmentCallback mTaskDataToFragmentCallback;
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.sweeper_base_fragment;
+ }
+
+ private View panelView;
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return true;
+ }
+
+ @Override
+ protected void initViews() {
+ mapBizView = findViewById(R.id.mapBizView);
+ groupTestPanel = findViewById(R.id.groupTestPanel);
+ mGroupNaviPanel = findViewById(R.id.group_navi_panel);
+ flTaskListPanelContainer = findViewById(R.id.module_mogo_och_task_list_container);
+ mTrafficDataView = findViewById(R.id.sweeper_arc);
+ panelView = 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);
+ mCloseNavIcon = findViewById(R.id.sweeper_close_navi_icon);
+ mRefreshNavi = findViewById(R.id.sweeper_refresh_navi);
+ mMapWeltView = findViewById(R.id.sweeper_task_welt_small_map);
+ mFlWeltMapOverView = findViewById(R.id.sweeper_welt_map_overview);
+ initListener();
+ //设置消息盒子
+ setMessageBox();
+ //设置左下角四个按钮监听事件
+ setBottomBtnListener();
+ // 模拟 不可自动驾驶,目前场景是刚开机,adas还未和工控机连接
+ findViewById(R.id.btnAutopilotDisable).setOnClickListener(view ->
+ debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE)
+ );
+
+ // 模拟 可自动驾驶,工控机连接正常,且处于人工干预状态
+ findViewById(R.id.btnAutopilotEnable).setOnClickListener(view ->
+ debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE)
+ );
+
+ // 模拟 自动驾驶能力,自动驾驶中,可能是停车,可能是行进,但是是机器在处理车的前进后退,不是人
+ findViewById(R.id.btnAutopilotRunning).setOnClickListener(view ->
+ debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING)
+ );
+ // 模拟 结束子任务
+ findViewById(R.id.btnEndTask).setOnClickListener(view ->
+ debugEndSubTask()
+ );
+ mTrafficDataView.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);
+ }
+
+ /**
+ * 消息盒子
+ */
+ 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);
+ mCloseNavIcon.setOnClickListener(this);
+ mRefreshNavi.setOnClickListener(this);
+ mMapWeltView.getSwitchToBig().setOnClickListener((v) -> {
+ showOrHideOverMapViewFragment(true);
+ });
+ }
+
+ /**
+ * 清扫车任务列表面板view,在{@link #initViews()}时候添加到container中
+ *
+ * @return 站点面板view
+ */
+ public abstract int getTaskListPanelViewId();
+
+ /**
+ * 模拟自动驾驶返回状态
+ *
+ * @param status
+ */
+ public abstract void debugAutoPilotStatus(int status);
+
+ /**
+ * 迈速表实时更新
+ *
+ * @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);
+ }
+ }
+
+
+ /**
+ * 展示人工驾驶地图导航
+ */
+ protected void showAmapNaviToStationFragment(boolean isShow) {
+ FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
+ if (isShow) {
+ mGroupNaviPanel.setVisibility(View.VISIBLE);
+ if (mOchAmapNaviFragment == null) {
+ mOchAmapNaviFragment=SweeperAmapNaviFragment.newInstance();
+ }
+ if (mOchAmapNaviFragment.isHidden()) {
+ transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
+ .show(mOchAmapNaviFragment).commitAllowingStateLoss();
+ return;
+ }
+ if (mOchAmapNaviFragment.isAdded()) {
+ transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
+ .show(mOchAmapNaviFragment).commitAllowingStateLoss();
+ return;
+ }
+ transaction
+ .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
+ .add(R.id.module_mogo_och_navi_panel_container, mOchAmapNaviFragment)
+ .show(mOchAmapNaviFragment).commitAllowingStateLoss();
+ } else {
+ AmapNaviToDestinationModel.getInstance(getContext()).destroyAmaNavi();
+ if (mOchAmapNaviFragment != null) {
+ transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE)
+ .hide(mOchAmapNaviFragment).commitAllowingStateLoss();
+ }
+ mGroupNaviPanel.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+ if (id == R.id.sweeper_close_navi_icon) {
+ showAmapNaviToStationFragment(false);
+ } else if (id == R.id.sweeper_refresh_navi) {
+ refreshNavi();
+ }
+ }
+
+ public abstract void refreshNavi();
+
+ /**
+ * 设置作业任务全览图隐藏或者显示
+ *
+ * @param isShow
+ */
+ public void showOrHideOverMapViewFragment(boolean isShow) {
+ FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
+ if (isShow) {
+ mFlWeltMapOverView.setVisibility(View.VISIBLE);
+ if (mWeltMapOverViewFragment == null) {
+ mWeltMapOverViewFragment = mWeltMapOverViewFragment.newInstance(
+ (IWeltMapSwitchToSmallCallback) this,
+ mCurrentTaskEndStation,
+ mWeltDataBeanList,
+ mSubTaskCoordinates,
+ mRouteList,
+ mProgress,
+ (SweeperFragment) this);
+ }
+ if (mWeltMapOverViewFragment.isHidden()) {
+ transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
+ .show(mWeltMapOverViewFragment).commitAllowingStateLoss();
+ return;
+ }
+ if (mWeltMapOverViewFragment.isAdded()) {
+ transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
+ .show(mWeltMapOverViewFragment).commitAllowingStateLoss();
+ return;
+ }
+ transaction
+ .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
+ .add(R.id.sweeper_welt_map_overview, mWeltMapOverViewFragment)
+ .show(mWeltMapOverViewFragment).commitAllowingStateLoss();
+ } else {
+ mFlWeltMapOverView.setVisibility(View.GONE);
+ if (mWeltMapOverViewFragment != null) {
+ transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE)
+ .hide(mWeltMapOverViewFragment).commitAllowingStateLoss();
+ }
+ }
+ }
+
+ @Override
+ public void onWeltMapSwitchToSmall() {
+ showOrHideOverMapViewFragment(false);
+ }
+
+ /**
+ * 设置贴边数据到地图
+ *
+ * @param weltDataBeans
+ */
+ public void setWeltDataToMap(ArrayList weltDataBeans, Boolean isWeltData, String distance) {
+ mWeltDataBeanList = weltDataBeans;
+ ThreadUtils.getSinglePool().execute(new Runnable() {
+ @Override
+ public void run() {
+ if (mMapWeltView != null) {
+ mMapWeltView.setWeltData(weltDataBeans, isWeltData, distance);
+ }
+ if (mTaskDataToFragmentCallback != null) {
+ mTaskDataToFragmentCallback.setWeltData(weltDataBeans, distance);
+ }
+ }
+ });
+ }
+
+ public void setTaskListCoordinatesLatLng(ArrayList subTaskCoordinates) {
+ this.mSubTaskCoordinates = subTaskCoordinates;
+ if (mMapWeltView != null) {
+ mMapWeltView.setTaskListCoordinatesLatLng(subTaskCoordinates);
+ }
+ if (mTaskDataToFragmentCallback != null) {
+ mTaskDataToFragmentCallback.setTaskListCoordinatesLatLng(subTaskCoordinates);
+ }
+ }
+
+ 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 startNaviToStation(Boolean isVoicePlay, double startLat, double startLng, double endLat, double endLng) {
+ AmapNaviToDestinationModel.getInstance(getContext()).destroyAmaNavi();
+ NaviLatLng startNaviLatLng = new NaviLatLng(startLat, startLng);
+ NaviLatLng endNaviLatLng = new NaviLatLng(endLat, endLng);
+ AmapNaviToDestinationModel.getInstance(getContext()).initAMapNavi(startNaviLatLng, endNaviLatLng);
+ AmapNaviToDestinationModel.getInstance(getContext()).setVoiceIsMute(isVoicePlay);
+ }
+
+ /**
+ * 设置任务轨迹点数据
+ */
+ public void setTaskRouteList(ArrayList routeList) {
+ mRouteList = routeList;
+ ThreadUtils.getSinglePool().execute(new Runnable() {
+ @Override
+ public void run() {
+ mMapWeltView.setRouteList(routeList);
+ if (mTaskDataToFragmentCallback != null) {
+ mTaskDataToFragmentCallback.setRouteList(routeList);
+ }
+ }
+ });
+ }
+
+ public static String format(double value) {
+ BigDecimal bd = new BigDecimal(value);
+ bd = bd.setScale(2, RoundingMode.HALF_UP);
+ return bd.toString();
+ }
+
+ public void setTaskDataToFragmentCallback(ISweeperTaskDataToFragmentCallback mTaskDataToFragmentCallback) {
+ this.mTaskDataToFragmentCallback = mTaskDataToFragmentCallback;
+ }
+
+ /**
+ * 结束子任务
+ */
+ public void debugEndSubTask() {
+ ArrayList resultArrayList = tempData();
+ setTaskRouteList(resultArrayList);
+ UiThreadHandler.postDelayed(() -> {
+ ArrayList routeList =tempData1();
+ ArrayList weltDataBeans = new ArrayList<>();
+ ArrayList subTaskCoordinates=new ArrayList<>();
+ for (int i = 0; i < routeList.size(); i++) {
+ WeltDataBean weltDataBean = new WeltDataBean();
+ weltDataBean.setLocLon(routeList.get(i).longitude);
+ weltDataBean.setLocLat(routeList.get(i).latitude);
+ weltDataBean.setWeltDistance(Math.random() * 50);
+ weltDataBeans.add(weltDataBean);
+ subTaskCoordinates.add(new LatLng(routeList.get(i).latitude,routeList.get(i).longitude));
+ }
+ setTaskListCoordinatesLatLng(subTaskCoordinates);
+ setWeltDataToMap(weltDataBeans, true, format(Math.random() * 50));
+ }, 2000);
+ }
+
+ private ArrayList tempData() {
+ ArrayList results = new ArrayList<>();
+ results.add(getRoute(116.41732262522,39.974576894194));
+ results.add(getRoute(116.43963532201855,39.9752190287537));
+ results.add(getRoute(116.4440910789222,39.96469276598098));
+ results.add(getRoute(116.45254030604285,39.958762580403544));
+ results.add(getRoute(116.46168616811329,39.94668171374373));
+ return results;
+ }
+ private ArrayList tempData1() {
+ ArrayList results = new ArrayList<>();
+ results.add(getRoute(116.41732262522,39.974576894194));
+ results.add(getRoute(116.43963532201855,39.9752190287537));
+ results.add(getRoute(116.4440910789222,39.96469276598098));
+ return results;
+ }
+ private SweeperRoutePlanningUpdateReqBean.Result getRoute(double longitude,double latitude){
+ SweeperRoutePlanningUpdateReqBean.Result result = new SweeperRoutePlanningUpdateReqBean.Result();
+ result.latitude = latitude;
+ result.longitude =longitude;
+ return result;
+ }
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperUIFragment.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperUIFragment.java
new file mode 100644
index 0000000000..3ee40b9134
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperUIFragment.java
@@ -0,0 +1,50 @@
+package com.mogo.och.sweeper.fragment;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+/**
+ * @author: wangmingjun
+ * @date: 2021/9/9
+ */
+public abstract class BaseSweeperUIFragment extends Fragment {
+ private View mRootView;
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ if (mRootView == null) {
+ mRootView = inflater.inflate(getLayoutId(), container, false);
+ } else {
+ ViewGroup viewGroup = (ViewGroup) mRootView.getParent();
+ if (viewGroup != null) {
+ viewGroup.removeView(mRootView);
+ }
+ }
+ initViews(mRootView);
+ initViews(savedInstanceState);
+ return mRootView;
+ }
+ /**
+ * 布局资源
+ *
+ * @return
+ */
+ protected abstract int getLayoutId();
+
+ protected abstract void initViews(View view);
+
+ protected void initViews(Bundle savedInstanceState) {
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mRootView = null;
+ }
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/SweeperAmapNaviFragment.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/SweeperAmapNaviFragment.java
new file mode 100644
index 0000000000..a1460e31c7
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/SweeperAmapNaviFragment.java
@@ -0,0 +1,230 @@
+package com.mogo.och.sweeper.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.sweeper.R;
+
+import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_TAXI;
+
+/**
+ * @author: wangmingjun
+ * @date: 2021/11/30
+ */
+public class SweeperAmapNaviFragment extends BaseSweeperUIFragment implements AMapNaviViewListener {
+
+ private CommonAmapNaviVIew mAMapNaviView;
+ private ICommonNaviChangedCallback mNaviToStartInfoCallback;
+ public static SweeperAmapNaviFragment newInstance() {
+
+ Bundle args = new Bundle();
+
+ SweeperAmapNaviFragment fragment = new SweeperAmapNaviFragment();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.sweeper_amap_navi_view;
+ }
+
+ @Override
+ protected void initViews(View view) {
+ mAMapNaviView = view.findViewById(R.id.navi_view);
+ }
+
+ @Override
+ protected void initViews(Bundle savedInstanceState) {
+ super.initViews(savedInstanceState);
+ if (mAMapNaviView != null)
+ mAMapNaviView.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mAMapNaviView != null)
+ mAMapNaviView.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (mAMapNaviView != null)
+ mAMapNaviView.onPause();
+ }
+
+ @Override
+ public void onHiddenChanged(boolean hidden) {
+ super.onHiddenChanged(hidden);
+ if (hidden) { //不在最前端界面显示
+ if (mAMapNaviView != null){
+ mAMapNaviView.onPause();
+ }
+ } else { //重新显示到最前端
+ if (mAMapNaviView != null){
+ mAMapNaviView.onResume();
+ }
+ }
+ }
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ AmapNaviToDestinationModel.getInstance(getContext()).setVoiceIsMute(false);
+ if (mAMapNaviView != null){
+ mAMapNaviView.onDestroy();
+ }
+
+ if (mNaviToStartInfoCallback != null){
+ mNaviToStartInfoCallback = null;
+ }
+ }
+
+ @Override
+ public void onNaviSetting() {
+ //底部导航设置点击回调
+ }
+
+ @Override
+ public void onNaviCancel() {
+ }
+
+ @Override
+ public void onNaviMapMode(int naviMode) {
+ //导航态车头模式,0:车头朝上状态;1:正北朝上模式。
+ }
+
+ @Override
+ public void onNaviTurnClick() {
+ //转弯view的点击回调
+ }
+
+ @Override
+ public void onNextRoadClick() {
+ //下一个道路View点击回调
+ }
+
+
+ @Override
+ public void onScanViewButtonClick() {
+ //全览按钮点击回调
+ }
+
+
+ @Override
+ public void onLockMap(boolean isLock) {
+ //锁地图状态发生变化时回调
+ }
+
+ @Override
+ public void onNaviViewLoaded() {
+ CallerLogger.INSTANCE.d(M_TAXI + "wlx", "导航页面加载成功");
+ CallerLogger.INSTANCE.d(M_TAXI + "wlx", "请不要使用AMapNaviView.getMap().setOnMapLoadedListener();会overwrite导航SDK内部画线逻辑");
+ }
+
+ @Override
+ public void onMapTypeChanged(int i) {
+
+ }
+
+ @Override
+ public void onNaviViewShowMode(int i) {
+
+ }
+
+ @Override
+ public boolean onNaviBackClick() {
+ return false;
+ }
+
+ /**
+ * 车道信息说明:
+ *
+ * 0xFF, 无对应车道
+ * 0, 直行
+ * 1, 左转
+ * 2, 直行+左转
+ * 3, 右转
+ * 4, 直行+右转
+ * 5, 左掉头
+ * 6, 左转+右转
+ * 7, 直行+左转+右转
+ * 8, 右掉头
+ * 9, 直行+左掉头
+ * 10, 直行+右掉头
+ * 11, 左转+左掉头
+ * 12, 右转+右掉头
+ * 13, 直行+扩展
+ * 14, 左转+左掉头+扩展
+ * 15, 保留
+ * 16, 直行+左转+左掉头
+ * 17, 右转+左掉头
+ * 18, 左转+右转+左掉头
+ * 19, 直行+右转+左掉头
+ * 20, 左转+右掉头
+ * 21, 公交车道
+ * 22, 空车道
+ * 23 可变车道
+ */
+
+ String[] array = {
+ "直行车道"
+ , "左转车道"
+ , "左转或直行车道"
+ , "右转车道"
+ , "右转或直行车道"
+ , "左掉头车道"
+ , "左转或者右转车道"
+ , " 左转或右转或直行车道"
+ , "右转掉头车道"
+ , "直行或左转掉头车道"
+ , "直行或右转掉头车道"
+ , "左转或左掉头车道"
+ , "右转或右掉头车道"
+ , "直行并且车道扩展"
+ , "左转+左掉头+扩展"
+ , "不可以选择该车道"
+ , "直行+左转+左掉头车道"
+ , "右转+左掉头"
+ , "左转+右转+左掉头"
+ , "直行+右转+左掉头"
+ , "左转+右掉头"
+ , "公交车道"
+ , "空车道"
+ , "可变车道"
+ };
+
+ String[] actions = {
+ "直行"
+ , "左转"
+ , "左转或直行"
+ , "右转"
+ , "右转或这行"
+ , "左掉头"
+ , "左转或者右转"
+ , " 左转或右转或直行"
+ , "右转掉头"
+ , "直行或左转掉头"
+ , "直行或右转掉头"
+ , "左转或左掉头"
+ , "右转或右掉头"
+ , "直行并且车道扩展"
+ , "左转+左掉头+扩展"
+ , "不可以选择"
+ , "直行+左转+左掉头"
+ , "右转+左掉头"
+ , "左转+右转+左掉头"
+ , "直行+右转+左掉头"
+ , "左转+右掉头"
+ , "公交车道"
+ , "空车道"
+ , "可变车道"
+ };
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/SweeperFragment.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/SweeperFragment.kt
new file mode 100644
index 0000000000..de0eae391b
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/SweeperFragment.kt
@@ -0,0 +1,527 @@
+package com.mogo.och.sweeper.fragment
+
+import android.graphics.Color
+import android.os.Bundle
+import android.view.View
+import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.LinearLayoutManager
+import chassis.ChassisStatesOuterClass
+import com.amap.api.maps.model.LatLng
+import com.mogo.commons.AbsMogoApplication
+import com.mogo.eagle.core.data.map.MogoLocation
+import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
+import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
+import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
+import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
+import com.mogo.eagle.core.utilcode.util.ClickUtils
+import com.mogo.eagle.core.utilcode.util.ToastUtils
+import com.mogo.och.common.module.utils.CoordinateCalculateRouteUtil
+import com.mogo.och.sweeper.R
+import com.mogo.och.sweeper.bean.*
+import com.mogo.och.sweeper.constant.SubTaskTypeEnum
+import com.mogo.och.sweeper.constant.TaskStatusEnum
+import com.mogo.och.sweeper.database.MyDataBase
+import com.mogo.och.sweeper.presenter.SweeperPresenter
+import com.mogo.och.sweeper.ui.adapter.TaskListAdapter
+import com.mogo.och.sweeper.ui.dialog.SweeperManualDrivingDialog
+import com.mogo.och.sweeper.ui.dialog.SweeperNoTitleCommonDialog
+import com.mogo.och.sweeper.ui.popwindow.MenuPopWindow
+import kotlinx.android.synthetic.main.fragment_och_sweeper.*
+import kotlinx.android.synthetic.main.sweeper_current_task_info.view.*
+import kotlinx.android.synthetic.main.sweeper_no_data_common_view.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlin.math.roundToInt
+
+/**
+ * 清扫车主界面
+ */
+class SweeperFragment : BaseSweeperTabFragment(), MenuPopWindow.OnMenuItemOnClickListener {
+
+ companion object {
+ const val TAG = "SweeperFragment"
+ }
+
+ private var mAdapter: TaskListAdapter? = null
+ private var mCurrentSubPosition: Int = 0 //子任务下标
+ private var mSubMutableList: MutableList? = null
+ private var mSubTaskBean: SweeperSubTaskBean? = null
+ private var mSubTaskType: SubTaskTypeEnum = SubTaskTypeEnum.AUTOPILOT_SUBTYPE //1:自动驾驶子任务 2:人工驾驶子任务
+ private var mCleanSystemState: ChassisStatesOuterClass.SweeperFuTianTaskSystemStates? = null
+ private var mMainTask: SweeperMainTaskBean? = null
+ private var mLocation: MogoLocation? = null
+ private var mSubInfo: SubInfo? = null
+
+ override fun getTagName(): String {
+ return "SweepersFragment"
+ }
+
+ override fun initViews() {
+ super.initViews()
+ mAdapter = context?.let { TaskListAdapter() }
+ val linearLayoutManager = LinearLayoutManager(context)
+ linearLayoutManager.orientation = LinearLayoutManager.VERTICAL
+ rvTaskList?.layoutManager = linearLayoutManager
+ rvTaskList?.adapter = mAdapter
+ mAdapter?.setOnTaskItemClickListener(onTaskItemClickListener)
+ initListener()
+ sweeper_cl_work_mode.setTrafficDataView(trafficDataView)
+ sweeper_current_task_view.readyTaskBtn.setOnClickListener {
+ if (ClickUtils.isFastClick()) {//防止重复点击
+ if (mSubTaskType.code == SubTaskTypeEnum.MANUAL_DRIVING_SUBTYPE.code) {
+ manualDriving(false)
+ } else {
+ //开始执行任务
+ mSubInfo?.apply {
+ presenter?.startTask(isFirstSubTask(), isLastSubTask(), taskId, mSubTaskType, taskStatus)
+ }
+ }
+ }
+ }
+ }
+
+ 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
+ }
+
+ /**
+ * 任务列表面板隐藏或显示
+ *
+ * @return
+ */
+ private fun setShowTaskListPanelView(isShow: Boolean) {
+ tvTaskConfirm.setTextColor(Color.parseColor("#66FFFFFF"))
+ tvTaskConfirm.isSelected = false
+ if (isShow) {
+ sweeper_current_task_list_view.visibility = View.VISIBLE
+ } else {
+ sweeper_current_task_list_view.visibility = View.GONE
+ }
+ }
+
+ /**
+ * 当前任务面板隐藏或显示
+ *
+ * @return
+ */
+ private fun setShowCurrentTaskPanelView(isShow: Boolean) {
+ if (isShow) {
+ sweeper_current_task_view.visibility = View.VISIBLE
+ } else {
+ sweeper_current_task_view.visibility = View.GONE
+ }
+ }
+
+ /**
+ * VR模式切换
+ *
+ * @param isVRMode
+ */
+ fun onVRModeChanged(isVRMode: Boolean) {
+ if (mRootView != null) {
+ mRootView.visibility = if (isVRMode) View.VISIBLE else View.GONE
+ }
+ }
+
+ fun hideOchSweeper() {}
+ override fun debugAutoPilotStatus(status: Int) {
+ mPresenter?.debugAutoPilotStatus(status)
+ }
+
+ /**
+ * 根据自动驾驶状态更新按钮
+ */
+ fun startAutoBtn(autopilotState: Int) {
+ sweeper_current_task_view.setStartAutoBtn(autopilotState)
+ }
+
+ /**
+ * 任务按钮状态
+ */
+ fun setTaskBtn(isWorking: Boolean) {
+ sweeper_current_task_view.setEnableClickBtn(isWorking)
+ }
+
+ /**
+ * 设置各种监听事件
+ */
+ private fun initListener() {
+ tvTaskConfirm.setOnClickListener {
+ mMainTask?.let { task ->
+ mCurrentSubPosition = 0
+ mSubTaskBean = SweeperSubTaskBean(task.mainTaskId, task.mainTaskName, task.mainTaskStartTime, 1, mSubMutableList)
+ //获取当前子任务列表
+ presenter?.getSubTaskList(task.mainTaskId, mSubTaskBean)
+ mAdapter?.selectPosition(-1)
+ }
+ }
+ //列表任务刷新
+ ivTaskListRefresh.setOnClickListener {
+ mPresenter?.getMainTaskList(true)
+ }
+ //无任务时刷新
+ ivNoTaskRefresh.setOnClickListener {
+ mPresenter?.getMainTaskList(true)
+ }
+ }
+
+ private val onTaskItemClickListener = object : TaskListAdapter.TaskItemClickListener {
+ override fun onItemClick(position: Int, mainTask: SweeperMainTaskBean) {
+ mAdapter?.selectPosition(position)
+ tvTaskConfirm.isSelected = true
+ tvTaskConfirm.setTextColor(Color.parseColor("#FFFFFFFF"))
+ this@SweeperFragment.mMainTask = mainTask
+ }
+
+ }
+
+ override fun onMenuItemClick(itemType: TaskStatusEnum) {
+ when (itemType.code) {
+ TaskStatusEnum.JUMP_OVER_SUBTASK.code -> {//跳过任务
+ mSubInfo?.let {
+ //如果当前只有一个子任务,则isFirst设置为false
+ presenter?.subTaskSkip(if (mSubMutableList?.size == 1) false else isFirstSubTask(), isLastSubTask(), it.taskId)
+ }
+ }
+ TaskStatusEnum.END_TASK.code -> {//结束主任务
+ endMainTask()
+ }
+ }
+ }
+
+ fun onSweeperFutianCleanSystemState(cleanSystemState: ChassisStatesOuterClass.SweeperFuTianTaskSystemStates) {
+ lifecycleScope.launch(Dispatchers.Main) {
+ mCleanSystemState = cleanSystemState
+ sweeper_cl_work_mode.setSweeperFutianCleanSystemState(mSubTaskType, cleanSystemState)
+ }
+ }
+
+ /**
+ * 设置当前主任务列表数据
+ */
+ fun setMainTaskList(mainTaskBeanList: MutableList?, refresh: Boolean) {
+ setShowCurrentTaskPanelView(false)
+ setShowTaskListPanelView(true)
+ sweeper_cl_work_mode.visibility = View.GONE
+ if (mainTaskBeanList != null && mainTaskBeanList.isNotEmpty()) {
+ noTaskDataView.visibility = View.GONE
+ sweeperListCl.visibility = View.VISIBLE
+ mAdapter?.setTaskListData(mainTaskBeanList)
+ } else {
+ noTaskDataView.visibility = View.VISIBLE
+ sweeperListCl.visibility = View.GONE
+ }
+ if (refresh) {
+ ToastUtils.showLong("已刷新")
+ }
+ }
+
+ /**
+ * 设置当前子任务列表数据
+ */
+ fun setSubTaskBean(subTaskBean: SweeperSubTaskBean, isWorkingSubTask: Boolean) {
+ this.mSubTaskBean = subTaskBean
+ this.mSubTaskBean?.let {
+ setShowCurrentTaskPanelView(true)
+ setShowTaskListPanelView(false)
+ sweeper_cl_work_mode.visibility = View.VISIBLE
+ mCurrentSubPosition = if (isWorkingSubTask) {//如果是正在执行的子任务
+ it.sort - 1
+ } else {
+ 0
+ }
+ d(SceneConstant.M_SWEEPER + TAG, "setSubTaskBean mCurrentSubPosition:$mCurrentSubPosition")
+ sweeper_current_task_view.setData(sweeper_cl_work_mode, it, mCurrentSubPosition, this, presenter)
+ mSubMutableList = it.subList
+ setSubTaskData()
+ if (mSubTaskType.code == SubTaskTypeEnum.AUTOPILOT_SUBTYPE.code) {//自动驾驶子任务需要调用详情
+ mSubInfo?.let { subInfo ->
+ presenter?.getSubTaskDetail(isFirstSubTask(), isLastSubTask(), subInfo.taskId, mSubTaskType, false)//加载子任务详情包括轨迹信息
+ }
+ }
+ mMainTask = SweeperMainTaskBean(it.taskId, it.taskName, 0, it.taskStartTime)
+ clearAllMarkerAndPolyline()
+ addWeltData()
+ }
+ }
+
+ /**
+ * 更新子任务状态
+ */
+ fun updateSubTaskStatus(typeEnum: TaskStatusEnum, isLastSubTask: Boolean) {
+ if (isLastSubTask) {
+ showAmapNaviToStationFragment(false)
+ clearAllMarkerAndPolyline()
+ //整个大任务结束,则删除它相关的贴边数据缓存
+ lifecycleScope.launch(Dispatchers.IO) {
+ MyDataBase.getInstance().weltDataDao.deleteAllWeltData()
+ mPresenter?.clearRouteList()
+ }
+ setTaskProgress("0")
+
+ val builder = SweeperManualDrivingDialog.Builder()
+ val endConfirmDialog = builder
+ .tips("任务已完成")
+ .confirmStr("确认")
+ .build(requireContext())
+ endConfirmDialog?.setClickListener(object: SweeperManualDrivingDialog.ClickListener{
+ override fun confirm() {
+ mPresenter?.getMainTaskList(false)
+ }
+ })
+ endConfirmDialog?.show()
+ return
+ }
+ when (typeEnum.code) {
+ TaskStatusEnum.END_SUBTASK.code -> {//子任务结束
+ mCurrentSubPosition++
+ setSubTaskData()
+ d(SceneConstant.M_SWEEPER + TAG, "END_SUBTASK mCurrentSubPosition:$mCurrentSubPosition")
+ if (mSubTaskType.code == SubTaskTypeEnum.AUTOPILOT_SUBTYPE.code) {//自动驾驶子任务
+ //关闭人工驾驶导航
+ showAmapNaviToStationFragment(false)
+ mSubInfo?.apply {
+ presenter?.getSubTaskDetail(isFirstSubTask(), isLastSubTask(), taskId, mSubTaskType, true)
+ }
+ sweeper_current_task_view.setCurrentData(mCurrentSubPosition)
+ } else {
+ manualDriving(true)
+ }
+ }
+ TaskStatusEnum.JUMP_OVER_SUBTASK.code -> { //子任务跳过
+ //是否是最后一个子任务结束
+ mCurrentSubPosition++
+ setSubTaskData()
+ d(SceneConstant.M_SWEEPER + TAG, "JUMP_OVER_SUBTASK mCurrentSubPosition:$mCurrentSubPosition")
+ showAmapNaviToStationFragment(false)
+ if (mSubTaskType.code == SubTaskTypeEnum.AUTOPILOT_SUBTYPE.code) {//自动驾驶子任务
+ //关闭人工驾驶导航
+ showAmapNaviToStationFragment(false)
+ mSubInfo?.apply {
+ presenter?.getSubTaskDetail(isFirstSubTask(), isLastSubTask(), taskId, mSubTaskType, true)
+ }
+ sweeper_current_task_view.setCurrentData(mCurrentSubPosition)
+ } else {
+ manualDriving(true)
+ }
+ }
+ TaskStatusEnum.START_SUBTASK.code -> { //子任务开始
+ setTaskBtn(true)
+ sweeper_current_task_view.setTaskStatus(2)
+ if (mSubTaskType == SubTaskTypeEnum.MANUAL_DRIVING_SUBTYPE) {
+ sweeper_current_task_view.setCurrentData(mCurrentSubPosition)
+ }
+ }
+ }
+ setEndStationMarker()
+ }
+
+ /**
+ * 主任务重置
+ */
+ fun setMainTaskReset(isSuccess: Boolean) {
+ if (isSuccess) {
+ //任务重置后,重新拉取任务列表数据
+ mPresenter?.getMainTaskList(false)
+ //清除任务全览图的marker和路线
+ clearAllMarkerAndPolyline()
+ showAmapNaviToStationFragment(false)
+ setTaskProgress("0")
+ //整个大任务结束,则删除它相关的贴边数据缓存
+ lifecycleScope.launch(Dispatchers.IO) {
+ MyDataBase.getInstance().weltDataDao.deleteAllWeltData()
+ mPresenter?.clearRouteList()
+ }
+ }
+ }
+
+ /**
+ * 设置当前选中的子任务信息
+ */
+ private fun setSubTaskData() {
+ mSubMutableList?.let {
+ mSubInfo = it[mCurrentSubPosition]
+ mSubTaskType = if (it[mCurrentSubPosition].taskType == SubTaskTypeEnum.AUTOPILOT_SUBTYPE.code)
+ SubTaskTypeEnum.AUTOPILOT_SUBTYPE else SubTaskTypeEnum.MANUAL_DRIVING_SUBTYPE
+ //设置当前子任务信息
+ presenter?.setSubtask(isFirstSubTask(), isLastSubTask(), it[mCurrentSubPosition].taskId, it[mCurrentSubPosition].taskType)
+ }
+ /**
+ * 计算任务的进度
+ */
+ lifecycleScope.launch(Dispatchers.IO) {
+ mSubMutableList?.let {
+ var sum: Double = 0.0
+ for (index in it.indices) {
+ sum += it[index].mileage
+ }
+ var completed: Double = 0.0
+ for (index in it.indices) {
+ if (index < mCurrentSubPosition) {
+ // 已完成的子任务记入完成度,进行中的不计入
+ completed += it[index].mileage
+ }
+ }
+ val progress = "${((completed / sum) * 100.0).roundToInt()}%"
+ setTaskProgress(progress)
+ }
+
+ }
+ }
+ /**
+ * 结束主任务
+ */
+ private fun endMainTask() {
+ //结束任务
+ val builder = SweeperNoTitleCommonDialog.Builder()
+ val endConfirmDialog = builder
+ .tips("是否结束任务?")
+ .confirmStr("确认")
+ .cancelStr("取消")
+ .build(requireContext())
+ endConfirmDialog?.setClickListener(object : SweeperNoTitleCommonDialog.ClickListener {
+ override fun confirm() {
+ mMainTask?.let {
+ presenter?.mainTaskReset(it.mainTaskId)
+ }
+ }
+
+ override fun cancel() {
+ endConfirmDialog?.dismiss()
+ }
+ })
+ endConfirmDialog?.show()
+ }
+
+ /**
+ * 人工驾驶子任务
+ */
+ private fun manualDriving(isCancelAutoPoilot: Boolean) {
+ if (isCancelAutoPoilot) { // 人工子任务 先取消自动驾驶
+ CallerAutoPilotStatusListenerManager.updateAutopilotControlParameters(null)
+ CallerAutoPilotControlManager.cancelAutoPilot()
+ }
+
+ mSubInfo?.apply {
+ val builder = SweeperManualDrivingDialog.Builder()
+ val endConfirmDialog = builder
+ .tips("前方子任务${taskName}请人工驾驶至(${endSiteName})")
+ .confirmStr("确认")
+ .build(requireContext())
+ endConfirmDialog?.setClickListener(object : SweeperManualDrivingDialog.ClickListener {
+ override fun confirm() {
+ presenter?.startTask(isFirstSubTask(), isLastSubTask(), taskId, mSubTaskType, taskStatus)
+ val startPoint =
+ CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj(AbsMogoApplication.getApp(), startWgs84Lon, startWgs84Lat)
+ val endPoint = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj(AbsMogoApplication.getApp(), endWgs84Lon, endWgs84Lat)
+ startNaviToStation(
+ true,
+ startPoint.latitude,
+ startPoint.longitude,
+ endPoint.latitude,
+ endPoint.longitude
+ )
+ showAmapNaviToStationFragment(true)
+ }
+ })
+ endConfirmDialog?.show()
+ }
+ }
+
+ /**
+ * 是否第一个子任务
+ */
+ fun isFirstSubTask(): Boolean {
+ return mCurrentSubPosition == 0
+ }
+
+ /**
+ * 是否最后一个子任务
+ */
+ fun isLastSubTask(): Boolean {
+ return mCurrentSubPosition == (mSubMutableList?.size?.minus(1))
+ }
+
+ /**
+ * 当前位置经纬度
+ */
+ fun setCurrentLocation(location: MogoLocation) {
+ this.mLocation = location
+ }
+
+ override fun refreshNavi() {
+ mSubInfo?.apply {
+ mLocation?.let {
+ val endPoint = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj(AbsMogoApplication.getApp(), endWgs84Lon, endWgs84Lat)
+ startNaviToStation(true, it.latitude, it.longitude, endPoint.latitude, endPoint.longitude)
+ }
+ }
+ }
+
+ private fun addWeltData() {
+ lifecycleScope.launch(Dispatchers.IO) {
+ mSubMutableList?.let { subList ->
+ if (subList.size <= 0) {
+ return@launch
+ }
+ val dataList = ArrayList()
+ for (index in subList.indices) {
+ val startPoint = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj(
+ AbsMogoApplication.getApp(),
+ subList[index].startWgs84Lon,
+ subList[index].startWgs84Lat
+ )
+ val startLatLng = LatLng(startPoint.latitude, startPoint.longitude)
+ dataList.add(index,startLatLng)
+ val endPoint = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj(
+ AbsMogoApplication.getApp(),
+ subList[index].endWgs84Lon,
+ subList[index].endWgs84Lat
+ )
+ val endLatLng = LatLng(endPoint.latitude, endPoint.longitude)
+ dataList.add(index+1,endLatLng)
+ }
+ setTaskListCoordinatesLatLng(dataList)
+ setEndStationMarker()
+ }
+ }
+ }
+
+ private fun setEndStationMarker(){
+ lifecycleScope.launch(Dispatchers.IO) {
+ mSubInfo?.let {
+ val endPoint = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj(
+ AbsMogoApplication.getApp(),
+ it.endWgs84Lon,
+ it.endWgs84Lat
+ )
+ super.mCurrentTaskEndStation = endPoint
+ setCurrentTaskEndMarker(endPoint)
+ }
+ }
+ }
+
+
+
+ //模拟结束子任务
+ override fun debugEndSubTask() {
+ mPresenter?.onArriveTaskEnd(null)
+ //super.debugEndSubTask()
+ }
+
+ /**
+ * 设置路线轨迹
+ */
+ override fun setTaskRouteList(routeList: ArrayList) {
+ super.setTaskRouteList(routeList)
+ }
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/WeltMapOverViewFragment.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/WeltMapOverViewFragment.kt
new file mode 100644
index 0000000000..a34f658856
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/WeltMapOverViewFragment.kt
@@ -0,0 +1,129 @@
+package com.mogo.och.sweeper.fragment
+
+import android.os.Bundle
+import com.amap.api.maps.model.LatLng
+import com.mogo.commons.mvp.BaseFragment
+import com.mogo.och.sweeper.R
+import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean
+import com.mogo.och.sweeper.callback.ISweeperTaskDataToFragmentCallback
+import com.mogo.och.sweeper.callback.IWeltMapSwitchToSmallCallback
+import com.mogo.och.sweeper.database.bean.WeltDataBean
+import kotlinx.android.synthetic.main.fragment_welt_map_overview.*
+import kotlinx.android.synthetic.main.sweeper_welt_map_overview.*
+
+/**
+ * 作业任务全览图
+ */
+class WeltMapOverViewFragment() : BaseFragment(), ISweeperTaskDataToFragmentCallback {
+ private var mIWeltMapSwitchToSmallCallBack: IWeltMapSwitchToSmallCallback? = null
+ private var mFragment: SweeperFragment? = null
+ override fun getLayoutId(): Int = R.layout.fragment_welt_map_overview
+ override fun getTagName(): String {
+ return "WeltMapOverViewFragment"
+ }
+
+ override fun initViews() {
+
+ }
+ fun setWeltMapSwitchToSmallCallBack(iWeltMapSwitchToSmallCallback: IWeltMapSwitchToSmallCallback){
+ this.mIWeltMapSwitchToSmallCallBack=iWeltMapSwitchToSmallCallback
+ }
+ fun setSweeperFragment(fragment: SweeperFragment){
+ this.mFragment=fragment
+ mFragment?.setTaskDataToFragmentCallback(this)
+ }
+ override fun initViews(savedInstanceState: Bundle?) {
+ super.initViews(savedInstanceState)
+ weltMapOverView?.onCreateView(savedInstanceState)
+ sweeperSwitchToSmall.setOnClickListener {
+ mIWeltMapSwitchToSmallCallBack?.onWeltMapSwitchToSmall()
+ }
+ val bundle = arguments
+ if (bundle != null) {
+ val latLngs = bundle.getSerializable("subTaskCoordinates") as? ArrayList
+ val latLng = bundle.getParcelable("subTaskEndCoordinates")
+ val weltDataList = bundle.getSerializable("weltDataList") as? ArrayList
+ val routeList = bundle.getSerializable("routeList") as? ArrayList
+ val progress = bundle.getString("progress")
+ routeList?.let {
+ weltMapOverView?.setRouteList(it)
+ }
+ latLng?.let {
+ setCurrentTaskCoordinatesLatLng(it)
+ }
+ latLngs?.let {
+ setTaskListCoordinatesLatLng(it)
+ }
+ weltDataList?.let {
+ setWeltData(it,"0.0cm")
+ }
+ progress?.let {
+ weltMapOverView?.setProgress(progress)
+ }
+ }
+
+ }
+
+ companion object {
+ @JvmStatic
+ fun newInstance(
+ mIWeltMapSwitchToSmallCallBack: IWeltMapSwitchToSmallCallback,
+ mCurrentTaskEndStation:LatLng?,
+ weltDataList: ArrayList?,
+ latLngs: ArrayList?,
+ routeList: ArrayList?,
+ progress:String?,
+ sweeperFragment: SweeperFragment
+ ): WeltMapOverViewFragment {
+ val args = Bundle()
+ args.putSerializable("weltDataList", weltDataList)
+ args.putSerializable("subTaskCoordinates", latLngs)
+ args.putParcelable("subTaskEndCoordinates", mCurrentTaskEndStation)
+ args.putSerializable("routeList", routeList)
+ args.putString("progress", progress)
+ val fragment = WeltMapOverViewFragment()
+ fragment.setWeltMapSwitchToSmallCallBack(mIWeltMapSwitchToSmallCallBack)
+ fragment.setSweeperFragment(sweeperFragment)
+ fragment.arguments = args
+ return fragment
+ }
+ }
+
+ override fun onPause() {
+ super.onPause()
+ weltMapOverView?.onPause()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ weltMapOverView?.onResume()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ weltMapOverView?.onDestroy()
+ }
+ override fun setTaskListCoordinatesLatLng(coordinatesLatLng: java.util.ArrayList) {
+ weltMapOverView?.setTaskListCoordinatesLatLng(coordinatesLatLng)
+ }
+
+ override fun setCurrentTaskCoordinatesLatLng(coordinatesLatLng: LatLng) {
+ weltMapOverView?.setCurrentTaskCoordinatesLatLng(coordinatesLatLng)
+ }
+
+ override fun clearAllMarkerAndPolyline() {
+ weltMapOverView?.clearAllMarkerAndPolyline()
+ }
+
+ override fun setProgress(progress: String) {
+ weltMapOverView?.setProgress(progress)
+ }
+
+ override fun setRouteList(routeList: java.util.ArrayList) {
+ weltMapOverView?.setRouteList(routeList)
+ }
+
+ override fun setWeltData(weltDatas: java.util.ArrayList?, distance: String) {
+ weltMapOverView?.setWeltData(weltDatas,true,distance)
+ }
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/model/SweeperTaskModel.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/model/SweeperTaskModel.java
new file mode 100644
index 0000000000..3022c92a28
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/model/SweeperTaskModel.java
@@ -0,0 +1,891 @@
+package com.mogo.och.sweeper.model;
+
+import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_SWEEPER;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.amap.api.maps.model.LatLng;
+import com.elegant.network.utils.GsonUtil;
+import com.mogo.aicloud.services.socket.IMogoOnMessageListener;
+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.AutopilotControlParameters;
+import com.mogo.eagle.core.data.config.FunctionBuildConfig;
+import com.mogo.eagle.core.data.map.MogoLocation;
+import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener;
+import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener;
+import com.mogo.eagle.core.function.api.autopilot.IMoGoPlanningRottingListener;
+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.utilcode.mogo.logger.CallerLogger;
+import com.mogo.eagle.core.utilcode.util.CoordinateUtils;
+import com.mogo.eagle.core.utilcode.util.NetworkUtils;
+import com.mogo.eagle.core.utilcode.util.ToastUtils;
+import com.mogo.och.common.module.biz.common.socketmessage.OCHSocketMessageManager;
+import com.mogo.och.common.module.biz.common.socketmessage.data.OCHOperationalMessage;
+import com.mogo.och.common.module.biz.network.OchCommonServiceCallback;
+import com.mogo.och.common.module.callback.OchAdasStartFailureCallback;
+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.common.module.utils.PinYinUtil;
+import com.mogo.och.common.module.utils.ToastUtilsOch;
+import com.mogo.och.common.module.voice.VoiceNotice;
+import com.mogo.och.sweeper.R;
+import com.mogo.och.sweeper.bean.BaseResponse;
+import com.mogo.och.sweeper.bean.SubInfo;
+import com.mogo.och.sweeper.bean.SweeperMainTaskBean;
+import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean;
+import com.mogo.och.sweeper.bean.SweeperSubTaskBean;
+import com.mogo.och.sweeper.bean.SweeperSubTaskDetailBean;
+import com.mogo.och.sweeper.callback.ISweeperADASStatusCallback;
+import com.mogo.och.sweeper.callback.ISweeperControllerStatusCallback;
+import com.mogo.och.sweeper.callback.ISweeperTaskCallback;
+import com.mogo.och.sweeper.constant.SubTaskTypeEnum;
+import com.mogo.och.sweeper.constant.SweeperConst;
+import com.mogo.och.sweeper.constant.TaskStatusEnum;
+import com.mogo.och.sweeper.net.SweeperServiceManager;
+import com.mogo.och.sweeper.util.SweeperAnalyticsManager;
+import com.mogo.och.sweeper.util.SweeperTrajectoryManager;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import io.reactivex.exceptions.UndeliverableException;
+import io.reactivex.functions.Consumer;
+import io.reactivex.plugins.RxJavaPlugins;
+import mogo.telematics.pad.MessagePad;
+
+/**
+ * @author congtaowang
+ * @since 2021/3/23
+ *
+ * 清扫车任务管理
+ */
+public class SweeperTaskModel {
+ private final String TAG = SweeperTaskModel.class.getSimpleName();
+ private static volatile SweeperTaskModel sInstance;
+ public double mLongitude = 0;
+ public double mLatitude = 0;
+ private Context mContext;
+ // 运营类型
+ private static final int VEHICLE_TYPE = 10;
+ private ISweeperControllerStatusCallback mControllerStatusCallback; //Model->Presenter:VR mode等
+ private ISweeperADASStatusCallback mADASStatusCallback;
+ private ISweeperTaskCallback mSweeperTaskCallback;
+ ArrayList points = new ArrayList<>();//全路径信息
+ //当前子任务详情信息包括轨迹文件信息
+ private SweeperSubTaskDetailBean mCurrentSubTaskDetail;
+ //子任务是否正在进行中
+ private boolean mIsSubTaskWorking = false;
+ //自动驾驶是否到达子任务终点
+ private boolean isAutopilotSubTaskArriveEndSite = false;
+ //当前子任务id
+ private int mSubTaskId = 0;
+ //当前是否最后一个子任务
+ private boolean mIsLastSubtask = false;
+ //当前任务是否是第一个
+ private boolean mIsFirstSubtask = false;
+ //当前任务是否是第一个
+ private int mSubTaskType = 0; //1自动驾驶 2.人工驾驶
+ //0: 代表没有启动过 1代表是启动第一次,当>=1 代表是重试 每次子任务结束/主任务结束清空置为0
+ private volatile int firstStartAutopilot = 0;
+ private int mLineId;//路线id
+ //自动驾驶状态
+ private int mAutopilotState = IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE;
+
+ 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);
+
+ //开启自驾后 异常信息返回
+ OCHAdasAbilityManager.getInstance().setAdasStartFailureCallback(mAdasStartFailureListener);
+
+ OCHSocketMessageManager.INSTANCE.registerSocketMessageListener(
+ OCHSocketMessageManager.msgMonitorType,
+ mMogoOnMessageListener);
+
+ //2022.1.28
+ // 调用Disposable.dispose() 时候会出现InterruptedException 导致出现崩溃
+ // The exception could not be delivered to the consumer because it has already canceled/disposed
+ // the flow or the excTeption has nowhere to go to begin with
+ RxJavaPlugins.setErrorHandler(new Consumer() {
+ @Override
+ public void accept(Throwable e) {
+ if (e instanceof UndeliverableException) {
+ e = e.getCause();
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "UndeliverableException");
+ }
+ if ((e instanceof IOException)) {//
+ // fine, irrelevant network problem or API that throws on cancellation
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "IOException");
+ return;
+ }
+ if (e instanceof InterruptedException) {
+ // fine, some blocking code was interrupted by a dispose call
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "InterruptedException");
+ return;
+ }
+ if ((e instanceof NullPointerException) || (e instanceof IllegalArgumentException)) {
+ // that's likely a bug in the application
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "NullPointerException or IllegalArgumentException");
+ Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
+ return;
+ }
+ if (e instanceof IllegalStateException) {
+ // that's a bug in RxJava or in a custom operator
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "IllegalStateException");
+ Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
+ return;
+ }
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "Undeliverable exception");
+ }
+ });
+ }
+
+ public void setAdasStatusCallback(ISweeperADASStatusCallback callback) {
+ this.mADASStatusCallback = callback;
+ }
+
+ public void setControllerStatusCallback(ISweeperControllerStatusCallback callback) {
+ this.mControllerStatusCallback = callback;
+ }
+
+ public void setSweeperTaskCallback(ISweeperTaskCallback 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) {
+ if (mCurrentSubTaskDetail.getLineId() != mLineId) {//判断是否同一条路线
+ mLineId = mCurrentSubTaskDetail.getLineId();
+ points.addAll(coordinateConverterWgsToGcjList(mContext, routeList.getWayPointsList()));
+ if (mSweeperTaskCallback != null) {
+ mSweeperTaskCallback.setRouteList(points);
+ }
+ }
+ }
+ }
+
+ };
+
+ public void setSubtask(boolean isFirstSubtask, boolean isLastSubtask, int subTaskId, int subTaskType) {
+ this.mIsLastSubtask = isLastSubtask;
+ this.mIsFirstSubtask = isFirstSubtask;
+ this.mSubTaskId = subTaskId;
+ this.mSubTaskType = subTaskType;
+ }
+
+ /**
+ * 清除路线缓存数据
+ */
+ public void clearRouteList() {
+ points.clear();
+ mSubTaskType=0;
+ }
+
+ /**
+ * 保存自动驾驶状态
+ *
+ * @param autopilotState
+ */
+ public void setAutopilotState(int autopilotState) {
+ this.mAutopilotState = autopilotState;
+ }
+
+ public static List coordinateConverterWgsToGcjList(Context mContext,
+ List mogoLatLngList) {
+ List points = new ArrayList<>();
+ for (MessagePad.Location m : mogoLatLngList) {
+ LatLng mogoLatLng = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj(mContext, m);
+ SweeperRoutePlanningUpdateReqBean.Result result = new SweeperRoutePlanningUpdateReqBean.Result();
+ result.latitude = mogoLatLng.latitude;
+ result.longitude = mogoLatLng.longitude;
+ points.add(result);
+ }
+ return points;
+ }
+
+ public void release() {
+ MogoStatusManager.getInstance().unregisterStatusChangedListener(TAG, StatusDescriptor.VR_MODE, mMogoStatusChangedListener);
+ // 注销定位监听
+ CallerChassisLocationGCJ02ListenerManager.INSTANCE.removeListener(TAG);
+ //自动驾驶路线规划接口
+ CallerPlanningRottingListenerManager.INSTANCE.removeListener(moGoAutopilotPlanningListener);
+ OCHAdasAbilityManager.getInstance().setAdasStartFailureCallback(null);
+ }
+
+ private Object readResolve() {
+ // 阻止反序列化,必须实现 Serializable 接口
+ return sInstance;
+ }
+
+ private final IMogoOnMessageListener mMogoOnMessageListener =
+ new IMogoOnMessageListener() {
+ @Override
+ public Class target() {
+ return OCHOperationalMessage.class;
+ }
+
+ @Override
+ public void onMsgReceived(OCHOperationalMessage obj) {
+ if (obj == null) {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onMsgReceived = null");
+ return;
+ }
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onMsgReceived = " + obj.getMessage());
+ OCHSocketMessageManager.INSTANCE.pushAppOperationalMsgBox(obj.getPushTimeStamp(),
+ obj.getMessage(),OCHSocketMessageManager.OPERATION_SYSTEM);
+ }
+ };
+
+ 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 OchAdasStartFailureCallback mAdasStartFailureListener = new OchAdasStartFailureCallback() {
+ @Override
+ public void onStartAutopilotFailure(@NotNull String startFailedCode, @NonNull String startFailedMessage) {
+ SweeperAnalyticsManager.getInstance().triggerStartAutopilotFailureEventByAdas(startFailedCode, startFailedMessage);
+ if (mADASStatusCallback != null && !FunctionBuildConfig.isDemoMode) {
+ CallerLogger.INSTANCE.e(M_SWEEPER + TAG, "mAdasStartFailureListener = " + startFailedMessage);
+ mADASStatusCallback.onStartAdasFailure();
+ }
+ }
+ };
+
+ // 自车定位
+ private final IMoGoChassisLocationGCJ02Listener mMapLocationListener = new IMoGoChassisLocationGCJ02Listener() {
+ @Override
+ public void onChassisLocationGCJ02(@Nullable MogoLocation gnssInfo) {
+ if (null == gnssInfo) return;
+ CallerLogger.INSTANCE.e(M_SWEEPER + TAG, "高德定位到站:mLongitude = " + gnssInfo.getLongitude()
+ + ", mLatitude=" + gnssInfo.getLatitude() + ", mSubTaskType=" + mSubTaskType +", mIsSubTaskWorking=" + mIsSubTaskWorking
+ + ", isAutopilotSubTaskArriveEndSite=" + isAutopilotSubTaskArriveEndSite
+ );
+ if (mControllerStatusCallback != null) {
+ mControllerStatusCallback.onCarLocationChanged(gnssInfo);
+ }
+ if (SubTaskTypeEnum.MANUAL_DRIVING_SUBTYPE.getCode() == mSubTaskType) {//人工驾驶子任务需要手动跳过,不能自动结束
+ addCoordinates(gnssInfo);
+ return;
+ }
+ //子任务完成的围栏判断 子任务正在执行中,还未到达子任务终点
+ if (mIsSubTaskWorking && !isAutopilotSubTaskArriveEndSite) {
+ judgeArrivedStation(gnssInfo);
+ }
+ }
+ };
+
+ /**
+ * 根据当前定位收集人工驾驶子任务轨迹点
+ *
+ * @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);
+ }
+ }
+ }
+
+ //根据围栏判断,是否到达子任务终点
+ private void judgeArrivedStation(MogoLocation location) {
+ if (mCurrentSubTaskDetail == null) {
+ CallerLogger.INSTANCE.d(TAG, "行程日志-judgeArrivedStation() mCurrentSubTaskDetail is null");
+ return;
+ }
+ double endSiteLon = mCurrentSubTaskDetail.getEndSiteLon();
+ double endSiteLat = mCurrentSubTaskDetail.getEndSiteLat();
+ double distance = CoordinateUtils.calculateLineDistance(
+ endSiteLon, endSiteLat,
+ location.getLongitude(), location.getLatitude());
+ if (distance <= SweeperConst.ARRIVE_AT_END_STATION_DISTANCE) {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "行程日志-judgeArrivedStation() distance = " + distance
+ + " to " + mCurrentSubTaskDetail.getEndSiteName());
+ isAutopilotSubTaskArriveEndSite = true;
+ //到达子任务终点 结束子任务
+ subTaskEnd(mIsFirstSubtask, mIsLastSubtask, mSubTaskId); //无自动驾驶到终点信息传null
+ return;
+ }
+ }
+
+ /**
+ * 在踩刹车、控制方向盘等操作后,会停止自动驾驶,重启自动驾驶的话相当于重新设置自动驾驶目的地
+ */
+ public void startAutopilot() {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "行程日志-重启自动驾驶===" + mIsSubTaskWorking);
+ //只去启动自动驾驶
+ startAutopilot(firstStartAutopilot >= 1);
+ }
+
+ /**
+ * 开启自动驾驶
+ *
+ * @param isRestart
+ */
+ private void startAutopilot(boolean isRestart) {
+ if (!FunctionBuildConfig.isDemoMode && !OCHAdasAbilityManager.getInstance().getAutopilotAbilityStatus()) {
+ ToastUtils.showLong(OCHAdasAbilityManager.getInstance().getAutopilotUnAbilityReason() +
+ ", 请稍候重试");
+ triggerUnableStartAPReasonEvent();
+ return;
+ }
+ firstStartAutopilot++;
+ triggerStartServiceEvent(isRestart, false);
+ AutopilotControlParameters parameters = initAutopilotControlParameters();
+ if (null == parameters) {
+ CallerLogger.INSTANCE.e(M_SWEEPER + TAG, "行程日志-AutopilotControlParameters is empty.");
+ return;
+ }
+ CallerAutoPilotControlManager.INSTANCE.startAutoPilot(parameters);
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "行程日志-开启自动驾驶====" + GsonUtil.jsonFromObject(parameters)
+ + " startLatLon=" + parameters.startName + ",endLatLon=" + parameters.endName +
+ "isRestart = " + isRestart);
+
+ if (mControllerStatusCallback != null) {
+ mControllerStatusCallback.startOpenAutopilot();
+ }
+ }
+
+ /**
+ * 获取任务子任务执行状态
+ */
+ public boolean getSubWorking() {
+ return mIsSubTaskWorking;
+ }
+
+ public void setWorking(Boolean isWorking) {
+ this.mIsSubTaskWorking = isWorking;
+ }
+
+ /**
+ * 关闭美化模式
+ */
+ public void closeBeautificationMode() {
+ if (FunctionBuildConfig.isDemoMode) {
+ FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData = false; //是否强制绘制引导线
+ CallerAutoPilotControlManager.INSTANCE.setIPCDemoMode(false);//是否自动启动自驾
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "美化模式-ignore:置为false");
+ }
+ }
+
+ /**
+ * 开启美化模式
+ */
+ public void startBeautificationMode() {
+ FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData = true;//是否强制绘制引导线
+ CallerAutoPilotControlManager.INSTANCE.setIPCDemoMode(true);//是否自动启动自驾
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "美化模式-ignore:置为true");
+ }
+
+ /**
+ * @param data
+ */
+ public void onArriveTaskEnd(MessagePad.ArrivalNotification data) {
+ //MAP 280 每隔100ms左右返回一次到站, 导致在到达中间站后再次滑动出发后会有时间差,收到一次到站,出现问题
+ //此处比对 自驾告诉的子任务终点坐标和本地应到子任务终点坐标, 一致时才表示子任务完成
+ if (data != null && data.getEndLocation() != null && mCurrentSubTaskDetail != null) {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "MAP到站通知:" + mCurrentSubTaskDetail.getEndSiteName() + " 经度:"
+ + data.getEndLocation().getLongitude() + " 纬度:" + data.getEndLocation().getLatitude());
+ String latitude = NumberFormatUtil.cutOutNumber(data.getEndLocation().getLatitude(), 5); //wgs
+ String longitude = NumberFormatUtil.cutOutNumber(data.getEndLocation().getLongitude(), 5);
+ String arriveLat = NumberFormatUtil.cutOutNumber(mCurrentSubTaskDetail.getEndSiteWgs64Lat(), 5);
+ String arriveLon = NumberFormatUtil.cutOutNumber(mCurrentSubTaskDetail.getEndSiteWgs64Lon(), 5);
+ if (!latitude.equals(arriveLat) || !longitude.equals(arriveLon)) {
+ CallerLogger.INSTANCE.e(M_SWEEPER + TAG, "行程日志-子任务终点拦截,自动子任务终点与本地子任务终点不一致");
+ return;
+ }
+ }
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "MAP到站通知:mSubTaskType=" + mSubTaskType + " isAutopilotSubTaskArriveEndSite="
+ + isAutopilotSubTaskArriveEndSite + " mSubTaskId=" + mSubTaskId);
+ if (SubTaskTypeEnum.MANUAL_DRIVING_SUBTYPE.getCode() == mSubTaskType) {//人工驾驶子任务需要手动跳过,不能自动结束
+ return;
+ }
+ if (isAutopilotSubTaskArriveEndSite) {
+ return;
+ }
+ isAutopilotSubTaskArriveEndSite = true;
+ //到达子任务终点 结束子任务
+ subTaskEnd(mIsFirstSubtask, mIsLastSubtask, mSubTaskId);
+ }
+
+ public void triggerStartServiceEvent(boolean isRestart, boolean send) {
+ if (mCurrentSubTaskDetail == null) {
+ return;
+ }
+ SweeperAnalyticsManager.getInstance().triggerStartAutopilotEvent(isRestart, send,
+ mCurrentSubTaskDetail.getStartSiteName(), mCurrentSubTaskDetail.getEndSiteName(), mCurrentSubTaskDetail.getLineId());
+ }
+
+ public boolean isRestartAutopilot() {
+ return firstStartAutopilot > 1;
+ }
+
+ public void triggerUnableStartAPReasonEvent() {
+ if (mCurrentSubTaskDetail == null) {
+ return;
+ }
+ SweeperAnalyticsManager.getInstance().triggerUnableStartAPReasonEvent(
+ mCurrentSubTaskDetail.getStartSiteName(), mCurrentSubTaskDetail.getEndSiteName(), mCurrentSubTaskDetail.getLineId(),
+ OCHAdasAbilityManager.getInstance().getAutopilotUnAbilityReason());
+ }
+
+ /**
+ * 将轨迹文件信息同步到鹰眼
+ */
+ private void updateAutopilotControlParameters() {
+
+ AutopilotControlParameters parameters = initAutopilotControlParameters();
+ if (null == parameters) {
+ CallerLogger.INSTANCE.e(M_SWEEPER + TAG, "AutopilotControlParameters is empty.");
+ return;
+ }
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "AutopilotControlParameters" + GsonUtil.jsonFromObject(parameters));
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "AutopilotControlParameters is update.");
+ CallerAutoPilotStatusListenerManager.INSTANCE.updateAutopilotControlParameters(parameters);
+ }
+
+ private void clearAutopilotControlParameters() {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "AutopilotControlParameters is clear.");
+ CallerAutoPilotStatusListenerManager.INSTANCE.updateAutopilotControlParameters(null);
+ }
+
+ private AutopilotControlParameters initAutopilotControlParameters() {
+ AutopilotControlParameters parameters = new AutopilotControlParameters();
+ if (mCurrentSubTaskDetail != null) {
+ parameters.routeID = mCurrentSubTaskDetail.getLineId();
+ parameters.routeName = mCurrentSubTaskDetail.getLineName();
+ parameters.startName = PinYinUtil.getPinYinHeadChar(mCurrentSubTaskDetail.getStartSiteName());
+ parameters.endName = PinYinUtil.getPinYinHeadChar(mCurrentSubTaskDetail.getEndSiteName());
+ parameters.startLatLon = new AutopilotControlParameters
+ .AutoPilotLonLat(mCurrentSubTaskDetail.getStartSiteWgs64Lat(), mCurrentSubTaskDetail.getStartSiteWgs64Lon());
+ parameters.endLatLon = new AutopilotControlParameters
+ .AutoPilotLonLat(mCurrentSubTaskDetail.getEndSiteWgs64Lat(), mCurrentSubTaskDetail.getEndSiteWgs64Lon());
+ parameters.vehicleType = VEHICLE_TYPE;
+ parameters.autoPilotLine = new AutopilotControlParameters.AutoPilotLine(
+ mCurrentSubTaskDetail.getLineId(),
+ mCurrentSubTaskDetail.getCsvFileUrl(), mCurrentSubTaskDetail.getCsvFileMd5(),
+ mCurrentSubTaskDetail.getTxtFileUrl(), mCurrentSubTaskDetail.getTxtFileMd5(),
+ mCurrentSubTaskDetail.getPublishTime(), mCurrentSubTaskDetail.getCarModel(),
+ mCurrentSubTaskDetail.getCsvFileUrlDPQP(), mCurrentSubTaskDetail.getCsvFileMd5DPQP(),
+ mCurrentSubTaskDetail.getTxtFileUrlDPQP(), mCurrentSubTaskDetail.getTxtFileMd5DPQP(),
+ mCurrentSubTaskDetail.getPublishTimeDPQP());
+ }
+ return parameters;
+ }
+
+ /**
+ * 获取当前正在执行的任务
+ */
+ public void getCurrentTask() {
+ SweeperServiceManager.getCurrentTask(mContext, new OchCommonServiceCallback>() {
+ @Override
+ public void onSuccess(BaseResponse data) {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "getCurrentTask:" + GsonUtil.jsonFromObject(data));
+ if (mSweeperTaskCallback != null && data != null) {
+ SweeperSubTaskBean sweeperSubTaskBean = data.getData();
+ if (sweeperSubTaskBean != null && sweeperSubTaskBean.getSubList() != null && sweeperSubTaskBean.getSubList().size() > 0) {
+ mSweeperTaskCallback.setSubTaskBean(sweeperSubTaskBean, true);
+ } else {
+ getMainTaskList(false);
+ }
+ }
+ }
+
+ @Override
+ public void onError() {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort(mContext.getString(R.string.network_error_tip));
+ } else {
+ ToastUtils.showShort(mContext.getString(R.string.request_error_tip));
+ }
+ }
+
+ @Override
+ public void onFail(int code, String msg) {
+ if (ToastUtilsOch.isCustomFastClick(5000)) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ } else {
+ ToastUtils.showShort(msg);
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * 获取主任务列表
+ */
+ public void getMainTaskList(boolean refresh) {
+ SweeperServiceManager.getMainTaskList(mContext, new OchCommonServiceCallback>>() {
+ @Override
+ public void onSuccess(BaseResponse> data) {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "getMainTaskList:" + GsonUtil.jsonFromObject(data));
+ if (mSweeperTaskCallback != null && data != null && data.getCode() == 0) {
+ List list = data.getData();
+ mSweeperTaskCallback.setMainTaskList(list, refresh);
+ }
+ }
+
+ @Override
+ public void onFail(int code, String msg) {
+ if (ToastUtilsOch.isCustomFastClick(5000)) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ } else {
+ ToastUtils.showShort(msg);
+ }
+ }
+ }
+
+ @Override
+ public void onError() {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort(mContext.getString(R.string.network_error_tip));
+ } else {
+ ToastUtils.showShort(mContext.getString(R.string.request_error_tip));
+ }
+ }
+ });
+ }
+
+ /**
+ * 获取子任务列表
+ */
+ public void getSubTaskList(int taskId, SweeperSubTaskBean sweeperSubTaskBean) {
+ SweeperServiceManager.getSubTaskList(taskId, mContext, new OchCommonServiceCallback>>() {
+ @Override
+ public void onSuccess(BaseResponse> data) {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "getSubTaskList:" + GsonUtil.jsonFromObject(data));
+ if (mSweeperTaskCallback != null && data != null && data.getCode() == 0) {
+ List list = data.getData();
+ if (list != null && list.size() > 0) {
+ sweeperSubTaskBean.setSubList(list);
+ mSweeperTaskCallback.setSubTaskBean(sweeperSubTaskBean, false);
+ } else {
+ getMainTaskList(false);
+ }
+ }
+ }
+
+ @Override
+ public void onFail(int code, String msg) {
+ if (ToastUtilsOch.isCustomFastClick(5000)) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ } else {
+ ToastUtils.showShort(msg);
+ }
+ }
+ }
+
+ @Override
+ public void onError() {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort(mContext.getString(R.string.network_error_tip));
+ } else {
+ ToastUtils.showShort(mContext.getString(R.string.request_error_tip));
+ }
+ }
+ });
+ }
+
+ /**
+ * 获取子任务详情包括轨迹文件信息
+ */
+ public void getSubTaskDetail(boolean isFirst, boolean isEnd, int subTaskId, SubTaskTypeEnum subTaskType, boolean isStartSubtask) {
+ SweeperServiceManager.getSubTaskDetail(subTaskId, mContext, new OchCommonServiceCallback>() {
+ @Override
+ public void onSuccess(BaseResponse data) {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "getSubTaskDetail:" + GsonUtil.jsonFromObject(data));
+ if (data != null) {
+ mCurrentSubTaskDetail = data.getData();
+ if (mCurrentSubTaskDetail != null) {
+ mSweeperTaskCallback.setSubTakDetail(mCurrentSubTaskDetail, subTaskType);
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "getSubTaskDetail:subTaskType=" + subTaskType
+ + ", isStartSubtask=" + isStartSubtask + ", mAutopilotState=" + mAutopilotState);
+ Log.d(M_SWEEPER + TAG, "getSubTaskDetail:subTaskType=" + subTaskType
+ + ", isStartSubtask=" + isStartSubtask + ", mAutopilotState=" + mAutopilotState);
+ if (subTaskType == SubTaskTypeEnum.AUTOPILOT_SUBTYPE) {//自动驾驶子任务
+ //向自动驾驶发送要下载文件轨迹路径
+ SweeperTrajectoryManager.getInstance().syncTrajectoryInfo(mCurrentSubTaskDetail);
+ updateAutopilotControlParameters();
+ // 不在启动驾驶状态也需要先开启子任务
+ if (isStartSubtask) {//是否需要自动开始执行任务
+ subTaskStart(isFirst, isEnd, subTaskId, subTaskType);
+ if (mAutopilotState == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) {
+ cancelAutoPilot();
+ startAutopilot();
+
+ //提示必须是N档,且拉起手刹 才能进入自动驾驶
+ VoiceNotice.showNotice(mContext.getString(R.string.sweeper_arrive_auto_start_next_subtask_tips));
+ ToastUtils.showLong(mContext.getString(R.string.sweeper_arrive_auto_start_next_subtask_tips));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onFail(int code, String msg) {
+ if (ToastUtilsOch.isCustomFastClick(5000)) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ } else {
+ ToastUtils.showShort(msg);
+ }
+ }
+ }
+
+ @Override
+ public void onError() {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort(mContext.getString(R.string.network_error_tip));
+ } else {
+ ToastUtils.showShort(mContext.getString(R.string.request_error_tip));
+ }
+ }
+ });
+ }
+
+ /**
+ * 子任务开始上报
+ */
+ public void subTaskStart(boolean isFirst, boolean isEnd, int subTaskId, SubTaskTypeEnum subTaskType) {
+ SweeperServiceManager.subTaskStart(isFirst, isEnd, subTaskId, mContext, new OchCommonServiceCallback>() {
+ @Override
+ public void onSuccess(BaseResponse data) {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "subTaskStart:" + GsonUtil.jsonFromObject(data));
+ if (mSweeperTaskCallback != null && data != null) {
+ if (data.getData()) {
+ mIsSubTaskWorking = true;
+ isAutopilotSubTaskArriveEndSite = false;
+ mSweeperTaskCallback.updateSubTaskStatus(TaskStatusEnum.START_SUBTASK, false);
+ if (subTaskType == SubTaskTypeEnum.AUTOPILOT_SUBTYPE) {//如果是自动驾驶子任务子开启自驾
+ if (FunctionBuildConfig.isDemoMode) {//美化模式开启时
+ SweeperTaskModel.getInstance().startBeautificationMode();
+ }
+ //ÏstartAutopilot(false);
+ } else {
+ if (FunctionBuildConfig.isDemoMode) {//美化模式开启时
+ FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData = true;//是否强制绘制引导线
+ CallerAutoPilotControlManager.INSTANCE.setIPCDemoMode(false);//是否自动启动自驾
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onFail(int code, String msg) {
+ if (ToastUtilsOch.isCustomFastClick(5000)) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ } else {
+ ToastUtils.showShort(msg);
+ }
+ }
+ }
+
+ @Override
+ public void onError() {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort(mContext.getString(R.string.network_error_tip));
+ } else {
+ ToastUtils.showShort(mContext.getString(R.string.request_error_tip));
+ }
+ }
+ });
+ }
+
+ /**
+ * 子任务结束上报
+ */
+ public void subTaskEnd(boolean isFirst, boolean isEnd, int subTaskId) {
+ SweeperServiceManager.subTaskEnd(isFirst, isEnd, subTaskId, mContext, new OchCommonServiceCallback>() {
+ @Override
+ public void onSuccess(BaseResponse data) {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "subTaskEnd:" +
+ String.format("isFirst=%b; isEnd=%b; ", isFirst, isEnd) + GsonUtil.jsonFromObject(data));
+ if (data != null) {
+ if (data.getData()) {
+ mIsSubTaskWorking = false;
+ if (mSweeperTaskCallback != null) {
+ mSweeperTaskCallback.updateSubTaskStatus(TaskStatusEnum.END_SUBTASK, isEnd);
+ }
+ if (isEnd) {
+ if (FunctionBuildConfig.isDemoMode) {//美化模式开启时
+ SweeperTaskModel.getInstance().closeBeautificationMode();
+ }
+ clearAutopilotControlParameters();
+ //结束自动驾驶
+ cancelAutoPilot();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onFail(int code, String msg) {
+ if (ToastUtilsOch.isCustomFastClick(5000)) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ } else {
+ if (isAutopilotSubTaskArriveEndSite) return;
+ ToastUtils.showShort(msg);
+ }
+ }
+ }
+
+ @Override
+ public void onError() {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort(mContext.getString(R.string.network_error_tip));
+ } else {
+ ToastUtils.showShort(mContext.getString(R.string.request_error_tip));
+ }
+
+ }
+ });
+ }
+
+ /**
+ * 子任务跳过上报
+ */
+ public void subTaskSkip(boolean isFirst, boolean isEnd, int subTaskId) {
+ SweeperServiceManager.subTaskSkip(isFirst, isEnd, subTaskId, mContext, new OchCommonServiceCallback>() {
+ @Override
+ public void onSuccess(BaseResponse data) {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "subTaskSkip:" +
+ String.format("isFirst=%b; isEnd=%b; ", isFirst, isEnd)+ GsonUtil.jsonFromObject(data));
+ if (mSweeperTaskCallback != null && data != null) {
+ if (data.getData()) {
+ mIsSubTaskWorking = false;
+ // 跳过子任务也相当于开始并结束一个子任务,相关变量状态需要重置
+ isAutopilotSubTaskArriveEndSite = false;
+ mSweeperTaskCallback.updateSubTaskStatus(TaskStatusEnum.JUMP_OVER_SUBTASK, isEnd);
+ }
+ }
+ }
+
+ @Override
+ public void onFail(int code, String msg) {
+ if (ToastUtilsOch.isCustomFastClick(5000)) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ } else {
+ ToastUtils.showShort(msg);
+ }
+ }
+ }
+
+ @Override
+ public void onError() {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort(mContext.getString(R.string.network_error_tip));
+ } else {
+ ToastUtils.showShort(mContext.getString(R.string.request_error_tip));
+ }
+ }
+ });
+ }
+
+ /**
+ * 主任务重置
+ */
+ public void mainTaskReset(int taskId) {
+ SweeperServiceManager.mainTaskReset(taskId, mContext, new OchCommonServiceCallback>() {
+ @Override
+ public void onSuccess(BaseResponse data) {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "mainTaskReset:" + GsonUtil.jsonFromObject(data));
+ // 主任务重置 当前子任务也需重置
+ mIsSubTaskWorking = false;
+ isAutopilotSubTaskArriveEndSite = false;
+ if (mSweeperTaskCallback != null && data != null) {
+ mSweeperTaskCallback.setMainTaskReset(data.getData());
+ }
+ }
+
+ @Override
+ public void onFail(int code, String msg) {
+ if (ToastUtilsOch.isCustomFastClick(5000)) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ } else {
+ ToastUtils.showShort(msg);
+ }
+ }
+ }
+
+ @Override
+ public void onError() {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort(mContext.getString(R.string.network_error_tip));
+ } else {
+ ToastUtils.showShort(mContext.getString(R.string.request_error_tip));
+ }
+ }
+ });
+ }
+
+ //结束自动驾驶
+ public void cancelAutoPilot() {
+ CallerAutoPilotControlManager.INSTANCE.cancelAutoPilot();
+ }
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/net/ISweeperApiService.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/net/ISweeperApiService.java
new file mode 100644
index 0000000000..5522f00dae
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/net/ISweeperApiService.java
@@ -0,0 +1,103 @@
+package com.mogo.och.sweeper.net;
+import com.mogo.och.sweeper.bean.BaseResponse;
+import com.mogo.och.sweeper.bean.SubInfo;
+import com.mogo.och.sweeper.bean.SubStartRequest;
+import com.mogo.och.sweeper.bean.SweeperSubTaskBean;
+import com.mogo.och.sweeper.bean.SweeperMainTaskBean;
+import com.mogo.och.sweeper.bean.SweeperSubTaskDetailBean;
+
+import java.util.List;
+import java.util.Map;
+
+import io.reactivex.Observable;
+import retrofit2.http.Body;
+import retrofit2.http.GET;
+import retrofit2.http.Header;
+import retrofit2.http.Headers;
+import retrofit2.http.POST;
+import retrofit2.http.Query;
+import retrofit2.http.QueryMap;
+
+/**
+ * 清扫车相关接口
+ */
+public interface ISweeperApiService {
+ /**
+ * 获取当前正在执行的任务
+ * @param appId
+ * @param ticket
+ * @param carSn
+ * @return
+ */
+ @GET("/och-sweep/api/task/v1/currentTask")
+ Observable> getCurrentTask(@Header ("appId") String appId, @Header("ticket") String ticket, @Query("carSn") String carSn);
+ /**
+ * 清扫车任务列表
+ * @param appId
+ * @param ticket
+ * @param carSn
+ * @return
+ */
+ @GET("/och-sweep/api/task/v1/mainTaskList")
+ Observable>> getMainTaskList(@Header ("appId") String appId, @Header("ticket") String ticket, @Query("carSn") String carSn);
+ /**
+ * 清扫车子任务列表
+ * @param appId
+ * @param ticket
+ * @param map
+ * @return
+ */
+ @GET("/och-sweep/api/task/v1/subTaskList")
+ Observable>> getSubTaskList(@Header ("appId") String appId, @Header("ticket") String ticket, @QueryMap Map map);
+ /**
+ * 子任务详情 包括子任务轨迹信息
+ * @param appId
+ * @param ticket
+ * @param map
+ * @return
+ */
+ @GET("/och-sweep/api/task/v1/subTaskInfo")
+ Observable> getSubTaskDetail(@Header ("appId") String appId, @Header("ticket") String ticket, @QueryMap Map map);
+
+ /**
+ * 子任务开始
+ * @param appId
+ * @param ticket
+ * @param subStartRequest
+ * @return
+ */
+ @Headers({"Content-type:application/json;charset=UTF-8"})
+ @POST("/och-sweep/api/task/v1/subTaskStart")
+ Observable> subTaskStart(@Header ("appId") String appId, @Header("ticket") String ticket, @Body SubStartRequest subStartRequest);
+
+ /**
+ * 子任务结束
+ * @param appId
+ * @param ticket
+ * @param subStartRequest
+ * @return
+ */
+ @Headers({"Content-type:application/json;charset=UTF-8"})
+ @POST("/och-sweep/api/task/v1/subTaskEnd")
+ Observable> subTaskEnd(@Header ("appId") String appId, @Header("ticket") String ticket, @Body SubStartRequest subStartRequest);
+ /**
+ * 子任务跳过
+ * @param appId
+ * @param ticket
+ * @param subStartRequest
+ * @return
+ */
+ @Headers({"Content-type:application/json;charset=UTF-8"})
+ @POST("/och-sweep/api/task/v1/subTaskSkip")
+ Observable> subTaskSkip(@Header ("appId") String appId, @Header("ticket") String ticket, @Body SubStartRequest subStartRequest);
+
+ /**
+ * 主任务重置
+ * @param appId
+ * @param ticket
+ * @return
+ */
+ @GET("/och-sweep/api/task/v1/mainTaskReset")
+ Observable> mainTaskReset(@Header ("appId") String appId, @Header("ticket") String ticket,@QueryMap Map map);
+}
+
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/net/SweeperServiceManager.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/net/SweeperServiceManager.kt
new file mode 100644
index 0000000000..118807dbb7
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/net/SweeperServiceManager.kt
@@ -0,0 +1,173 @@
+package com.mogo.och.sweeper.net
+
+import android.content.Context
+import com.elegant.network.utils.GsonUtil
+import com.mogo.cloud.passport.MoGoAiCloudClientConfig
+import com.mogo.eagle.core.network.MoGoRetrofitFactory
+import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
+import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
+import com.mogo.och.common.module.biz.constant.OchCommonConst
+import com.mogo.och.common.module.biz.network.OchCommonServiceCallback
+import com.mogo.och.common.module.biz.network.OchCommonSubscribeImpl
+import com.mogo.och.common.module.biz.network.interceptor.transformTry
+import com.mogo.och.sweeper.bean.*
+import com.mogo.och.sweeper.model.SweeperTaskModel
+
+object SweeperServiceManager {
+ private val TAG = SweeperTaskModel::class.java.simpleName
+ private val mService: ISweeperApiService = MoGoRetrofitFactory.getInstance(OchCommonConst.getBaseUrl()).create(
+ ISweeperApiService::class.java
+ )
+
+ /**
+ * 获取当前正在执行的任务
+ */
+ @JvmStatic
+ fun getCurrentTask(context: Context, callback: OchCommonServiceCallback>?) {
+ val map = hashMapOf()
+ map["serviceAppId"] = getServiceAppId()
+ map["token"] = getToken()
+ map["sn"] = getCarSN()
+ d(SceneConstant.M_SWEEPER + TAG, "getCurrentTask:" + GsonUtil.jsonFromObject(map))
+ mService.getCurrentTask(
+ getServiceAppId(),
+ getToken(),
+ getCarSN()
+ )
+ .transformTry()
+ .subscribe(OchCommonSubscribeImpl(context, callback, "getCurrentTask"))
+ }
+
+ /**
+ * 获取主任务列表
+ */
+ @JvmStatic
+ fun getMainTaskList(context: Context, callback: OchCommonServiceCallback>>?) {
+ val map = hashMapOf()
+ map["serviceAppId"] = getServiceAppId()
+ map["token"] = getToken()
+ map["sn"] = getCarSN()
+ d(SceneConstant.M_SWEEPER + TAG, "getMainTaskList:" + GsonUtil.jsonFromObject(map))
+ mService.getMainTaskList(
+ getServiceAppId(),
+ getToken(),
+ getCarSN()
+ )
+ .transformTry()
+ .subscribe(OchCommonSubscribeImpl(context, callback, "getMainTaskList"))
+ }
+
+ /**
+ * 获取子任务列表
+ */
+ @JvmStatic
+ fun getSubTaskList(taskId: Int, context: Context, callback: OchCommonServiceCallback>>?) {
+ val map = hashMapOf()
+ map["carSn"] = getCarSN()
+ map["taskId"] = taskId.toString()
+ d(SceneConstant.M_SWEEPER + TAG, "getSubTaskList:" + GsonUtil.jsonFromObject(map))
+ mService.getSubTaskList(
+ getServiceAppId(),
+ getToken(),
+ map
+ )
+ .transformTry()
+ .subscribe(OchCommonSubscribeImpl(context, callback, "getSubTaskList"))
+ }
+
+ /**
+ * 获取子任务详情包括轨迹文件信息
+ */
+ @JvmStatic
+ fun getSubTaskDetail(subTaskId: Int, context: Context, callback: OchCommonServiceCallback>?) {
+ val map = hashMapOf()
+ map["carSn"] = getCarSN()
+ map["taskId"] = subTaskId.toString()
+ d(SceneConstant.M_SWEEPER + TAG, "getSubTaskDetail:" + GsonUtil.jsonFromObject(map))
+ mService.getSubTaskDetail(
+ getServiceAppId(),
+ getToken(),
+ map
+ )
+ .transformTry()
+ .subscribe(OchCommonSubscribeImpl(context, callback, "getSubTaskList"))
+ }
+
+ /**
+ * 子任务开始上报
+ */
+ @JvmStatic
+ fun subTaskStart(isFirst: Boolean, isEnd: Boolean, subTaskId: Int, context: Context, callback: OchCommonServiceCallback>?) {
+ val subStartRequest = SubStartRequest(getCarSN(), subTaskId, System.currentTimeMillis(), isFirst, isEnd)
+ d(SceneConstant.M_SWEEPER + TAG, "subTaskStart:" + GsonUtil.jsonFromObject(subStartRequest))
+ mService.subTaskStart(
+ getServiceAppId(),
+ getToken(),
+ subStartRequest
+ )
+ .transformTry()
+ .subscribe(OchCommonSubscribeImpl(context, callback, "subTaskStart"))
+ }
+
+ /**
+ * 子任务结束上报
+ */
+ @JvmStatic
+ fun subTaskEnd(isFirst: Boolean, isEnd: Boolean, subTaskId: Int, context: Context, callback: OchCommonServiceCallback>?) {
+ val subStartRequest = SubStartRequest(getCarSN(), subTaskId, System.currentTimeMillis(), isFirst, isEnd)
+ d(SceneConstant.M_SWEEPER + TAG, "subTaskEnd:" + GsonUtil.jsonFromObject(subStartRequest))
+ mService.subTaskEnd(
+ getServiceAppId(),
+ getToken(),
+ subStartRequest
+ )
+ .transformTry()
+ .subscribe(OchCommonSubscribeImpl(context, callback, "subTaskEnd"))
+ }
+
+ /**
+ * 子任务跳过上报
+ */
+ @JvmStatic
+ fun subTaskSkip(isFirst: Boolean, isEnd: Boolean, subTaskId: Int, context: Context, callback: OchCommonServiceCallback>?) {
+ val subStartRequest = SubStartRequest(getCarSN(), subTaskId, System.currentTimeMillis(), isFirst, isEnd)
+ d(SceneConstant.M_SWEEPER + TAG, "subTaskSkip:" + GsonUtil.jsonFromObject(subStartRequest))
+ mService.subTaskSkip(
+ getServiceAppId(),
+ getToken(),
+ subStartRequest
+ )
+ .transformTry()
+ .subscribe(OchCommonSubscribeImpl(context, callback, "subTaskSkip"))
+ }
+
+ /**
+ * 主任务重置
+ */
+ @JvmStatic
+ fun mainTaskReset(taskId: Int, context: Context, callback: OchCommonServiceCallback>?) {
+ val map = hashMapOf()
+ map["carSn"] = getCarSN()
+ map["taskId"] = taskId.toString()
+ d(SceneConstant.M_SWEEPER + TAG, "mainTaskReset:" + GsonUtil.jsonFromObject(map))
+ mService.mainTaskReset(
+ getServiceAppId(),
+ getToken(),
+ map
+ )
+ .transformTry()
+ .subscribe(OchCommonSubscribeImpl(context, callback, "mainTaskReset"))
+ }
+
+ private fun getCarSN(): String {
+ return MoGoAiCloudClientConfig.getInstance().sn
+ }
+
+ private fun getServiceAppId(): String {
+ return MoGoAiCloudClientConfig.getInstance().serviceAppId
+ }
+
+ private fun getToken(): String {
+ return MoGoAiCloudClientConfig.getInstance().token
+ }
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/presenter/SweeperPresenter.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/presenter/SweeperPresenter.java
new file mode 100644
index 0000000000..acf46f64f6
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/presenter/SweeperPresenter.java
@@ -0,0 +1,461 @@
+package com.mogo.och.sweeper.presenter;
+
+
+import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_SWEEPER;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.amap.api.maps.model.LatLng;
+import com.mogo.commons.AbsMogoApplication;
+import com.mogo.commons.mvp.Presenter;
+import com.mogo.eagle.core.data.autopilot.AutopilotStatusInfo;
+import com.mogo.eagle.core.data.config.FunctionBuildConfig;
+import com.mogo.eagle.core.data.map.MogoLocation;
+import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener;
+import com.mogo.eagle.core.function.api.autopilot.IMoGoSweeperFutianCleanSystemListener;
+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.CallerSweeperFutianCleanSystemListenerManager;
+import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
+import com.mogo.eagle.core.utilcode.util.ThreadUtils;
+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.sweeper.bean.SweeperMainTaskBean;
+import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean;
+import com.mogo.och.sweeper.bean.SweeperSubTaskBean;
+import com.mogo.och.sweeper.bean.SweeperSubTaskDetailBean;
+import com.mogo.och.sweeper.callback.ISweeperADASStatusCallback;
+import com.mogo.och.sweeper.callback.ISweeperControllerStatusCallback;
+import com.mogo.och.sweeper.callback.ISweeperTaskCallback;
+import com.mogo.och.sweeper.callback.ISweeperTaskRouteCallback;
+import com.mogo.och.sweeper.constant.SubTaskTypeEnum;
+import com.mogo.och.sweeper.constant.SweeperConst;
+import com.mogo.och.sweeper.constant.TaskStatusEnum;
+import com.mogo.och.sweeper.database.MyDataBase;
+import com.mogo.och.sweeper.database.bean.WeltDataBean;
+import com.mogo.och.sweeper.fragment.SweeperFragment;
+import com.mogo.och.sweeper.model.SweeperTaskModel;
+import com.mogo.och.sweeper.util.SweeperFutianCmdUtil;
+import com.mogo.och.sweeper.util.SweeperTrajectoryManager;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.List;
+
+import chassis.ChassisStatesOuterClass;
+import mogo.telematics.pad.MessagePad;
+import mogo_msg.MogoReportMsg;
+import planning.RoboSweeperTaskIndexOuterClass;
+import system_master.SystemStatusInfo;
+
+/**
+ * 网约车小巴
+ *
+ * @author tongchenfei
+ */
+public class SweeperPresenter extends Presenter
+ implements IMoGoAutopilotStatusListener, ISweeperControllerStatusCallback, ISweeperADASStatusCallback,
+ IMoGoSweeperFutianCleanSystemListener, ISweeperTaskCallback, ISweeperTaskRouteCallback {
+
+ private static final String TAG = "SweeperPresenter";
+ //当前子任务id
+ private int mSubTaskId = 0;
+ // 清扫模式回调时间间隔
+ 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 String longitude;//经度
+ private String latitude;//纬度
+
+ public SweeperPresenter(SweeperFragment view) {
+ super(view);
+ //2021.11.1 鹰眼架构整合,由IMoGoAutopilotStatusListener逐步替代IMogoAdasOCHCallback接口
+ CallerAutoPilotStatusListenerManager.INSTANCE.addListener(TAG, this);
+ //清扫车模式和贴边数据回调监听
+ CallerSweeperFutianCleanSystemListenerManager.INSTANCE.addListener(TAG, this);
+ 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().setAdasStatusCallback(this);
+ SweeperTaskModel.getInstance().setSweeperTaskCallback(this);
+ }
+
+ public void releaseListener() {
+ SweeperTaskModel.getInstance().setControllerStatusCallback(null);
+ SweeperTaskModel.getInstance().setAdasStatusCallback(null);
+ SweeperTaskModel.getInstance().setSweeperTaskCallback(null);
+ CallerSweeperFutianCleanSystemListenerManager.INSTANCE.removeListener(TAG);
+ }
+
+ @Override
+ public void onAutopilotRouteLineId(long lineId) {
+
+ }
+
+ @Override
+ public void onAutopilotStatusResponse(@NotNull AutopilotStatusInfo autopilotStatusInfo) {
+ if (autopilotStatusInfo == null) return;
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onAutopilotStatusResponse state:" + autopilotStatusInfo.getState());
+ SweeperTaskModel.getInstance().setAutopilotState(autopilotStatusInfo.getState());
+ ThreadUtils.runOnUiThread(() -> mView.startAutoBtn(autopilotStatusInfo.getState()));
+ switch (autopilotStatusInfo.getState()) {
+ case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE://不可自动驾驶
+ break;
+ case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE://人工驾驶
+ if (SweeperTaskModel.getInstance().getSubWorking()) {
+ if (FunctionBuildConfig.isDemoMode) {//美化模式开启时
+ SweeperTaskModel.getInstance().startBeautificationMode();
+ }
+ } else {
+ if (FunctionBuildConfig.isDemoMode) {//美化模式开启时
+ //关闭美化模式
+ SweeperTaskModel.getInstance().closeBeautificationMode();
+ }
+ }
+ break;
+ case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING://自动驾驶中
+ SweeperTaskModel.getInstance().triggerStartServiceEvent(
+ SweeperTaskModel.getInstance().isRestartAutopilot(), true);
+ if (SweeperTaskModel.getInstance().getSubWorking()) {
+ if (FunctionBuildConfig.isDemoMode) {//美化模式开启时
+ SweeperTaskModel.getInstance().startBeautificationMode();
+ }
+ }
+ break;
+ case IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING://平行驾驶
+ if (SweeperTaskModel.getInstance().getSubWorking()) {
+ if (FunctionBuildConfig.isDemoMode) {//美化模式开启时
+ FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData = true;//是否强制绘制引导线
+ CallerAutoPilotControlManager.INSTANCE.setIPCDemoMode(false);//是否自动启动自驾
+ }
+ } else {
+ if (FunctionBuildConfig.isDemoMode) {//美化模式开启时
+ //关闭美化模式
+ SweeperTaskModel.getInstance().closeBeautificationMode();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ @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 startOpenAutopilot() {
+
+ }
+ /**
+ * 清除路线缓存数据
+ */
+ public void clearRouteList(){
+ SweeperTaskModel.getInstance().clearRouteList();
+ }
+ public void startAutopilot() {
+ SweeperTaskModel.getInstance().startAutopilot();
+ }
+
+ /**
+ * 设置当前子任务信息
+ */
+ public void setSubtask(boolean isFirstSubtask, boolean isLastSubtask, int subTaskId,int subTaskType) {
+ this.mSubTaskId = subTaskId;
+ SweeperTaskModel.getInstance().setSubtask(isFirstSubtask, isLastSubtask, subTaskId,subTaskType);
+ }
+ public void setWorking(boolean isWorking){
+ SweeperTaskModel.getInstance().setWorking(isWorking);
+ }
+ /**
+ * 测试使用
+ *
+ * @param status
+ */
+ public void debugAutoPilotStatus(int status) {
+ AutopilotStatusInfo info = new AutopilotStatusInfo();
+ info.setState(status);
+ onAutopilotStatusResponse(info);
+ }
+
+ @Override
+ public void onAutopilotGuardian(MogoReportMsg.MogoReportMessage guardianInfo) {
+ SweeperTrajectoryManager.getInstance().onAutopilotGuardian(guardianInfo);
+ }
+
+ @Override
+ public void onAutopilotIpcConnectStatusChanged(int status, @Nullable String reason) {
+ }
+
+ @Override
+ public void onAutopilotStatusRespByQuery(@NonNull SystemStatusInfo.StatusInfo status) {
+
+ }
+
+ @Override
+ public void onAutopilotArriveAtStation(@Nullable MessagePad.ArrivalNotification arrivalNotification) {
+ SweeperTaskModel.getInstance().onArriveTaskEnd(arrivalNotification);
+ }
+
+ @Override
+ public void onAutopilotSNRequest() {
+
+ }
+
+ @Override
+ public void onStartAdasFailure() {
+
+ }
+
+ public void onArriveTaskEnd(@Nullable MessagePad.ArrivalNotification arrivalNotification) {
+ SweeperTaskModel.getInstance().onArriveTaskEnd(arrivalNotification);
+ }
+
+ @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;
+ boolean clean_open_requirement = cleanSystemState.getSecuMotWorkSts();
+ // 洗扫
+ boolean clean_mode_wash_sweep = cleanSystemState.getSecuModWashSweepSts();
+ // 纯洗
+ boolean clean_mode_pure_wash = cleanSystemState.getSecuModWashSts();
+ // 纯吸
+ boolean clean_mode_pure_draw = cleanSystemState.getSecuWorkTonSts();
+ // 左侧
+ boolean clean_direction_left_side = cleanSystemState.getSecuWorkLeftSts();
+ // 右侧
+ boolean clean_direction_right_side = cleanSystemState.getSecuWorkRightSts();
+ // 两侧
+ boolean clean_direction_both_side = cleanSystemState.getSecuWorkOnBothsidesSts();
+ // 作业强度状态
+ boolean clean_intensity_standard = cleanSystemState.getSecuWorkStandSts();
+ boolean clean_intensity_strong = cleanSystemState.getSecuWorkStrongSts();
+
+ // 纯扫 模式判断:不是另外其他3个模式,同时有清扫方向,说明开启了纯扫模式
+ boolean clean_mode_pure_sweep = SweeperFutianCmdUtil.checkIfCleanModePureSweep(cleanSystemState);
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("开关:")
+ .append(clean_open_requirement)
+ .append("\n")
+ .append("纯扫:")
+ .append(clean_mode_wash_sweep)
+ .append("纯洗:")
+ .append(clean_mode_pure_wash)
+ .append("纯吸:")
+ .append(clean_mode_pure_draw)
+ .append("纯扫:")
+ .append("\n")
+ .append(clean_mode_pure_sweep)
+ .append("左侧:")
+ .append(clean_direction_left_side)
+ .append("右侧:")
+ .append(clean_direction_right_side)
+ .append("两侧:")
+ .append("\n")
+ .append(clean_direction_both_side)
+ .append("标准:")
+ .append(clean_intensity_standard)
+ .append("强力:")
+ .append(clean_intensity_strong);
+
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onSweeperFutianCleanSystemState:" + stringBuilder);
+ mView.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;
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("清扫模式:")
+ .append(roboSweeperTaskIndex.getCleanMode())
+ .append("清扫方向:")
+ .append(roboSweeperTaskIndex.getCleanDirection())
+ .append("清扫强度:")
+ .append(roboSweeperTaskIndex.getCleanIntensity())
+ .append("贴边距离:")
+ .append(roboSweeperTaskIndex.getDistToRefEdgePoint())
+ .append("经度:")
+ .append(roboSweeperTaskIndex.getLocLon())
+ .append("纬度:")
+ .append(roboSweeperTaskIndex.getLocLat());
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onSweeperFutianTaskIndexData:" + stringBuilder);
+ 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){
+ 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 四舍五入到整数
+ }
+ mView.setWeltDataToMap((ArrayList) MyDataBase.getInstance().getWeltDataDao().loadAllWeltDataInfo(), true, distance);
+ }
+ }
+
+ public static String format(double value) {
+ BigDecimal bd = new BigDecimal(value);
+ bd = bd.setScale(2, RoundingMode.HALF_UP);
+ return bd.toString();
+ }
+
+ /**
+ * 获取当前正在执行的任务
+ */
+ public void getCurrentTask() {
+ SweeperTaskModel.getInstance().getCurrentTask();
+ }
+
+ /**
+ * 获取主任务列表
+ */
+ public void getMainTaskList(boolean refresh) {
+ SweeperTaskModel.getInstance().getMainTaskList(refresh);
+ }
+
+ /**
+ * 获取子任务列表
+ */
+ public void getSubTaskList(int taskId, SweeperSubTaskBean sweeperSubTaskBean) {
+ SweeperTaskModel.getInstance().getSubTaskList(taskId, sweeperSubTaskBean);
+ }
+
+ /**
+ * 获取子任务详情包括轨迹文件信息
+ */
+ public void getSubTaskDetail(boolean isFirst, boolean isEnd, int subTaskId, SubTaskTypeEnum subTaskType, boolean isStartSubtask) {
+ SweeperTaskModel.getInstance().getSubTaskDetail(isFirst, isEnd, subTaskId, subTaskType, isStartSubtask);
+ }
+
+ /**
+ * 开始任务
+ */
+ public void startTask(boolean isFirst, boolean isEnd, int subTaskId, SubTaskTypeEnum subTaskType, int subTaskStatus) {
+ if (SubTaskTypeEnum.AUTOPILOT_SUBTYPE.getCode() == subTaskStatus) {
+ SweeperTaskModel.getInstance().subTaskStart(isFirst, isEnd, subTaskId, subTaskType);
+ }
+ }
+
+ /**
+ * 子任务结束上报
+ */
+ public void subTaskEnd(boolean isFirst, boolean isEnd, int subTaskId) {
+ SweeperTaskModel.getInstance().subTaskEnd(isFirst, isEnd, subTaskId);
+ }
+
+ /**
+ * 子任务跳过上报
+ */
+ public void subTaskSkip(boolean isFirst, boolean isEnd, int subTaskId) {
+ SweeperTaskModel.getInstance().subTaskSkip(isFirst, isEnd, subTaskId);
+ }
+
+ /**
+ * 主任务重置
+ */
+ public void mainTaskReset(int taskId) {
+ SweeperTaskModel.getInstance().mainTaskReset(taskId);
+ }
+
+ @Override
+ public void setMainTaskList(List mainTaskBeanList,boolean refresh) {
+ mView.setMainTaskList(mainTaskBeanList,refresh);
+ }
+
+ @Override
+ public void setSubTaskBean(SweeperSubTaskBean subTaskBean, boolean isWorkingSubTask) {
+ mView.setSubTaskBean(subTaskBean, isWorkingSubTask);
+ }
+
+ @Override
+ public void updateSubTaskStatus(TaskStatusEnum typeEnum, boolean isLastSubTask) {
+ mView.updateSubTaskStatus(typeEnum, isLastSubTask);
+ }
+
+ @Override
+ public void setMainTaskReset(boolean isSuccess) {
+ mView.setMainTaskReset(isSuccess);
+ }
+
+ @Override
+ public void setSubTakDetail(@NonNull SweeperSubTaskDetailBean subTaskDetailBean, SubTaskTypeEnum subTaskTypeEnum) {
+ }
+
+ @Override
+ public void setRouteList(@NonNull ArrayList routeList) {
+ mView.setTaskRouteList(routeList);
+ }
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/receiver/TestSweeperBroadcastReceiver.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/receiver/TestSweeperBroadcastReceiver.java
new file mode 100644
index 0000000000..b2ef6bcadd
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/receiver/TestSweeperBroadcastReceiver.java
@@ -0,0 +1,42 @@
+package com.mogo.och.sweeper.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.sweeper.constant.SweeperConst;
+
+/**
+ * 测试小巴车的场景
+ *
+ * @author donghongyu
+ * @date 4/26/21 12:08 PM
+ */
+public class TestSweeperBroadcastReceiver extends BroadcastReceiver {
+ private static final String TAG = "TestBusBroadcastReceiver";
+
+ private Context mContext;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ this.mContext = context;
+ int sceneType = intent.getIntExtra(SweeperConst.BROADCAST_TEST_SWEEPER_CONTROL_TYPE_EXTRA_KEY, 0);
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "sceneType:" + sceneType);
+
+ // 分发场景
+ dispatchSceneTest(sceneType);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void dispatchSceneTest(int sceneType) {
+
+ }
+
+
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/SweeperOperatePanelView.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/SweeperOperatePanelView.java
new file mode 100644
index 0000000000..934cc029de
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/SweeperOperatePanelView.java
@@ -0,0 +1,1094 @@
+package com.mogo.och.sweeper.ui;
+
+import static com.mogo.och.sweeper.util.SweeperFutianCmdUtil.CLEAN_DIRECTION_BOTH_SIDE;
+import static com.mogo.och.sweeper.util.SweeperFutianCmdUtil.CLEAN_DIRECTION_LEFT_SIDE;
+import static com.mogo.och.sweeper.util.SweeperFutianCmdUtil.CLEAN_DIRECTION_RIGHT_SIDE;
+import static com.mogo.och.sweeper.util.SweeperFutianCmdUtil.CLEAN_INTENSITY_STRAND;
+import static com.mogo.och.sweeper.util.SweeperFutianCmdUtil.CLEAN_INTENSITY_STRONG;
+import static com.mogo.och.sweeper.util.SweeperFutianCmdUtil.CLEAN_MODE_PURE_DRAW;
+import static com.mogo.och.sweeper.util.SweeperFutianCmdUtil.CLEAN_MODE_PURE_SWEEP;
+import static com.mogo.och.sweeper.util.SweeperFutianCmdUtil.CLEAN_MODE_PURE_WASH;
+import static com.mogo.och.sweeper.util.SweeperFutianCmdUtil.CLEAN_MODE_WASH_SWEEP;
+
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.animation.LinearInterpolator;
+import android.widget.CheckedTextView;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager;
+import com.mogo.eagle.core.utilcode.mogo.view.OnPreventFastClickListener;
+import com.mogo.eagle.core.utilcode.util.ToastUtils;
+import com.mogo.och.sweeper.R;
+import com.mogo.och.sweeper.callback.ICleaningModeStateCallback;
+import com.mogo.och.sweeper.constant.OperateStateEnum;
+import com.mogo.och.sweeper.util.SweeperFutianCmdUtil;
+import com.mogo.och.sweeper.view.NoTouchConstraintLayout;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import chassis.ChassisStatesOuterClass;
+import chassis.SpecialVehicleTaskCmdOuterClass;
+
+import static com.mogo.och.sweeper.util.SweeperFutianCmdUtil.CLEAN_DIRECTION_CLOSE;
+import static com.mogo.och.sweeper.util.SweeperFutianCmdUtil.CLEAN_MODE_CLOSE;
+import static com.mogo.och.sweeper.util.SweeperFutianCmdUtil.CLEAN_WORK_CLOSE;
+import static com.mogo.och.sweeper.util.SweeperFutianCmdUtil.CLEAN_WORK_OPEN;
+
+/**
+ * 清扫车操作面板View
+ */
+public class SweeperOperatePanelView extends LinearLayout {
+
+ private static final String TAG = "SweeperOperatePanelView";
+ private static final int CMD_EXECUTE_TIMEOUT_SECONDS = 30;
+ private static final int CMD_EXECUTE_MOCK_SUCCESS_SECONDS = 3;
+ private boolean isFirst = false;
+
+ CheckedTextView mBtnCleanWorkOpenClose;//开关
+ CheckedTextView mBtnCleanModePureSweep;//纯扫
+ CheckedTextView mBtnCleanModePureWash;//纯洗
+ CheckedTextView mBtnCleanModeSweepWash;//洗扫
+ CheckedTextView mBtnCleanModePureAbsorption;//纯吸
+ CheckedTextView mBtnCleanDirectionLeftSide;//左侧
+ CheckedTextView mBtnCleanDirectionRightSide;//右侧
+ CheckedTextView mBtnCleanDirectionBothSide;//两侧
+ CheckedTextView mBtnCleanIntensityStandard;//普通
+ CheckedTextView mBtnCleanIntensityStrong;//强力
+ FrameLayout mLoadingContainer;//loading container
+ TextView mLoadingHint;//loading 文本提示
+ ImageView mLoadingView;//loading 转圈动画
+ NoTouchConstraintLayout mWorkmodePanelRootView;
+
+ // 作业模式相关操作按钮的id
+ List cleanModeBtnViewIds = Arrays.asList(
+ R.id.btn_clean_mode_pure_sweep,
+ R.id.btn_clean_mode_pure_wash,
+ R.id.btn_clean_mode_sweep_wash,
+ R.id.btn_clean_mode_pure_absorption);
+
+ // 作业模式相关操作按钮,对应命令参数值
+ HashMap cleanModeBtnAndCmdValueMap = new HashMap() {
+ {
+ put(R.id.btn_clean_mode_pure_sweep, CLEAN_MODE_PURE_SWEEP);
+ put(R.id.btn_clean_mode_pure_wash, CLEAN_MODE_PURE_WASH);
+ put(R.id.btn_clean_mode_sweep_wash, CLEAN_MODE_WASH_SWEEP);
+ put(R.id.btn_clean_mode_pure_absorption, CLEAN_MODE_PURE_DRAW);
+ }
+ };
+
+ // 清扫方向相关操作按钮的id
+ List cleanDirectionBtnViewIds = Arrays.asList(
+ R.id.btn_clean_direction_left_side,
+ R.id.btn_clean_direction_right_side,
+ R.id.btn_clean_direction_both_side);
+
+ // 清扫方向相关按钮操作,对应命令参数值
+ HashMap cleanDirectionBtnAndCmdValueMap = new HashMap() {
+ {
+ put(R.id.btn_clean_direction_left_side, CLEAN_DIRECTION_LEFT_SIDE);
+ put(R.id.btn_clean_direction_right_side, CLEAN_DIRECTION_RIGHT_SIDE);
+ put(R.id.btn_clean_direction_both_side, CLEAN_DIRECTION_BOTH_SIDE);
+ }
+ };
+
+ // 作业强度相关按钮操作
+ List cleanIntensityBtnViewIds = Arrays.asList(
+ R.id.btn_clean_intensity_standard,
+ R.id.btn_clean_intensity_strong);
+
+ // 作业强度相关按钮操作,对应命令参数值
+ HashMap cleanIntensityBtnAndCmdValueMap = new HashMap() {
+ {
+ put(R.id.btn_clean_intensity_standard, CLEAN_INTENSITY_STRAND);
+ put(R.id.btn_clean_intensity_strong, CLEAN_INTENSITY_STRONG);
+ }
+ };
+ private boolean isSelectPureSweepMode = false;//用于标注是否选中纯扫
+
+ private ICleaningModeStateCallback cleaningModeStateCallback;
+
+ private OperateStateEnum operateStateEnum = OperateStateEnum.SYNCING_STATUS;
+
+ private ObjectAnimator objectAnimator;
+
+ private static ChassisStatesOuterClass.SweeperFuTianTaskSystemStates mCurrentCleanSystemState;//当前作业模式
+
+ public SweeperOperatePanelView(Context context) {
+ super(context);
+ }
+
+ public SweeperOperatePanelView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ initView(context);
+ }
+
+ public SweeperOperatePanelView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initView(context);
+ }
+
+ public SweeperOperatePanelView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ initView(context);
+ }
+
+ private void initView(Context context) {
+ LayoutInflater.from(context).inflate(R.layout.sweeper_operate_panel_view, this, true);
+ mBtnCleanWorkOpenClose = (CheckedTextView) findViewById(R.id.btn_clean_work_open_close);
+ mWorkmodePanelRootView = (NoTouchConstraintLayout) findViewById(R.id.work_mode_panel_root_view);
+ mBtnCleanModePureSweep = (CheckedTextView) findViewById(R.id.btn_clean_mode_pure_sweep);
+ mBtnCleanModePureWash = (CheckedTextView) findViewById(R.id.btn_clean_mode_pure_wash);
+ mBtnCleanModeSweepWash = (CheckedTextView) findViewById(R.id.btn_clean_mode_sweep_wash);
+ mBtnCleanModePureAbsorption = (CheckedTextView) findViewById(R.id.btn_clean_mode_pure_absorption);
+ mBtnCleanDirectionLeftSide = (CheckedTextView) findViewById(R.id.btn_clean_direction_left_side);
+ mBtnCleanDirectionRightSide = (CheckedTextView) findViewById(R.id.btn_clean_direction_right_side);
+ mBtnCleanDirectionBothSide = (CheckedTextView) findViewById(R.id.btn_clean_direction_both_side);
+ mBtnCleanIntensityStandard = (CheckedTextView) findViewById(R.id.btn_clean_intensity_standard);
+ mBtnCleanIntensityStrong = (CheckedTextView) findViewById(R.id.btn_clean_intensity_strong);
+ mLoadingContainer = findViewById(R.id.loading_hint_container);
+ mLoadingHint = findViewById(R.id.loading_hint);
+ mLoadingView = findViewById(R.id.loading_view);
+ initViewListener();
+ }
+
+ private void initViewListener() {
+ setClickListener(mBtnCleanWorkOpenClose, (v) -> onCleanWorkBtnClick());
+ setClickListener(mBtnCleanModePureSweep, (v) -> onCleanModeBtnClick(v));
+ setClickListener(mBtnCleanModePureWash, (v) -> onCleanModeBtnClick(v));
+ setClickListener(mBtnCleanModeSweepWash, (v) -> onCleanModeBtnClick(v));
+ setClickListener(mBtnCleanModePureAbsorption, (v) -> onCleanModeBtnClick(v));
+ setClickListener(mBtnCleanDirectionLeftSide, (v) -> onCleanDirectionBtnClick(v));
+ setClickListener(mBtnCleanDirectionRightSide, (v) -> onCleanDirectionBtnClick(v));
+ setClickListener(mBtnCleanDirectionBothSide, (v) -> onCleanDirectionBtnClick(v));
+ setClickListener(mBtnCleanIntensityStandard, (v) -> onCleanIntensityBtnClick(v));
+ setClickListener(mBtnCleanIntensityStrong, (v) -> onCleanIntensityBtnClick(v));
+ }
+
+ /**
+ * 清扫任务开关按钮点击事件
+ */
+ private void onCleanWorkBtnClick() {
+ // 是否是 关闭 操作
+ boolean isCloseAction = mBtnCleanWorkOpenClose.isChecked();
+ CmdRequestCallback cmdRequestCallback = new CmdRequestCallback() {
+ @Override
+ public void onSendCmd() {
+ showLoadingMask(CMD_EXECUTE_TIMEOUT_SECONDS);
+ }
+
+ @Override
+ public void onCountDownTick(int seconds) {
+ updateLoadingCountDown(seconds);
+ }
+
+ @Override
+ public boolean onCheckIfCmdSuccess(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) {
+ boolean success = false;
+ if (cleanSystemState == null) {
+ return success;
+ }
+ if (isCloseAction) {
+ success = !cleanSystemState.getSecuMotWorkSts();
+ } else {
+ success = cleanSystemState.getSecuMotWorkSts();
+ }
+ return success;
+ }
+
+ @Override
+ public void onCmdSuccess() {
+ if (isCloseAction) {
+ mBtnCleanWorkOpenClose.setText("打开");
+ mBtnCleanWorkOpenClose.setChecked(false);
+ toggleCleanModeBtnsStatus(false);
+ toggleCleanDirectionBtnsStatus(false);
+ toggleCleanIntensityBtnsStatus(false);
+ } else {
+ mBtnCleanWorkOpenClose.setText("关闭");
+ mBtnCleanWorkOpenClose.setChecked(true);
+ toggleCleanModeBtnsStatus(true);
+ }
+ hideLoadingMask();
+ showCmdExecuteSuccessToast();
+ }
+
+ @Override
+ public void onCmdFailed() {
+ }
+
+ @Override
+ public void onCmdTimeout() {
+ //按钮样式恢复原样
+ if (isCloseAction) {
+ mBtnCleanWorkOpenClose.setText("关闭");
+ mBtnCleanWorkOpenClose.setChecked(true);
+ } else {
+ mBtnCleanWorkOpenClose.setText("打开");
+ mBtnCleanWorkOpenClose.setChecked(false);
+ }
+ hideLoadingMask();
+ showCmdExecuteTimeoutToast();
+ }
+ };
+ if (isCloseAction) {
+ //关闭操作,点击时需要弹框提示确认后,关闭
+ sendSweeperCmd(
+ SweeperFutianCmdUtil.buildCleanWorkStopCmd(),
+ cmdRequestCallback
+ , CMD_EXECUTE_TIMEOUT_SECONDS);
+ } else {
+ //打开操作,点击时打开
+ sendSweeperCmd(
+ SweeperFutianCmdUtil.buildCleanWorkStartCmd(),
+ cmdRequestCallback,
+ CMD_EXECUTE_TIMEOUT_SECONDS);
+ }
+ }
+
+ /**
+ * 作业模式按钮点击事件
+ *
+ * @param currentClickView
+ */
+ private void onCleanModeBtnClick(final View currentClickView) {
+ CheckedTextView currentChoosedModeBtnView = null;
+ for (Integer viewId : cleanModeBtnViewIds) {
+ CheckedTextView view = (CheckedTextView) findViewById(viewId);
+ if (view.isChecked()) {
+ currentChoosedModeBtnView = view;
+ break;
+ }
+ }
+ boolean isClickCurrentChoosedModeBtn = currentChoosedModeBtnView != null
+ && currentChoosedModeBtnView.getId() == currentClickView.getId();
+ //是否纯吸View
+ boolean isPureAbsorptionClick = currentClickView.getId() == R.id.btn_clean_mode_pure_absorption;
+ //是否纯洗View
+ boolean isPureWashClick = currentClickView.getId() == R.id.btn_clean_mode_pure_wash;
+ //是否纯扫View
+ boolean isPureSweepClick = currentClickView.getId() == R.id.btn_clean_mode_pure_sweep;
+ //是否洗扫View
+ boolean isWashSweepClick = currentClickView.getId() == R.id.btn_clean_mode_sweep_wash;
+ CmdRequestCallback cmdRequestCallback = new CmdRequestCallback() {
+ @Override
+ public void onSendCmd() {
+ showLoadingMask(CMD_EXECUTE_TIMEOUT_SECONDS);
+ }
+
+ @Override
+ public void onCountDownTick(int seconds) {
+ updateLoadingCountDown(seconds);
+ }
+
+ @Override
+ public boolean onCheckIfCmdSuccess(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) {
+ boolean success = false;
+ if (cleanSystemState == null) {
+ return success;
+ }
+ // 洗扫
+ boolean clean_mode_wash_sweep = cleanSystemState.getSecuModWashSweepSts();
+ // 纯洗
+ boolean clean_mode_pure_wash = cleanSystemState.getSecuModWashSts();
+ // 纯吸
+ boolean clean_mode_pure_draw = cleanSystemState.getSecuWorkTonSts();
+ // 纯扫 模式判断:不是另外其他3个模式,同时有清扫方向,说明开启了纯扫模式
+ boolean clean_mode_pure_sweep = SweeperFutianCmdUtil.checkIfCleanModePureSweep(cleanSystemState);
+ // 关闭作业模式(实际执行了3个操作: 关闭作业模式 关闭清扫方向 切换标准强度,实际以关闭作业模式成功为准)
+ boolean clean_mode_close = !clean_mode_wash_sweep
+ && !clean_mode_pure_wash
+ && !clean_mode_pure_draw
+ && !clean_mode_pure_sweep;
+
+ if (isClickCurrentChoosedModeBtn && clean_mode_close) {// 关闭放第一判断
+ success = clean_mode_close;
+ isSelectPureSweepMode = false;
+ } else if (isPureSweepClick) {
+ //success = clean_mode_pure_sweep;
+ //纯扫 这个模式实际在福田清扫车上没有这个按钮,只是发送指令给特种车端,默认此命令肯定是正确的
+ success = true;
+ isSelectPureSweepMode = true;
+ } else if (isPureWashClick) {
+ success = clean_mode_pure_wash;
+ isSelectPureSweepMode = false;
+ } else if (isWashSweepClick) {
+ success = clean_mode_wash_sweep;
+ isSelectPureSweepMode = false;
+ } else if (isPureAbsorptionClick) {
+ success = clean_mode_pure_draw;
+ isSelectPureSweepMode = false;
+ }
+ return success;
+ }
+
+ @Override
+ public void onCmdSuccess() {
+ ((CheckedTextView) currentClickView).setChecked(!isClickCurrentChoosedModeBtn);
+ toggleCleanModeBtnsByChoosedViewId(currentClickView.getId(), isClickCurrentChoosedModeBtn);
+ if (isClickCurrentChoosedModeBtn) {
+ toggleCleanDirectionBtnsStatus(false);
+ toggleCleanIntensityBtnsStatus(false);
+ } else {
+ // 如果是纯吸,没有设置清扫方向,同时自动设置作业强度为标准
+ if (isPureAbsorptionClick) {
+ toggleCleanDirectionBtnsStatus(false);
+ setCleanIntensityStandard();
+ } else {
+ toggleCleanDirectionBtnsStatus(true);
+ toggleCleanIntensityBtnsStatus(false);
+ }
+ }
+ hideLoadingMask();
+ showCmdExecuteSuccessToast();
+ }
+
+ @Override
+ public void onCmdFailed() {
+ }
+
+ @Override
+ public void onCmdTimeout() {
+ ((CheckedTextView) currentClickView).setChecked(isClickCurrentChoosedModeBtn);
+ hideLoadingMask();
+ showCmdExecuteTimeoutToast();
+ }
+ };
+
+ if (isClickCurrentChoosedModeBtn) {
+ //当前已选择模式的按钮,取消当前模式,并关闭清扫方向
+ sendSweeperCmd(
+ SweeperFutianCmdUtil.buildCleanModeCloseCmd(),
+ cmdRequestCallback,
+ CMD_EXECUTE_TIMEOUT_SECONDS);
+ } else {
+ //开启新的作业模式,直接发送命令(纯吸需要一并设置作业强度为标准)
+ int cmdValue = cleanModeBtnAndCmdValueMap.get(currentClickView.getId());
+ sendSweeperCmd(
+ isPureAbsorptionClick ? SweeperFutianCmdUtil.buildCleanModePureDrawCmd()
+ : SweeperFutianCmdUtil.buildCleanModeCmd(cmdValue),
+ cmdRequestCallback,
+ CMD_EXECUTE_TIMEOUT_SECONDS);
+ }
+ }
+
+ private void onCleanDirectionBtnClick(final View currentClickView) {
+ CheckedTextView currentChoosedDirectionBtnView = null;
+ for (Integer viewId : cleanDirectionBtnViewIds) {
+ CheckedTextView view = (CheckedTextView) findViewById(viewId);
+ if (view.isChecked()) {
+ currentChoosedDirectionBtnView = view;
+ break;
+ }
+ }
+ boolean isClickCurrentChoosedDirectionBtn = currentChoosedDirectionBtnView != null
+ && currentChoosedDirectionBtnView.getId() == currentClickView.getId();
+
+ boolean isLeftSide = currentClickView.getId() == R.id.btn_clean_direction_left_side;
+ boolean isRightSide = currentClickView.getId() == R.id.btn_clean_direction_right_side;
+ boolean isBothSide = currentClickView.getId() == R.id.btn_clean_direction_both_side;
+ CmdRequestCallback cmdRequestCallback = new CmdRequestCallback() {
+ @Override
+ public void onSendCmd() {
+ showLoadingMask(CMD_EXECUTE_TIMEOUT_SECONDS);
+ }
+
+ @Override
+ public void onCountDownTick(int seconds) {
+ updateLoadingCountDown(seconds);
+ }
+
+ @Override
+ public boolean onCheckIfCmdSuccess(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) {
+ boolean success = false;
+ if (cleanSystemState == null) {
+ return success;
+ }
+ // 左侧
+ boolean clean_direction_left_side = cleanSystemState.getSecuWorkLeftSts();
+ // 右侧
+ boolean clean_direction_right_side = cleanSystemState.getSecuWorkRightSts();
+ // 两侧
+ boolean clean_direction_both_side = cleanSystemState.getSecuWorkOnBothsidesSts();
+ // 关闭清扫方向(实际执行了2个操作:关闭清扫方向 切换标准强度,实际以关闭清扫方向成功为准)
+ boolean clean_direction_close = !clean_direction_left_side && !clean_direction_right_side
+ && !clean_direction_both_side;
+
+ if (isClickCurrentChoosedDirectionBtn && clean_direction_close) {//关闭放第一判断
+ success = clean_direction_close;
+ } else if (isLeftSide) {
+ success = clean_direction_left_side;
+ } else if (isRightSide) {
+ success = clean_direction_right_side;
+ } else if (isBothSide) {
+ success = clean_direction_both_side;
+ }
+ return success;
+ }
+
+ @Override
+ public void onCmdSuccess() {
+ ((CheckedTextView) currentClickView).setChecked(!isClickCurrentChoosedDirectionBtn);
+ toggleCleanDirectionBtnsByChoosedViewId(currentClickView.getId(), isClickCurrentChoosedDirectionBtn);
+ if (isClickCurrentChoosedDirectionBtn) {
+ toggleCleanIntensityBtnsStatus(false);
+ } else {
+ toggleCleanIntensityBtnsStatus(true);
+ // 一并设置作业强度为标准
+ setCleanIntensityStandard();
+ }
+ hideLoadingMask();
+ showCmdExecuteSuccessToast();
+ }
+
+ @Override
+ public void onCmdFailed() {
+ }
+
+ @Override
+ public void onCmdTimeout() {
+ ((CheckedTextView) currentClickView).setChecked(isClickCurrentChoosedDirectionBtn);
+ hideLoadingMask();
+ showCmdExecuteTimeoutToast();
+ }
+ };
+ if (isClickCurrentChoosedDirectionBtn) {
+ //当前已选择模式的按钮,取消当前模式,重置作业强度为标准,并置灰作业强度按钮
+ sendSweeperCmd(
+ SweeperFutianCmdUtil.buildCleanDirectionCloseCmd(),
+ cmdRequestCallback,
+ CMD_EXECUTE_TIMEOUT_SECONDS);
+ } else {
+ //开启新的作业模式,直接发送命令(作业强度默认为标准)
+ int cmdValue = cleanDirectionBtnAndCmdValueMap.get(currentClickView.getId());
+ sendSweeperCmd(
+ SweeperFutianCmdUtil.buildCleanDirectionCmd(cmdValue),
+ cmdRequestCallback,
+ CMD_EXECUTE_TIMEOUT_SECONDS);
+ }
+ }
+
+ private void onCleanIntensityBtnClick(final View currentClickView) {
+ CheckedTextView currentChoosedModeBtnView = null;
+ for (Integer viewId : cleanIntensityBtnViewIds) {
+ CheckedTextView view = (CheckedTextView) findViewById(viewId);
+ if (view.isChecked()) {
+ currentChoosedModeBtnView = view;
+ break;
+ }
+ }
+ boolean isClickCurrentChoosedModeBtn = currentChoosedModeBtnView != null
+ && currentChoosedModeBtnView.getId() == currentClickView.getId();
+ //作业强度如果已经选中,则重复点击时不需要再重复发送指令
+ if (isClickCurrentChoosedModeBtn) {
+ return;
+ }
+ boolean isStandardBtnClick = currentClickView.getId() == R.id.btn_clean_intensity_standard;
+ boolean isStrongBtnClick = currentClickView.getId() == R.id.btn_clean_intensity_strong;
+ CmdRequestCallback cmdRequestCallback = new CmdRequestCallback() {
+ @Override
+ public void onSendCmd() {
+ showLoadingMask(CMD_EXECUTE_TIMEOUT_SECONDS);
+ }
+
+ @Override
+ public void onCountDownTick(int seconds) {
+ updateLoadingCountDown(seconds);
+ }
+
+ @Override
+ public boolean onCheckIfCmdSuccess(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) {
+ boolean success = false;
+ if (cleanSystemState == null) {
+ return success;
+ }
+ boolean clean_intensity_standard = cleanSystemState.getSecuWorkStandSts();
+ boolean clean_intensity_strong = cleanSystemState.getSecuWorkStrongSts();
+ if (isStandardBtnClick) {
+ success = clean_intensity_standard;
+ } else if (isStrongBtnClick) {
+ success = clean_intensity_strong;
+ }
+ return success;
+ }
+
+ @Override
+ public void onCmdSuccess() {
+ ((CheckedTextView) currentClickView).setChecked(true);
+ if (isStandardBtnClick) {
+ setCleanIntensityStandard();
+ } else {
+ setCleanIntensityStrong();
+ }
+ hideLoadingMask();
+ showCmdExecuteSuccessToast();
+ }
+
+ @Override
+ public void onCmdFailed() {
+ }
+
+ @Override
+ public void onCmdTimeout() {
+ ((CheckedTextView) currentClickView).setChecked(false);
+ hideLoadingMask();
+ showCmdExecuteTimeoutToast();
+ }
+ };
+ int cmdValue = cleanIntensityBtnAndCmdValueMap.get(currentClickView.getId());
+ sendSweeperCmd(
+ SweeperFutianCmdUtil.buildCleanIntensityCmd(cmdValue),
+ cmdRequestCallback,
+ CMD_EXECUTE_TIMEOUT_SECONDS);
+ }
+
+ /**
+ * 作业模式按钮状态切换-置灰/开启 按钮
+ *
+ * @param enable
+ */
+ private void toggleCleanModeBtnsStatus(boolean enable) {
+ for (Integer viewId : cleanModeBtnViewIds) {
+ CheckedTextView view = (CheckedTextView) findViewById(viewId);
+ view.setEnabled(enable);
+ view.setChecked(false);
+ }
+ }
+
+ /**
+ * 作业模式按钮状态切换-将当前点击按钮之外的其他按钮 置灰或开启
+ *
+ * @param choosedBtnId
+ * @param enable
+ */
+ private void toggleCleanModeBtnsByChoosedViewId(int choosedBtnId, boolean enable) {
+ for (Integer viewId : cleanModeBtnViewIds) {
+ CheckedTextView view = (CheckedTextView) findViewById(viewId);
+ if (view.getId() != choosedBtnId) {
+ view.setEnabled(enable);
+ view.setChecked(false);
+ }
+ }
+ }
+
+ /**
+ * 清扫方向按钮状态切换-置灰/开启 按钮
+ *
+ * @param enable
+ */
+ private void toggleCleanDirectionBtnsStatus(boolean enable) {
+ for (Integer viewId : cleanDirectionBtnViewIds) {
+ CheckedTextView view = (CheckedTextView) findViewById(viewId);
+ view.setEnabled(enable);
+ view.setChecked(false);
+ }
+ }
+
+ /**
+ * 清扫方向按钮状态切换-将当前点击按钮之外的其他按钮 置灰或开启
+ *
+ * @param choosedBtnId
+ * @param enable
+ */
+ private void toggleCleanDirectionBtnsByChoosedViewId(int choosedBtnId, boolean enable) {
+ for (Integer viewId : cleanDirectionBtnViewIds) {
+ CheckedTextView view = (CheckedTextView) findViewById(viewId);
+ if (view.getId() != choosedBtnId) {
+ view.setEnabled(enable);
+ view.setChecked(false);
+ }
+ }
+ }
+
+ /**
+ * 作业强度按钮状态切换-置灰/开启 按钮
+ *
+ * @param enable
+ */
+ private void toggleCleanIntensityBtnsStatus(boolean enable) {
+ for (Integer viewId : cleanIntensityBtnViewIds) {
+ CheckedTextView view = (CheckedTextView) findViewById(viewId);
+ view.setEnabled(enable);
+ view.setChecked(false);
+ }
+ }
+
+ /**
+ * 设置作业强度-标准
+ */
+ private void setCleanIntensityStandard() {
+ mBtnCleanIntensityStandard.setChecked(true);
+ mBtnCleanIntensityStandard.setEnabled(true);
+ mBtnCleanIntensityStrong.setChecked(false);
+ mBtnCleanIntensityStrong.setEnabled(true);
+ }
+
+ /**
+ * 设置作业强度-加强
+ */
+ private void setCleanIntensityStrong() {
+ mBtnCleanIntensityStandard.setChecked(false);
+ mBtnCleanIntensityStandard.setEnabled(true);
+ mBtnCleanIntensityStrong.setChecked(true);
+ mBtnCleanIntensityStrong.setEnabled(true);
+ }
+
+ /**
+ * 发送命令后等待时,展示loading
+ *
+ * @param timeout
+ */
+ private void showLoadingMask(int timeout) {
+ mLoadingContainer.setVisibility(View.VISIBLE);
+ mWorkmodePanelRootView.setInterceptTouchEvent(true);
+ if (timeout < 0) {//状态同步中
+ mLoadingHint.setText("状态同步中,请稍后");
+ mLoadingView.setVisibility(View.GONE);
+ } else {
+ mLoadingHint.setText(timeout + "s");
+ mLoadingView.setVisibility(View.VISIBLE);
+ startRotation();
+ }
+ if (cleaningModeStateCallback != null && timeout > 0) {
+ operateStateEnum = OperateStateEnum.STARTING_STATUS;
+ cleaningModeStateCallback.cleaningModeState(operateStateEnum, mCurrentCleanSystemState, isSelectPureSweepMode);
+ }
+ }
+
+ /**
+ * 隐藏loading
+ */
+ private void hideLoadingMask() {
+ mSweeperOperateCmdHandler.removeMessages(MSG_CMD_EXECUTE_COUNT_DOWN);
+ mLoadingContainer.setVisibility(View.GONE);
+ mWorkmodePanelRootView.setInterceptTouchEvent(false);
+ }
+
+ /**
+ * 更新loading中倒计时
+ *
+ * @param timeout
+ */
+ private void updateLoadingCountDown(int timeout) {
+ mLoadingHint.setText(timeout + "s");
+ }
+
+ /**
+ * 命令执行成功toast
+ */
+ private void showCmdExecuteSuccessToast() {
+ if (cleaningModeStateCallback != null) {
+ operateStateEnum = OperateStateEnum.SUCCESS_STATUS;
+ cleaningModeStateCallback.cleaningModeState(operateStateEnum, mCurrentCleanSystemState, isSelectPureSweepMode);
+ }
+ //停止旋转动画
+ stopRotation();
+ ToastUtils.showLong("设备已响应,操作成功");
+ }
+
+ /**
+ * 命令执行超时toast
+ */
+ private void showCmdExecuteTimeoutToast() {
+ if (cleaningModeStateCallback != null) {
+ operateStateEnum = OperateStateEnum.FAIL_STATUS;
+ cleaningModeStateCallback.cleaningModeState(operateStateEnum, mCurrentCleanSystemState, isSelectPureSweepMode);
+ }
+ //停止旋转动画
+ stopRotation();
+ ToastUtils.showLong("超时未响应,操作失败");
+ }
+
+ private void setClickListener(View view, OnClickListener listener) {
+ view.setOnClickListener(new OnPreventFastClickListener() {
+ @Override
+ public void onClickImpl(View v) {
+ listener.onClick(v);
+ }
+ });
+ }
+
+ public void setSweeperFutianCleanSystemState(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState,
+ ICleaningModeStateCallback cleaningModeStateCallback) {
+ this.cleaningModeStateCallback = cleaningModeStateCallback;
+ // 有命令正在执行
+ if (mCurrentCmdRequestCallback != null) {
+ Log.d(TAG, "getSecuWorkLeftSts = " + cleanSystemState.getSecuWorkLeftSts());
+ if (mCurrentCmdRequestCallback.onCheckIfCmdSuccess(cleanSystemState)) {
+ mCurrentCmdRequestCallback.onCmdSuccess();
+ mCurrentCmdRequestCallback = null;
+ }
+ }
+ //正在上装中或者上装失败,则不更新面板内容
+ if (operateStateEnum == OperateStateEnum.STARTING_STATUS) {
+ return;
+ }
+ if (!isFirst) {
+ isFirst = true;
+ onSyncVehicleStateCallBack(cleanSystemState);
+ }
+ }
+
+ /**
+ * 设置是否展示状态同步中
+ *
+ * @param operateState
+ */
+ public void showSyncing(OperateStateEnum operateState) {
+ if (operateState == OperateStateEnum.SYNCING_STATUS) {
+ syncVehicleStateAndRecoverOperatePanelStates();
+ isFirst = false;
+ } else {
+ hideLoadingMask();
+ }
+ }
+
+ /**
+ * 等待同步底盘数据,并根据底盘数据恢复操作面板中按钮的状态
+ */
+ private synchronized void syncVehicleStateAndRecoverOperatePanelStates() {
+ // show sync loading
+ showLoadingMask(-1);
+ }
+
+ private synchronized void onSyncVehicleStateCallBack(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) {
+ if (cleanSystemState == null) return;
+ // 清扫作业开启状态(以电机状态为true代表Open成功,实际控制端控制步骤为:1.发送远程控制上装指令 2.发送电机启动指令)
+ boolean clean_open_requirement = cleanSystemState.getSecuMotWorkSts();
+ // 作业模式状态
+ // 洗扫
+ boolean clean_mode_wash_sweep = cleanSystemState.getSecuModWashSweepSts();
+ // 纯洗
+ boolean clean_mode_pure_wash = cleanSystemState.getSecuModWashSts();
+ // 纯吸
+ boolean clean_mode_pure_draw = cleanSystemState.getSecuWorkTonSts();
+
+ // 清扫方向状态
+ // 左侧
+ boolean clean_direction_left_side = cleanSystemState.getSecuWorkLeftSts();
+ // 右侧
+ boolean clean_direction_right_side = cleanSystemState.getSecuWorkRightSts();
+ // 两侧
+ boolean clean_direction_both_side = cleanSystemState.getSecuWorkOnBothsidesSts();
+
+ // 纯扫 模式判断:不是另外其他3个模式,同时有清扫方向,说明开启了纯扫模式
+ boolean clean_mode_pure_sweep = SweeperFutianCmdUtil.checkIfCleanModePureSweep(cleanSystemState);
+
+ // 作业强度状态
+ boolean clean_intensity_standard = cleanSystemState.getSecuWorkStandSts();
+ boolean clean_intensity_strong = cleanSystemState.getSecuWorkStrongSts();
+ if (clean_open_requirement) {
+ // 打开状态
+ mBtnCleanWorkOpenClose.setText("关闭");
+ mBtnCleanWorkOpenClose.setChecked(true);
+ } else {
+ // 关闭状态
+ mBtnCleanWorkOpenClose.setText("打开");
+ mBtnCleanWorkOpenClose.setChecked(false);
+ }
+ if (clean_mode_pure_sweep) {
+ //纯扫
+ mBtnCleanModePureSweep.setChecked(true);
+ mBtnCleanModePureSweep.setEnabled(true);
+ toggleCleanModeBtnsByChoosedViewId(R.id.btn_clean_mode_pure_sweep, false);
+ } else if (clean_mode_pure_wash) {
+ //纯洗
+ mBtnCleanModePureWash.setChecked(true);
+ mBtnCleanModePureWash.setEnabled(true);
+ toggleCleanModeBtnsByChoosedViewId(R.id.btn_clean_mode_pure_wash, false);
+ } else if (clean_mode_wash_sweep) {
+ //洗扫
+ mBtnCleanModeSweepWash.setChecked(true);
+ mBtnCleanModeSweepWash.setEnabled(true);
+ toggleCleanModeBtnsByChoosedViewId(R.id.btn_clean_mode_sweep_wash, false);
+ } else if (clean_mode_pure_draw) {
+ //纯吸,需要disable作业方向
+ mBtnCleanModePureAbsorption.setChecked(true);
+ mBtnCleanModePureAbsorption.setEnabled(true);
+ toggleCleanModeBtnsByChoosedViewId(R.id.btn_clean_mode_pure_absorption, false);
+ toggleCleanDirectionBtnsStatus(false);
+ }
+
+ if (!clean_mode_pure_draw) {// 非纯吸模式才有清扫方向
+ if (clean_direction_left_side) {
+ mBtnCleanDirectionLeftSide.setChecked(true);
+ mBtnCleanDirectionLeftSide.setEnabled(true);
+ toggleCleanDirectionBtnsByChoosedViewId(R.id.btn_clean_direction_left_side, false);
+ } else if (clean_direction_right_side) {
+ mBtnCleanDirectionRightSide.setChecked(true);
+ mBtnCleanDirectionRightSide.setEnabled(true);
+ toggleCleanDirectionBtnsByChoosedViewId(R.id.btn_clean_direction_right_side, false);
+ } else if (clean_direction_both_side) {
+ mBtnCleanDirectionBothSide.setChecked(true);
+ mBtnCleanDirectionBothSide.setEnabled(true);
+ toggleCleanDirectionBtnsByChoosedViewId(R.id.btn_clean_direction_both_side, false);
+ }
+ }
+ if (clean_intensity_standard) {
+ setCleanIntensityStandard();
+ } else if (clean_intensity_strong) {
+ setCleanIntensityStrong();
+ }
+ hideLoadingMask();
+ }
+
+ /**
+ * 发送清扫车相关作业命令
+ *
+ * @param fuTianCleanCmd
+ * @param cmdRequestCallback
+ * @param timeout
+ */
+ private void sendSweeperCmd(
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd fuTianCleanCmd,
+ CmdRequestCallback cmdRequestCallback,
+ int timeout) {
+ // 设置当前请求的回调
+ mCurrentCmdRequestCallback = cmdRequestCallback;
+ // onSendCmd
+ mCurrentCmdRequestCallback.onSendCmd();
+ // 发送命令
+ CallerAutoPilotControlManager.INSTANCE.sendSweeperFuTianTaskCmd(fuTianCleanCmd);
+ // log发送命令
+ logSweeperCmdValue(fuTianCleanCmd);
+ // 开启倒计时
+ Message msg = Message.obtain();
+ msg.what = MSG_CMD_EXECUTE_COUNT_DOWN;
+ msg.obj = timeout;
+ mSweeperOperateCmdHandler.sendMessage(msg);
+ // Mock Cmd Success
+ //mockCleanModeSuccess(fuTianCleanCmd);
+ }
+
+ private void mockSendCmdSuccess() {
+ Message successMsg = Message.obtain();
+ successMsg.what = MSG_CMD_EXECUTE_MOCK_SUCCESS;
+ mSweeperOperateCmdHandler.sendMessageDelayed(successMsg, 1000L * CMD_EXECUTE_MOCK_SUCCESS_SECONDS);
+ }
+
+ private void logSweeperCmdValue(SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd taskCmd) {
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd roboSweeperFutianCleanCmd = taskCmd.getRoboSweeperFutianCleanCmd();
+ int clean_open_requirement = roboSweeperFutianCleanCmd.getCleanOpenRequirement();
+ int clean_mode_requirement = roboSweeperFutianCleanCmd.getCleanModeRequirement();
+ int clean_direction_requirement = roboSweeperFutianCleanCmd.getCleanDirectionRequirement();
+ int clean_intensity_requirement = roboSweeperFutianCleanCmd.getCleanIntensityRequirement();
+ Log.d(TAG, "---- sendSweeperFuTianTaskCmd ----"
+ + "[clean_open_requirement = " + clean_open_requirement + "],"
+ + "[clean_mode_requirement = " + clean_mode_requirement + "],"
+ + "[clean_direction_requirement = " + clean_direction_requirement + "],"
+ + "[clean_intensity_requirement = " + clean_intensity_requirement + "]"
+ );
+ }
+
+ private final static SweeperOperateCmdHandler mSweeperOperateCmdHandler = new SweeperOperateCmdHandler();
+ private static CmdRequestCallback mCurrentCmdRequestCallback;//发送命令后的回调
+ private static final int MSG_CMD_EXECUTE_COUNT_DOWN = 10001;
+ private static final int MSG_CMD_EXECUTE_MOCK_SUCCESS = 10002;
+
+ /**
+ * 执行命令时倒计时的Handler
+ */
+ static class SweeperOperateCmdHandler extends Handler {
+
+ @Override
+ public void handleMessage(@NonNull Message msg) {
+ super.handleMessage(msg);
+ if (msg.what == MSG_CMD_EXECUTE_COUNT_DOWN) {
+ int seconds = (int) msg.obj;
+ if (seconds > 0) {
+ if (mCurrentCmdRequestCallback != null) {
+ mCurrentCmdRequestCallback.onCountDownTick(seconds);
+ }
+ Message newMsg = Message.obtain();
+ newMsg.what = MSG_CMD_EXECUTE_COUNT_DOWN;
+ newMsg.obj = seconds - 1;
+ mSweeperOperateCmdHandler.sendMessageDelayed(newMsg, 1000L);
+ } else {
+ if (mCurrentCmdRequestCallback != null) {
+ mCurrentCmdRequestCallback.onCmdTimeout();
+ mCurrentCmdRequestCallback = null;
+ }
+ removeMessages(MSG_CMD_EXECUTE_COUNT_DOWN);
+ }
+ } else if (msg.what == MSG_CMD_EXECUTE_MOCK_SUCCESS) {
+ if (mCurrentCmdRequestCallback != null) {
+ if (mCurrentCmdRequestCallback.onCheckIfCmdSuccess(mCurrentCleanSystemState)) {
+ mCurrentCmdRequestCallback.onCmdSuccess();
+ mCurrentCmdRequestCallback = null;
+ }
+ }
+ removeMessages(MSG_CMD_EXECUTE_COUNT_DOWN);
+ }
+ }
+ }
+
+ interface CmdRequestCallback {
+ void onSendCmd();
+
+ void onCountDownTick(int senonds);
+
+ boolean onCheckIfCmdSuccess(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState);
+
+ void onCmdSuccess();
+
+ void onCmdFailed();
+
+ void onCmdTimeout();
+ }
+
+ /**
+ * 开始旋转
+ */
+ private void startRotation() {
+ if (objectAnimator == null) {
+ objectAnimator = ObjectAnimator.ofFloat(mLoadingView, "rotation", 0, 360f);
+ objectAnimator.setDuration(1500);
+ objectAnimator.setRepeatCount(-1);
+ objectAnimator.setInterpolator(new LinearInterpolator());
+ objectAnimator.start();
+ }
+ }
+
+ /**
+ * 停止旋转
+ */
+ private void stopRotation() {
+ if (objectAnimator != null && objectAnimator.isRunning()) {
+ objectAnimator.end();
+ objectAnimator = null;
+ }
+ }
+
+ /**
+ * 模拟指令操作成功
+ */
+ private void mockCleanModeSuccess(SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd fuTianTaskCmd) {
+ ChassisStatesOuterClass.SweeperFuTianTaskSystemStates.Builder builder = ChassisStatesOuterClass.SweeperFuTianTaskSystemStates.newBuilder();
+ chassis.SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd fuTianCleanCmd = fuTianTaskCmd.getRoboSweeperFutianCleanCmd();
+ if (fuTianCleanCmd.getCleanOpenRequirement() == CLEAN_WORK_OPEN) {//打开
+ builder.setSecuMotWorkSts(true);
+ builder.setSecuModWashSweepSts(false);
+ builder.setSecuModWashSts(false);
+ builder.setSecuWorkTonSts(false);
+ builder.setSecuWorkOnBothsidesSts(false);
+ builder.setSecuWorkLeftSts(false);
+ builder.setSecuWorkRightSts(false);
+ builder.setSecuWorkStandSts(true);
+ builder.setSecuWorkStrongSts(false);
+ mCurrentCleanSystemState = builder.build();
+ mockSendCmdSuccess();
+ return;
+ } else if (fuTianCleanCmd.getCleanOpenRequirement() == CLEAN_WORK_CLOSE) {//关闭
+ builder.setSecuModWashSweepSts(false);
+ builder.setSecuModWashSts(false);
+ builder.setSecuWorkTonSts(false);
+ builder.setSecuWorkOnBothsidesSts(false);
+ builder.setSecuWorkLeftSts(false);
+ builder.setSecuWorkRightSts(false);
+ builder.setSecuWorkStandSts(true);
+ builder.setSecuWorkStrongSts(false);
+ builder.setSecuMotWorkSts(false);
+ mCurrentCleanSystemState = builder.build();
+ mockSendCmdSuccess();
+ return;
+ }
+ if (fuTianCleanCmd.getCleanModeRequirement() == CLEAN_MODE_PURE_SWEEP) {//纯扫
+ builder.setSecuModWashSweepSts(false);
+ builder.setSecuModWashSts(false);
+ builder.setSecuWorkTonSts(false);
+ mCurrentCleanSystemState = builder.build();
+ mockSendCmdSuccess();
+ return;
+ } else if (fuTianCleanCmd.getCleanModeRequirement() == CLEAN_MODE_WASH_SWEEP) {//洗扫
+ builder.setSecuModWashSweepSts(!mCurrentCleanSystemState.getSecuModWashSweepSts());
+ mCurrentCleanSystemState = builder.build();
+ mockSendCmdSuccess();
+ return;
+ } else if (fuTianCleanCmd.getCleanModeRequirement() == CLEAN_MODE_PURE_WASH) {//纯洗
+ builder.setSecuModWashSts(!mCurrentCleanSystemState.getSecuModWashSts());
+ mCurrentCleanSystemState = builder.build();
+ mockSendCmdSuccess();
+ return;
+ } else if (fuTianCleanCmd.getCleanModeRequirement() == CLEAN_MODE_PURE_DRAW) {//纯吸
+ builder.setSecuWorkTonSts(!mCurrentCleanSystemState.getSecuWorkTonSts());
+ builder.setSecuWorkStandSts(true);
+ builder.setSecuWorkOnBothsidesSts(false);
+ builder.setSecuWorkLeftSts(false);
+ builder.setSecuWorkRightSts(false);
+ mCurrentCleanSystemState = builder.build();
+ mockSendCmdSuccess();
+ return;
+ } else if (fuTianCleanCmd.getCleanModeRequirement() == CLEAN_MODE_CLOSE) {
+ builder.setSecuModWashSweepSts(false);
+ builder.setSecuModWashSts(false);
+ builder.setSecuWorkTonSts(false);
+ builder.setSecuWorkOnBothsidesSts(false);
+ builder.setSecuWorkLeftSts(false);
+ builder.setSecuWorkRightSts(false);
+ builder.setSecuWorkStandSts(true);
+ builder.setSecuWorkStrongSts(false);
+ mCurrentCleanSystemState = builder.build();
+ mockSendCmdSuccess();
+ return;
+ }
+ if (fuTianCleanCmd.getCleanDirectionRequirement() == CLEAN_DIRECTION_BOTH_SIDE) {//两侧
+ builder.setSecuWorkOnBothsidesSts(!mCurrentCleanSystemState.getSecuWorkOnBothsidesSts());
+ builder.setSecuWorkStandSts(true);
+ builder.setSecuWorkStrongSts(false);
+ mCurrentCleanSystemState = builder.build();
+ mockSendCmdSuccess();
+ return;
+ } else if (fuTianCleanCmd.getCleanDirectionRequirement() == CLEAN_DIRECTION_LEFT_SIDE) {//左侧
+ builder.setSecuWorkLeftSts(!mCurrentCleanSystemState.getSecuWorkLeftSts());
+ builder.setSecuWorkStandSts(true);
+ builder.setSecuWorkStrongSts(false);
+ mCurrentCleanSystemState = builder.build();
+ mockSendCmdSuccess();
+ return;
+ } else if (fuTianCleanCmd.getCleanDirectionRequirement() == CLEAN_DIRECTION_RIGHT_SIDE) {//右侧
+ builder.setSecuWorkRightSts(!mCurrentCleanSystemState.getSecuWorkRightSts());
+ builder.setSecuWorkStandSts(true);
+ builder.setSecuWorkStrongSts(false);
+ mCurrentCleanSystemState = builder.build();
+ mockSendCmdSuccess();
+ return;
+ } else if (fuTianCleanCmd.getCleanDirectionRequirement() == CLEAN_DIRECTION_CLOSE) {
+ builder.setSecuWorkLeftSts(false);
+ builder.setSecuWorkRightSts(false);
+ builder.setSecuWorkOnBothsidesSts(false);
+ builder.setSecuWorkStandSts(true);
+ builder.setSecuWorkStrongSts(false);
+ mCurrentCleanSystemState = builder.build();
+ mockSendCmdSuccess();
+ return;
+ }
+ if (fuTianCleanCmd.getCleanIntensityRequirement() == CLEAN_INTENSITY_STRAND) {
+ builder.setSecuWorkStrongSts(true);
+ builder.setSecuWorkStandSts(false);
+ mCurrentCleanSystemState = builder.build();
+ mockSendCmdSuccess();
+ return;
+ } else if (fuTianCleanCmd.getCleanIntensityRequirement() == CLEAN_INTENSITY_STRONG) {
+ builder.setSecuWorkStandSts(true);
+ builder.setSecuWorkStrongSts(false);
+ mCurrentCleanSystemState = builder.build();
+ mockSendCmdSuccess();
+ }
+
+ }
+
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/adapter/TaskListAdapter.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/adapter/TaskListAdapter.kt
new file mode 100644
index 0000000000..ef9aaa9a61
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/adapter/TaskListAdapter.kt
@@ -0,0 +1,79 @@
+package com.mogo.och.sweeper.ui.adapter
+
+import android.graphics.Color
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import com.mogo.och.common.module.utils.DateTimeUtil
+import com.mogo.och.sweeper.R
+import com.mogo.och.sweeper.bean.SweeperMainTaskBean
+
+class TaskListAdapter() : RecyclerView.Adapter() {
+ private var mItemClickListener: TaskItemClickListener? = null
+ private var mSelectPosition: Int = -1
+ private var data:MutableList?=null
+ fun setOnTaskItemClickListener(itemClickListener: TaskItemClickListener?) {
+ mItemClickListener = itemClickListener
+ }
+
+ class TaskViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ val selectIv: ImageView
+ val taskName: TextView//任务名称
+ val taskDesc: TextView//任务描述
+ val tvTaskTime: TextView//任务时间
+
+ init {
+ selectIv = itemView.findViewById(R.id.ivTaskSelect)
+ taskName = itemView.findViewById(R.id.tvTaskName)
+ taskDesc = itemView.findViewById(R.id.tvTaskDesc)
+ tvTaskTime = itemView.findViewById(R.id.tvTaskTime)
+ }
+ }
+
+ fun selectPosition(position: Int) {
+ this.mSelectPosition = position
+ notifyDataSetChanged()
+ }
+ fun setTaskListData(data: MutableList?){
+ this.data=data
+ notifyDataSetChanged()
+ }
+ interface TaskItemClickListener {
+ fun onItemClick(position: Int,mainTask:SweeperMainTaskBean)
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TaskViewHolder {
+ val view = LayoutInflater.from(parent.context).inflate(
+ R.layout.sweeper_item_task_info, parent, false
+ )
+ return TaskViewHolder(view)
+ }
+
+ override fun onBindViewHolder(holder: TaskViewHolder, position: Int) {
+ data?.let { mainTask->
+ holder.taskName.text= mainTask[position].mainTaskName
+ holder.taskDesc.text= "全程包含${mainTask[position].subTaskTotal}个子任务"
+ val calendar = DateTimeUtil.formatLongToCalendar(mainTask[position].mainTaskStartTime)
+ if (DateTimeUtil.compareDateIsCurrentDay(calendar)){
+ holder.tvTaskTime.text="今天${DateTimeUtil.formatCalendarToString(calendar, DateTimeUtil.HH_mm)}"
+ }else{
+ holder.tvTaskTime.text=DateTimeUtil.formatCalendarToString(calendar, DateTimeUtil.MM_dd_HH_mm)
+ }
+ holder.itemView.setOnClickListener {
+ mItemClickListener?.onItemClick(position,mainTask[position])
+ }
+ }
+ if (position == mSelectPosition) {
+ holder.selectIv.visibility = View.VISIBLE
+ holder.itemView.setBackgroundColor(Color.parseColor("#FF122B4E"))
+ } else {
+ holder.selectIv.visibility = View.GONE
+ holder.itemView.setBackgroundColor(Color.parseColor("#00000000"))
+ }
+ }
+
+ override fun getItemCount(): Int = data?.size ?: 0
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/dialog/SweeperManualDrivingDialog.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/dialog/SweeperManualDrivingDialog.kt
new file mode 100644
index 0000000000..788f2965e6
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/dialog/SweeperManualDrivingDialog.kt
@@ -0,0 +1,70 @@
+package com.mogo.och.sweeper.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.sweeper.R
+
+/**
+ * 不带带有title, tip,confirm,cancel的dialog
+ */
+class SweeperManualDrivingDialog: BaseFloatDialog, LifecycleObserver {
+
+ private var commonConfirm : TextView? = null
+ private var commonTips : TextView? = null
+
+ private var clickListener: ClickListener? = null
+
+ constructor(builder: Builder,context: Context) : super(context) {
+ commonTips?.text = builder.tipsStr
+ commonConfirm?.text = builder.confirmStr
+ }
+
+ init{
+ setContentView(R.layout.dialog_sweeper_manual_driving)
+
+ setCanceledOnTouchOutside(false)
+
+ commonConfirm = findViewById(R.id.sweeper_common_confirm)
+ commonTips = findViewById(R.id.sweeper_common_tips)
+
+ commonConfirm?.setOnClickListener{
+ clickListener?.confirm()
+ dismiss()
+ }
+ }
+
+ fun setClickListener(clickListener: ClickListener) {
+ this.clickListener = clickListener
+ }
+
+ fun showUpgradeDialog(){
+ if(isShowing){
+ return
+ }
+ show()
+ }
+
+ interface ClickListener{
+ fun confirm()
+ }
+
+ class Builder{
+ var tipsStr:String = ""
+ var confirmStr:String = ""
+ fun tips(tips: String) : Builder{
+ this.tipsStr = tips
+ return this
+ }
+
+ fun confirmStr(commit: String) : Builder{
+ this.confirmStr = commit
+ return this
+ }
+ fun build(context: Context): SweeperManualDrivingDialog? {
+ return SweeperManualDrivingDialog(this,context)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/dialog/SweeperNoTitleCommonDialog.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/dialog/SweeperNoTitleCommonDialog.kt
new file mode 100644
index 0000000000..57618ccb5f
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/dialog/SweeperNoTitleCommonDialog.kt
@@ -0,0 +1,85 @@
+package com.mogo.och.sweeper.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.sweeper.R
+
+/**
+ * 不带带有title, tip,confirm,cancel的dialog
+ */
+class SweeperNoTitleCommonDialog: BaseFloatDialog, LifecycleObserver {
+
+ private var commonConfirm : TextView? = null
+ private var commonCancel : TextView? = null
+ private var commonTips : TextView? = null
+
+ private var clickListener: ClickListener? = null
+
+ constructor(builder: Builder,context: Context) : super(context) {
+ commonTips?.text = builder.tipsStr
+ commonCancel?.text = builder.cancelStr
+ commonConfirm?.text = builder.confirmStr
+ }
+
+ init{
+ setContentView(R.layout.dialog_sweeper_no_title)
+
+ setCanceledOnTouchOutside(true)
+
+ commonConfirm = findViewById(R.id.sweeper_common_confirm)
+ commonCancel = findViewById(R.id.sweeper_common_cancel)
+ commonTips = findViewById(R.id.sweeper_common_tips)
+
+ commonConfirm?.setOnClickListener{
+ clickListener?.confirm()
+ dismiss()
+ }
+ commonCancel?.setOnClickListener {
+ clickListener?.cancel()
+ dismiss()
+ }
+ }
+
+ fun setClickListener(clickListener: ClickListener) {
+ this.clickListener = clickListener
+ }
+
+ fun showUpgradeDialog(){
+ if(isShowing){
+ return
+ }
+ show()
+ }
+
+ interface ClickListener{
+ fun confirm()
+ fun cancel()
+ }
+
+ class Builder{
+ var tipsStr:String = ""
+ var confirmStr:String = ""
+ var cancelStr:String = ""
+ fun tips(tips: String) : Builder{
+ this.tipsStr = tips
+ return this
+ }
+
+ fun confirmStr(commit: String) : Builder{
+ this.confirmStr = commit
+ return this
+ }
+
+ fun cancelStr(cancel: String) : Builder{
+ this.cancelStr = cancel
+ return this
+ }
+
+ fun build(context: Context): SweeperNoTitleCommonDialog? {
+ return SweeperNoTitleCommonDialog(this,context)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/popwindow/MenuPopWindow.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/popwindow/MenuPopWindow.kt
new file mode 100644
index 0000000000..1f2c5ad8f0
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/popwindow/MenuPopWindow.kt
@@ -0,0 +1,91 @@
+package com.mogo.och.sweeper.ui.popwindow
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup.LayoutParams
+import android.widget.PopupWindow
+import android.widget.TextView
+import com.mogo.och.sweeper.R
+import com.mogo.och.sweeper.constant.TaskStatusEnum
+
+/**
+ * 当前任务操作菜单栏
+ */
+class MenuPopWindow : PopupWindow, View.OnClickListener{
+
+ private var mTvJumpOverTask: TextView? = null
+
+ private var mTaskJumpLineView: View? = null
+
+ private var mTvEndTask: TextView? = null
+
+ private var mTvCancelTask: TextView? = null
+
+ private var mMenuItemClickListener:OnMenuItemOnClickListener?=null
+
+ constructor(context: Context,menuItemClickListener:OnMenuItemOnClickListener) : super(context) {
+ init(context)
+ this.mMenuItemClickListener=menuItemClickListener
+ }
+
+ /**
+ * 初始化布局
+ */
+ private fun init(context: Context) {
+ setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+ var view: View = LayoutInflater.from(context).inflate(R.layout.sweeper_task_menu, null)
+ mTvJumpOverTask = view.findViewById(R.id.tvJumpOverTask)
+ mTaskJumpLineView = view.findViewById(R.id.taskJumpLineView)
+ mTvEndTask = view.findViewById(R.id.tvEndTask)
+ mTvCancelTask = view.findViewById(R.id.tvCancelTask)
+ mTvJumpOverTask?.setOnClickListener(this)
+ mTvEndTask?.setOnClickListener(this)
+ mTvCancelTask?.setOnClickListener(this)
+ width = context.resources.getDimension(R.dimen.dp_174).toInt()
+ height = LayoutParams.WRAP_CONTENT
+ contentView = view
+ isFocusable = true
+ isOutsideTouchable = true
+ }
+
+ /**
+ * 设置是否是手动任务
+ * 1:云端自动驾驶任务
+ * 2:云端手动驾驶任务
+ * 3: 运营任务
+ */
+ fun setMenuView(type: Int) {
+ if (type == 1) {
+ mTvJumpOverTask?.visibility = View.GONE
+ mTaskJumpLineView?.visibility = View.GONE
+ } else {
+ mTvJumpOverTask?.visibility = View.VISIBLE
+ mTaskJumpLineView?.visibility = View.VISIBLE
+ }
+ }
+
+ interface OnMenuItemOnClickListener {
+ fun onMenuItemClick(itemType: TaskStatusEnum)
+ }
+
+ override fun onClick(v: View) {
+ when(v.id){
+ R.id.tvJumpOverTask->{
+ mMenuItemClickListener?.onMenuItemClick(TaskStatusEnum.JUMP_OVER_SUBTASK)
+ dismiss()
+ }
+ R.id.tvEndTask->{
+ mMenuItemClickListener?.onMenuItemClick(TaskStatusEnum.END_TASK)
+ dismiss()
+ }
+ R.id.tvCancelTask->{
+ mMenuItemClickListener?.onMenuItemClick(TaskStatusEnum.CANCEL_TASK)
+ dismiss()
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/popwindow/SweeperOperatePanelPopWindow.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/popwindow/SweeperOperatePanelPopWindow.kt
new file mode 100644
index 0000000000..1004555886
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/ui/popwindow/SweeperOperatePanelPopWindow.kt
@@ -0,0 +1,59 @@
+package com.mogo.och.sweeper.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.sweeper.R
+import com.mogo.och.sweeper.callback.ICleaningModeStateCallback
+import com.mogo.och.sweeper.constant.OperateStateEnum
+import com.mogo.och.sweeper.ui.SweeperOperatePanelView
+
+/**
+ * 清扫车面板浮窗
+ */
+class SweeperOperatePanelPopWindow : PopupWindow{
+
+ private var mOperatePanelView: SweeperOperatePanelView? = null
+
+ constructor(context: Context) : super(context) {
+ init(context)
+ }
+ private fun init(context: Context) {
+ setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+ mOperatePanelView = LayoutInflater.from(context).inflate(R.layout.sweeper_popwindow_operate_panel, null) as SweeperOperatePanelView?
+ width = ViewGroup.LayoutParams.WRAP_CONTENT
+ height = ViewGroup.LayoutParams.WRAP_CONTENT
+ contentView = mOperatePanelView
+ }
+
+ /**
+ * 设置清扫模式数据
+ */
+ fun setCleanSystemState(
+ cleanSystemState: ChassisStatesOuterClass.SweeperFuTianTaskSystemStates?,
+ cleaningModeStateCallback: ICleaningModeStateCallback
+ ) {
+ mOperatePanelView?.setSweeperFutianCleanSystemState(cleanSystemState, cleaningModeStateCallback)
+ }
+
+ /**.
+ *
+ * 设置是否让popWindow消失
+ */
+ fun setIsOutsideTouchable(isOutsideTouchable:Boolean){
+ this.isFocusable = isOutsideTouchable
+ this.isOutsideTouchable = isOutsideTouchable
+ this.isTouchable=isOutsideTouchable
+ }
+
+ /**
+ * 设置是否展示状态同步中
+ */
+ fun showSyncing(operateState: OperateStateEnum){
+ mOperatePanelView?.showSyncing(operateState)
+ }
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/util/SweeperAnalyticsManager.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/util/SweeperAnalyticsManager.java
new file mode 100644
index 0000000000..bf01bbf0b5
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/util/SweeperAnalyticsManager.java
@@ -0,0 +1,149 @@
+package com.mogo.och.sweeper.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.sweeper.constant.SweeperConst;
+
+import java.util.HashMap;
+
+/**
+ * OCH sweeper埋点工具
+ *
+ * Created on 2022/3/24
+ */
+public class SweeperAnalyticsManager {
+
+ private static final class SingletonHolder {
+ private static final SweeperAnalyticsManager INSTANCE = new SweeperAnalyticsManager();
+ }
+
+ public static SweeperAnalyticsManager getInstance() {
+ return SweeperAnalyticsManager.SingletonHolder.INSTANCE;
+ }
+
+ private String mStartAutopilotKey;
+ private HashMap mStartAutopilotParams = new HashMap<>();
+
+ private Runnable startAutopilotRunnable = () -> {
+ // 15s内未开启,上报失败埋点
+ triggerStartAutopilotFailureEvent("", "15s后app等待超时");
+ };
+
+ public void triggerStartAutopilotFailureEventByAdas(String failCode, String failMsg){
+ removeWaitingCallback();
+ triggerStartAutopilotFailureEvent(failCode, failMsg);
+ }
+
+ private void triggerStartAutopilotFailureEvent(String failCode, String failMsg){
+ if (mStartAutopilotParams.isEmpty()) return;
+
+ CallerLogger.INSTANCE.e( M_SWEEPER + "triggerStartAutopilotFailureEvent", failMsg );
+
+ if (CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState() !=
+ IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING){
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_FAILURE_CODE, failCode);
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_FAILURE_MSG, failMsg);
+ }
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_RESULT
+ , CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState() ==
+ IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING);
+
+ MogoAnalyticUtils.INSTANCE.track(mStartAutopilotKey, mStartAutopilotParams);
+
+ clearStartAutopilotParams();//清空参数数据,防止误传
+ }
+
+ private void removeWaitingCallback() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ if (startAutopilotRunnable != null) {
+ UiThreadHandler.removeCallbacks(startAutopilotRunnable);
+ }
+ }
+ }
+
+ public void clearStartAutopilotFailureMSG(){
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_FAILURE_CODE, "");
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_FAILURE_MSG, "");
+ }
+
+ private void clearStartAutopilotParams(){
+ mStartAutopilotParams.clear();
+ }
+
+ /**
+ * 触发'开启自动驾驶'埋点流程
+ * 开启自动驾驶,15s内成功则发送成功埋点,否则发送失败埋点
+ * @param restart false(点击'滑动出发'启动)/true(接管后点击'自动驾驶'按钮启动)
+ * @param send 是否直接发送埋点(15s内开启成功则直接发送成功埋点)
+ */
+ public void triggerStartAutopilotEvent(
+ boolean restart, boolean send, String startName, String endName, int lineId) {
+ mStartAutopilotKey = restart ?
+ SweeperConst.EVENT_KEY_RESTART_AUTOPILOT : SweeperConst.EVENT_KEY_START_SERVICE;
+ String sn = MoGoAiCloudClientConfig.getInstance().getSn();
+ String plateNum = AppConfigInfo.INSTANCE.getPlateNumber();
+ String dateTime = DateTimeUtils.getTimeText(
+ System.currentTimeMillis(), DateTimeUtils.yyyy_MM_dd_HH_mm_ss);
+
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_SN, sn);
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_PLATE_NUM, TextUtils.isEmpty(plateNum) ? "" : plateNum);
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_ENV_ONLINE,
+ DebugConfig.getNetMode() == DebugConfig.NET_MODE_RELEASE ? true : false);
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_TIME, dateTime);
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_NAME, startName);
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_END_NAME, endName);
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_LINE_ID, lineId);
+
+ if (send) {
+ if (mStartAutopilotParams.isEmpty()) return;
+ // 开启成功,上报埋点
+ clearStartAutopilotFailureMSG();
+ removeWaitingCallback();
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_RESULT, true);
+ MogoAnalyticUtils.INSTANCE.track(mStartAutopilotKey, mStartAutopilotParams);
+
+ clearStartAutopilotParams();//清空参数数据,防止误传
+ } else {
+ UiThreadHandler.postDelayed(startAutopilotRunnable, SweeperConst.LOOP_PERIOD_15S);
+ }
+ }
+
+ /**
+ * 触发"无法开启自驾已知异常"埋点
+ * @param startName
+ * @param endName
+ * @param lineId
+ */
+ public void triggerUnableStartAPReasonEvent(String startName, String endName, int lineId,
+ String reason) {
+ String sn = MoGoAiCloudClientConfig.getInstance().getSn();
+ String plateNum = AppConfigInfo.INSTANCE.getPlateNumber();
+ String dateTime = DateTimeUtils.getTimeText(
+ System.currentTimeMillis(), DateTimeUtils.yyyy_MM_dd_HH_mm_ss);
+
+ HashMap params = new HashMap<>();
+
+ params.put(SweeperConst.EVENT_PARAM_SN, sn);
+ params.put(SweeperConst.EVENT_PARAM_PLATE_NUM, TextUtils.isEmpty(plateNum) ? "" : plateNum);
+ params.put(SweeperConst.EVENT_PARAM_ENV_ONLINE,
+ DebugConfig.getNetMode() == DebugConfig.NET_MODE_RELEASE ? true : false);
+ params.put(SweeperConst.EVENT_PARAM_TIME, dateTime);
+ params.put(SweeperConst.EVENT_PARAM_START_NAME, startName);
+ params.put(SweeperConst.EVENT_PARAM_END_NAME, endName);
+ params.put(SweeperConst.EVENT_PARAM_LINE_ID, lineId);
+ params.put(SweeperConst.EVENT_PARAM_UNABLE_START_REASON, reason);
+ MogoAnalyticUtils.INSTANCE.track(SweeperConst.EVENT_KEY_AP_UNABLE_START_REASON, params);
+ }
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/util/SweeperFutianCmdUtil.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/util/SweeperFutianCmdUtil.java
new file mode 100644
index 0000000000..79932ae4d2
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/util/SweeperFutianCmdUtil.java
@@ -0,0 +1,202 @@
+package com.mogo.och.sweeper.util;
+
+import chassis.ChassisStatesOuterClass;
+import chassis.SpecialVehicleTaskCmdOuterClass;
+
+/**
+ * 清扫车-福田,构建业务命令数据的工具类
+ */
+public class SweeperFutianCmdUtil {
+ public static final int CLEAN_WORK_OPEN = 1; //清扫作业-开启
+ public static final int CLEAN_WORK_CLOSE = 2;//清扫作业-关闭
+ public static final int CLEAN_MODE_PURE_SWEEP = 1;//作业模式-纯扫
+ public static final int CLEAN_MODE_WASH_SWEEP = 2;//作业模式-洗扫
+ public static final int CLEAN_MODE_PURE_WASH = 3;//作业模式-纯洗
+ public static final int CLEAN_MODE_PURE_DRAW = 4;//作业模式-纯吸
+ public static final int CLEAN_MODE_CLOSE = 5;//作业模式-关闭
+ public static final int CLEAN_DIRECTION_BOTH_SIDE = 1;//清扫方向-两侧
+ public static final int CLEAN_DIRECTION_LEFT_SIDE = 2;//清扫方向-左侧
+ public static final int CLEAN_DIRECTION_RIGHT_SIDE = 3;//清扫方向-右侧
+ public static final int CLEAN_DIRECTION_CLOSE = 4;//清扫方向-关闭
+ public static final int CLEAN_INTENSITY_STRAND = 1;//作业强度-标准
+ public static final int CLEAN_INTENSITY_STRONG = 2;//作业强度-加强
+
+ /**
+ * 清扫作业:打开
+ *
+ * @return
+ */
+ public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanWorkStartCmd() {
+ return buildCleanWorkCmd(CLEAN_WORK_OPEN);
+ }
+
+ /**
+ * 清扫作业:关闭
+ *
+ * @return
+ */
+ public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanWorkStopCmd() {
+ return buildCleanWorkCmd(CLEAN_WORK_CLOSE);
+ }
+
+
+ private static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanWorkCmd(int startOrStop) {
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder();
+ builder.setCleanOpenRequirement(startOrStop);
+ return buildTaskCmd(builder.build());
+ }
+
+ /**
+ * 作业模式:传入具体的模式对应的值
+ *
+ * @param value
+ * @return
+ */
+ public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanModeCmd(int value) {
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder();
+ builder.setCleanModeRequirement(value);
+ return buildTaskCmd(builder.build());
+ }
+
+ /**
+ * 作业模式:纯吸
+ *
+ * @return
+ */
+ public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanModePureDrawCmd() {
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder();
+ builder.setCleanModeRequirement(CLEAN_MODE_PURE_DRAW);
+ //不用设置作业方向,自动设置作业强度为:标准
+ builder.setCleanIntensityRequirement(CLEAN_INTENSITY_STRAND);
+ return buildTaskCmd(builder.build());
+ }
+
+ /**
+ * 作业模式:关闭作业模式
+ *
+ * @return
+ */
+ public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanModeCloseCmd() {
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder();
+ builder.setCleanModeRequirement(CLEAN_MODE_CLOSE);
+ //关闭清扫方向,待下次在选择
+ builder.setCleanDirectionRequirement(CLEAN_DIRECTION_CLOSE);
+ //自动设置作业强度为:标准
+ builder.setCleanIntensityRequirement(CLEAN_INTENSITY_STRAND);
+ return buildTaskCmd(builder.build());
+ }
+
+ /**
+ * 作业方向:根据具体的方向传入具体的值
+ *
+ * @param value
+ * @return
+ */
+ public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanDirectionCmd(int value) {
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder();
+ builder.setCleanDirectionRequirement(value);
+ builder.setCleanIntensityRequirement(CLEAN_INTENSITY_STRAND);
+ // 同时作业强度默认:标准
+ return buildTaskCmd(builder.build());
+ }
+
+ /**
+ * 作业方向:关闭作业方向
+ *
+ * @return
+ */
+ public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanDirectionCloseCmd() {
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder();
+ builder.setCleanDirectionRequirement(CLEAN_DIRECTION_CLOSE);
+ //重置作业强度为标准
+ builder.setCleanIntensityRequirement(CLEAN_INTENSITY_STRAND);
+ return buildTaskCmd(builder.build());
+ }
+
+ /**
+ * 作业强度:传入具体的值
+ *
+ * @param value
+ * @return
+ */
+ public static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildCleanIntensityCmd(int value) {
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder();
+ builder.setCleanIntensityRequirement(value);
+ return buildTaskCmd(builder.build());
+ }
+
+ private static SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd buildTaskCmd(
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd fuTianCleanCmd) {
+ return SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd.newBuilder()
+ .setRoboSweeperFutianCleanCmd(fuTianCleanCmd).build();
+ }
+
+ /**
+ * 判断是否有作业模式
+ * @param cleanSystemState
+ * @return true:没有作业模式 false:有作业模式
+ */
+ public static boolean checkIfCleanMode(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState){
+ return (!cleanSystemState.getSecuModWashSweepSts()&&!cleanSystemState.getSecuModWashSts()&&!cleanSystemState.getSecuWorkTonSts())&&
+ (!cleanSystemState.getSecuWorkLeftSts()&&!cleanSystemState.getSecuWorkRightSts()&&!cleanSystemState.getSecuWorkOnBothsidesSts());
+ }
+
+ /**
+ * 判断是否有清扫方向
+ * @param cleanSystemState
+ * @return true:没有清扫方向 false:有清扫方向
+ */
+ public static boolean checkIfCleanDirection(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState){
+ return !cleanSystemState.getSecuWorkLeftSts()&&!cleanSystemState.getSecuWorkRightSts()&&!cleanSystemState.getSecuWorkOnBothsidesSts();
+ }
+ /**
+ * 判断是否有作业强度
+ * @param cleanSystemState
+ * @return true:没有作业强度 false:有作业强度
+ */
+ public static boolean checkIfCleanIntensity(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState){
+ return !cleanSystemState.getSecuWorkStandSts()&&!cleanSystemState.getSecuWorkStrongSts();
+ }
+ /**
+ * 判断是否纯扫模式
+ *
+ * @param cleanSystemState
+ * @return
+ */
+ public static boolean checkIfCleanModePureSweep(ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState) {
+ // 作业模式状态
+ // 洗扫
+ boolean clean_mode_wash_sweep = cleanSystemState.getSecuModWashSweepSts();
+ // 纯洗
+ boolean clean_mode_pure_wash = cleanSystemState.getSecuModWashSts();
+ // 纯吸
+ boolean clean_mode_pure_draw = cleanSystemState.getSecuWorkTonSts();
+
+ // 清扫方向状态
+ // 左侧
+ boolean clean_direction_left_side = cleanSystemState.getSecuWorkLeftSts();
+ // 右侧
+ boolean clean_direction_right_side = cleanSystemState.getSecuWorkRightSts();
+ // 两侧
+ boolean clean_direction_both_side = cleanSystemState.getSecuWorkOnBothsidesSts();
+
+ // 纯扫 模式判断:不是另外其他3个模式,同时有清扫方向,说明开启了纯扫模式
+ boolean clean_mode_pure_sweep = (clean_direction_left_side || clean_direction_right_side || clean_direction_both_side)
+ && (!clean_mode_wash_sweep && !clean_mode_pure_wash && !clean_mode_pure_draw);
+ return clean_mode_pure_sweep;
+ }
+ /**
+ * 构建底盘Mock数据
+ *
+ * @return
+ */
+ public static ChassisStatesOuterClass.SweeperFuTianTaskSystemStates buildSweeperFuTionCleanSystemStateMockData() {
+ ChassisStatesOuterClass.SweeperFuTianTaskSystemStates.Builder builder = ChassisStatesOuterClass.SweeperFuTianTaskSystemStates.newBuilder();
+ builder.setSecuMotWorkSts(true);
+ builder.setSecuModWashSts(true);
+ builder.setSecuWorkOnBothsidesSts(true);
+ builder.setSecuWorkStrongSts(true);
+ return builder.build();
+ }
+
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/util/SweeperMapAssetStyleUtil.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/util/SweeperMapAssetStyleUtil.java
new file mode 100644
index 0000000000..5f9f1db28e
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/util/SweeperMapAssetStyleUtil.java
@@ -0,0 +1,61 @@
+package com.mogo.och.sweeper.util;
+
+
+import android.content.Context;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author donghongyu
+ * @date 12/18/20 5:37 PM
+ */
+public class SweeperMapAssetStyleUtil {
+
+ public static byte[] getAssetsStyle(Context context,String fileName) {
+ byte[] buffer1 = null;
+ InputStream is1 = null;
+ try {
+ is1 = context.getResources().getAssets().open(fileName); //eg. over_view_style.data
+ int lenght1 = is1.available();
+ buffer1 = new byte[lenght1];
+ is1.read(buffer1);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (is1 != null) {
+ is1.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return buffer1;
+ }
+
+
+ public static byte[] getAssetsExtraStyle(Context context, String fileName) {
+ byte[] buffer1 = null;
+ InputStream is1 = null;
+ try {
+ is1 = context.getResources().getAssets().open(fileName); //eg. over_view_style_extra.data
+ int lenght1 = is1.available();
+ buffer1 = new byte[lenght1];
+ is1.read(buffer1);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (is1 != null) {
+ is1.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return buffer1;
+ }
+
+
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/util/SweeperTrajectoryManager.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/util/SweeperTrajectoryManager.java
new file mode 100644
index 0000000000..878cb08b78
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/util/SweeperTrajectoryManager.java
@@ -0,0 +1,183 @@
+package com.mogo.och.sweeper.util;
+
+import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters;
+import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager;
+import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
+import com.mogo.eagle.core.utilcode.util.GsonUtils;
+import com.mogo.och.sweeper.bean.SweeperSubTaskDetailBean;
+import com.mogo.och.sweeper.constant.SweeperConst;
+
+import java.util.concurrent.TimeUnit;
+
+import androidx.annotation.Nullable;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+import mogo_msg.MogoReportMsg;
+
+import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_SWEEPER;
+
+/**
+ * Bus轨迹管理:给MEC下发用于轨迹下载的信息
+ * Created on 2022/6/23
+ */
+public class SweeperTrajectoryManager {
+ private static final String TAG = SweeperTrajectoryManager.class.getSimpleName();
+
+ private static final class SingletonHolder {
+ private static final SweeperTrajectoryManager INSTANCE = new SweeperTrajectoryManager();
+ }
+
+ public static SweeperTrajectoryManager getInstance() {
+ return SweeperTrajectoryManager.SingletonHolder.INSTANCE;
+ }
+
+ private AutopilotControlParameters.AutoPilotLine mAutoPilotLine = null;
+ private Disposable mSendReqDisposable = null;
+
+ public SweeperTrajectoryManager() {
+ mAutoPilotLine = new AutopilotControlParameters.AutoPilotLine(-1,
+ "", "", "", "", 0, "",
+ "", "", "", "", 0);
+ }
+
+ /**
+ * 同步Bus路线信息
+ */
+ public void syncTrajectoryInfo(SweeperSubTaskDetailBean sweeperSubTaskDetailBean) {
+ if (sweeperSubTaskDetailBean != null) {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "syncTrajectoryInfo() start.");
+ startTrajReqLoop(sweeperSubTaskDetailBean);
+ } else {
+ // 无路线信息or当前未在始发站
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "syncTrajectoryInfo() stop.");
+ stopTrajReqLoop();
+ }
+ }
+
+ /**
+ * 接口MEC反馈的常规信息(MAP v2.5.0新增轨迹相关信息)
+ *
+ * @param guardianInfo
+ */
+ public void onAutopilotGuardian(@Nullable MogoReportMsg.MogoReportMessage guardianInfo) {
+ if (guardianInfo == null || !guardianInfo.hasCode()) return;
+ if ("ISYS_INIT_TRAJECTORY_START".equals(guardianInfo.getCode())) {
+ // 1. 轨迹管理_轨迹开始下载(本地已有对应轨迹也触发)
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onAutopilotGuardian() 轨迹开始下载");
+ // ToastUtils.showShort("轨迹开始下载");
+ stopTrajReqLoop();
+ } else if ("ISYS_INIT_TRAJECTORY_SUCCESS".equals(guardianInfo.getCode())) {
+ // 2. 轨迹管理_轨迹下载成功(本地已有对应轨迹也触发)
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onAutopilotGuardian() 轨迹下载成功");
+ // ToastUtils.showShort("轨迹下载成功");
+ stopTrajReqLoop();
+ } else if ("ISYS_INIT_TRAJECTORY_FAILURE".equals(guardianInfo.getCode())) {
+ // 3. 轨迹管理_轨迹下载失败,本地无对应轨迹
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onAutopilotGuardian() " +
+ "轨迹下载失败,本地无对应轨迹");
+ // ToastUtils.showShort("轨迹下载失败,本地无对应轨迹");
+ } else if ("ISYS_INIT_TRAJECTORY_WARNING".equals(guardianInfo.getCode())) {
+ // 4. 轨迹管理_轨迹下载失败,本地有对应轨迹,认为成功
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onAutopilotGuardian() " +
+ "轨迹下载失败,本地有对应轨迹,认为成功");
+ // ToastUtils.showShort("轨迹下载失败,本地有对应轨迹,认为成功");
+ } else if ("ISYS_INIT_TRAJECTORY_TIMEOUT".equals(guardianInfo.getCode())) {
+ // 5. 轨迹管理_轨迹下载超时
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "onAutopilotGuardian() 轨迹下载超时");
+ // ToastUtils.showShort("轨迹下载超时");
+ }
+ }
+
+ private void setupAutoPilotLine(SweeperSubTaskDetailBean subTaskDetail) {
+ if (subTaskDetail == null) {
+ CallerLogger.INSTANCE.e(M_SWEEPER + TAG, "setupAutoPilotLine(): routesResult is null.");
+ return;
+ } else {
+ mAutoPilotLine = new AutopilotControlParameters.AutoPilotLine(subTaskDetail.getLineId(),
+ subTaskDetail.getCsvFileUrl(), subTaskDetail.getCsvFileMd5(),
+ subTaskDetail.getTxtFileUrl(), subTaskDetail.getTxtFileMd5(),
+ subTaskDetail.getPublishTime(), subTaskDetail.getCarModel(),
+ subTaskDetail.getCsvFileUrlDPQP(), subTaskDetail.getCsvFileMd5DPQP(),
+ subTaskDetail.getTxtFileUrlDPQP(), subTaskDetail.getTxtFileMd5DPQP(),
+ subTaskDetail.getPublishTimeDPQP());
+ }
+ }
+
+ private void clearAutoPilotLine() {
+ if (mAutoPilotLine == null) return;
+ mAutoPilotLine.setLineId(-1);
+ mAutoPilotLine.setTrajUrl("");
+ mAutoPilotLine.setTrajMd5("");
+ mAutoPilotLine.setStopUrl("");
+ mAutoPilotLine.setStopMd5("");
+ mAutoPilotLine.setTimestamp(0);
+ mAutoPilotLine.setVehicleModel("");
+ mAutoPilotLine.setTrajUrl_dpqp("");
+ mAutoPilotLine.setTrajMd5_dpqp("");
+ mAutoPilotLine.setStopUrl_dpqp("");
+ mAutoPilotLine.setStopMd5_dpqp("");
+ mAutoPilotLine.setTimestamp_dpqp(0);
+ }
+
+ private void startTrajReqLoop(SweeperSubTaskDetailBean sweeperSubTaskDetailBean) {
+ if (mSendReqDisposable != null && !mSendReqDisposable.isDisposed()) {
+ return;
+ }
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "startTrajReqLoop()");
+ setupAutoPilotLine(sweeperSubTaskDetailBean);
+ mSendReqDisposable = Observable.interval(SweeperConst.LOOP_DELAY,
+ SweeperConst.LOOP_PERIOD_10S, TimeUnit.MILLISECONDS)
+ .map((aLong -> aLong + 1))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(aLong -> {
+ if (aLong > SweeperConst.LOOP_SEND_TRAJ_TIMES) {
+ stopTrajReqLoop();
+ return;
+ }
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "loop sendTrajectoryReq: " + aLong);
+ sendTrajectoryReq();
+ });
+ }
+
+ public void stopTrajReqLoop() {
+ if (mSendReqDisposable != null) {
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "stopTrajReqLoop()");
+ mSendReqDisposable.dispose();
+ mSendReqDisposable = null;
+ clearAutoPilotLine();
+ }
+ }
+
+ private void sendTrajectoryReq() {
+ if (mAutoPilotLine == null) {
+ CallerLogger.INSTANCE.e(M_SWEEPER + TAG, "sendTrajectoryReq(): mAutoPilotLine is null!!!");
+ return;
+ }
+
+ // TODO: 2022/6/24
+ // test1
+// mAutoPilotLine.setLineId(148);
+// mAutoPilotLine.setTrajUrl("http://file-qa.zhidaozhixing.com/fileServer/upload/downloadFileStream?key=fileServer/online_car_hailing/e27c20c2da32481021d934c3ef084536/traj_148.csv");
+// mAutoPilotLine.setTrajMd5("e27c20c2da32481021d934c3ef084536");
+// mAutoPilotLine.setStopUrl("http://file-qa.zhidaozhixing.com/fileServer/upload/downloadFileStream?key=fileServer/online_car_hailing/6224c9dd2c0e2bd990c6482c0464de45/stop_148.txt");
+// mAutoPilotLine.setStopMd5("6224c9dd2c0e2bd990c6482c0464de45");
+// mAutoPilotLine.setTimestamp(1654596000000L); //20220607 18:00
+// mAutoPilotLine.setVehicleModel("红旗H9");
+
+ // test2
+// mAutoPilotLine.setLineId(148);
+// mAutoPilotLine.setTrajUrl("http://file-qa.zhidaozhixing.com/fileServer/upload/downloadFileStream?key=fileServer/online_car_hailing/8654497cf918be461a59c7ad8e22920d/traj_148.csv");
+// mAutoPilotLine.setTrajMd5("8654497cf918be461a59c7ad8e22920d");
+// mAutoPilotLine.setStopUrl("http://file-qa.zhidaozhixing.com/fileServer/upload/downloadFileStream?key=fileServer/online_car_hailing/1bb098b244922649bf3e7bada0d3950f/stop_148.txt");
+// mAutoPilotLine.setStopMd5("1bb098b244922649bf3e7bada0d3950f");
+// mAutoPilotLine.setTimestamp(1654761600000L); //20220609 16:00
+// mAutoPilotLine.setVehicleModel("红旗H9");
+
+ CallerAutoPilotControlManager.INSTANCE.sendTrajectoryDownloadReq(mAutoPilotLine);
+ CallerLogger.INSTANCE.d(M_SWEEPER + TAG, "sendTrajectoryReq(): "
+ + GsonUtils.toJson(mAutoPilotLine));
+ }
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/BusArcView.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/BusArcView.java
new file mode 100644
index 0000000000..d559214b15
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/BusArcView.java
@@ -0,0 +1,190 @@
+package com.mogo.och.sweeper.view;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Typeface;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import com.mogo.och.sweeper.R;
+
+/**
+ * created by wujifei on 2021/3/24 16:20
+ * describe:
+ */
+public class BusArcView extends View {
+
+ //中心的文字描述
+ private String mDes = "KM/H";
+ //根据数据显示的圆弧Paint
+ private Paint mArcPaint;
+ //圆弧颜色
+ private int mArcColor;
+ //圆弧的画笔的宽度
+ private float mStrokeWith = getResources().getDimension(R.dimen.sweeper_ext_arcView_stroke_with);
+ //文字描述的paint
+ private Paint mTextPaint;
+
+ //当前进度夹角大小
+ private float mIncludedAngle = 0;
+ //当前数据
+ private int currentValue;
+ //最大数据
+ private int maxValue = 240;
+ //圆弧背景的开始和结束间的夹角大小
+ private float mAngle = 270;
+ //上次绘制圆弧夹角
+ private float lastAngle = 0;
+
+ public BusArcView(Context context) {
+ this(context, null);
+ }
+
+ public BusArcView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public BusArcView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ //初始化paint
+ initPaint();
+ //绘制弧度
+ drawArc(canvas);
+ //绘制文本
+ drawText(canvas);
+ }
+
+ private void drawText(Canvas canvas) {
+ Rect mRect = new Rect();
+ String mValue = String.valueOf(currentValue);
+ mTextPaint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ //绘制中心的数值
+ mTextPaint.getTextBounds(mValue, 0, mValue.length(), mRect);
+ canvas.drawText(mValue, getWidth() / 2, getHeight() / 2 + mRect.height() / 2 - 10, mTextPaint);
+
+ mTextPaint.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
+ //绘制中心文字描述
+ mTextPaint.setTextSize(getResources().getDimension(R.dimen.sweeper_ext_arcView_des_text_size));
+ mTextPaint.getTextBounds(mDes, 0, mDes.length(), mRect);
+ canvas.drawText(mDes, getWidth() / 2, getHeight() * 17 / 20 + mRect.height() / 2, mTextPaint);
+ }
+
+ private void drawArc(Canvas canvas) {
+ //绘制圆弧背景
+ RectF mRectF = new RectF(mStrokeWith, mStrokeWith, getWidth() - mStrokeWith, getHeight() - mStrokeWith);
+ canvas.drawArc(mRectF, 135, mAngle, false, mArcPaint);
+
+ //绘制当前数值对应的圆弧
+ mArcPaint.setColor(mArcColor);
+ //根据当前数据绘制对应的圆弧
+ canvas.drawArc(mRectF, 135, mIncludedAngle, false, mArcPaint);
+ }
+
+ private void initPaint() {
+ //圆弧的paint
+ mArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ //抗锯齿
+ mArcPaint.setAntiAlias(true);
+ mArcPaint.setColor(Color.parseColor("#151D4C"));
+ //设置透明度(数值为0-255)
+ mArcPaint.setAlpha(100);
+ //设置画笔的画出的形状
+ mArcPaint.setStrokeJoin(Paint.Join.ROUND);
+ mArcPaint.setStrokeCap(Paint.Cap.ROUND);
+ //设置画笔类型
+ mArcPaint.setStyle(Paint.Style.STROKE);
+ //画笔宽度
+ mArcPaint.setStrokeWidth(mStrokeWith);
+
+ //中心文字的paint
+ mTextPaint = new Paint();
+ mTextPaint.setAntiAlias(true);
+ mTextPaint.setColor(Color.parseColor("#FFFFFF"));
+ //设置文本的对齐方式
+ mTextPaint.setTextAlign(Paint.Align.CENTER);
+ //mTextPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.dp_12));
+ mTextPaint.setTextSize(getResources().getDimension(R.dimen.sweeper_ext_arcView_center_text_size));
+
+ }
+
+
+ /**
+ * 为绘制弧度及数据设置动画
+ *
+ * @param startAngle 开始的弧度
+ * @param currentAngle 需要绘制的弧度
+ * @param time 动画执行的时长
+ */
+ private void setAnimation(float startAngle, float currentAngle, int time) {
+ //绘制当前数据对应的圆弧的动画效果
+ ValueAnimator progressAnimator = ValueAnimator.ofFloat(startAngle, currentAngle);
+ progressAnimator.setDuration(time);
+ progressAnimator.setTarget(mIncludedAngle);
+ progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mIncludedAngle = (float) animation.getAnimatedValue();
+ //重新绘制,不然不会出现效果
+ postInvalidate();
+ }
+ });
+ //开始执行动画
+ progressAnimator.start();
+ }
+
+
+ /**
+ * 设置弧形颜色
+ *
+ * @param value 颜色值
+ */
+ public void setArcColor(int value) {
+ mArcColor = value;
+ }
+
+ /**
+ * 设置数据
+ *
+ * @param value 当前绘制的值
+ */
+ public void setValues(int value) {
+ //完全覆盖
+ if (value > maxValue) {
+ value = maxValue;
+ }
+ if (value < 0) {
+ value = 0;
+ }
+ currentValue = value;
+ //计算弧度比重
+ float scale = (float) currentValue / maxValue;
+ //计算弧度
+ float currentAngle = scale * mAngle;
+ //开始执行动画
+ setAnimation(lastAngle, currentAngle, 1000);
+ lastAngle = currentAngle;
+ //重新绘制
+ postInvalidate();
+ }
+
+
+ private float dp2px(float dp) {
+ DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
+ return dp * metrics.density;
+ }
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/LegendItemView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/LegendItemView.kt
new file mode 100644
index 0000000000..9a6e360b14
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/LegendItemView.kt
@@ -0,0 +1,32 @@
+package com.mogo.och.sweeper.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.LinearLayout
+import com.mogo.och.sweeper.R
+import kotlinx.android.synthetic.main.sweeper_item_legend.view.*
+
+/**
+ * 任务路线全览图图例
+ */
+class LegendItemView:LinearLayout {
+ constructor(context: Context) : super(context) {}
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ initView(context)
+ }
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {}
+
+ private fun initView(context: Context) {
+ LayoutInflater.from(context).inflate(R.layout.sweeper_item_legend, this)
+ }
+
+ /**
+ * 设置数据
+ */
+ fun setData(resId:Int,text:String){
+ sweeperLegendIcon.setImageResource(resId)
+ sweeperLegendText.text = text
+ }
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/NoTouchConstraintLayout.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/NoTouchConstraintLayout.java
new file mode 100644
index 0000000000..2bdbd938e0
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/NoTouchConstraintLayout.java
@@ -0,0 +1,45 @@
+package com.mogo.och.sweeper.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+/**
+ * 强制拦截所有touch时间的约束布局
+ *
+ * @author tongchenfei
+ */
+public class NoTouchConstraintLayout extends ConstraintLayout {
+ private boolean interceptTouchEvent = false;
+
+ public NoTouchConstraintLayout(Context context) {
+ super(context);
+ }
+
+ public NoTouchConstraintLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public NoTouchConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (interceptTouchEvent) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 设置事件拦截
+ *
+ * @param interceptTouchEvent
+ */
+ public void setInterceptTouchEvent(boolean interceptTouchEvent) {
+ this.interceptTouchEvent = interceptTouchEvent;
+ }
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/NoTouchFrameLayout.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/NoTouchFrameLayout.java
new file mode 100644
index 0000000000..48b45b27af
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/NoTouchFrameLayout.java
@@ -0,0 +1,30 @@
+package com.mogo.och.sweeper.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+
+/**
+ * 强制拦截所有touch时间的约束布局
+ *
+ * @author tongchenfei
+ */
+public class NoTouchFrameLayout extends FrameLayout {
+ public NoTouchFrameLayout(Context context) {
+ super(context);
+ }
+
+ public NoTouchFrameLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public NoTouchFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return false;
+ }
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SlidePanelView.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SlidePanelView.java
new file mode 100644
index 0000000000..f7171bce89
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SlidePanelView.java
@@ -0,0 +1,270 @@
+package com.mogo.och.sweeper.view;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+
+import androidx.annotation.Nullable;
+
+import com.mogo.och.sweeper.R;
+
+/**
+ * 滑块滑动面板
+ *
+ * @author tongchenfei
+ */
+public class SlidePanelView extends View {
+ private static final String TAG = "SlidePanelView";
+
+ public SlidePanelView(Context context) {
+ this(context, null);
+ }
+
+ public SlidePanelView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SlidePanelView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.SlidePanelView);
+ textSize = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_textSize, textSize);
+ BLOCK_START_X = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_BLOCK_START_X, BLOCK_START_X);
+ BLOCK_START_Y = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_BLOCK_START_Y, BLOCK_START_Y);
+ NORMAL_TEXT_MARGIN_LEFT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_NORMAL_TEXT_MARGIN_LEFT, NORMAL_TEXT_MARGIN_LEFT);
+ NORMAL_TEXT_MARGIN_RIGHT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_NORMAL_TEXT_MARGIN_RIGHT, NORMAL_TEXT_MARGIN_RIGHT);
+ SHORT_TEXT_MARGIN_LEFT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_SHORT_TEXT_MARGIN_LEFT, SHORT_TEXT_MARGIN_LEFT);
+ SHORT_TEXT_MARGIN_RIGHT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_SHORT_TEXT_MARGIN_RIGHT, SHORT_TEXT_MARGIN_RIGHT);
+ init();
+ }
+
+ private final Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Paint blockPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ private static int textSize = 40;
+ private static int BLOCK_START_X = 15;
+ private static int BLOCK_START_Y = 15;
+ private static int NORMAL_TEXT_MARGIN_LEFT = 40;
+ private static int NORMAL_TEXT_MARGIN_RIGHT = 60;
+ private static int SHORT_TEXT_MARGIN_LEFT = 60;
+ private static int SHORT_TEXT_MARGIN_RIGHT = 70;
+
+ private int textMarginLeft = NORMAL_TEXT_MARGIN_LEFT;
+ private int textMarginRight = NORMAL_TEXT_MARGIN_RIGHT;
+
+ private OnSlidePanelMoveToEndListener moveToEndListener;
+
+ private int blockWidth = 0;
+ private int blockOffset = 0;
+
+ private float lastX;
+ private boolean isToEnd = false;
+
+ private static final String STRING_SLIDE_TO_RIGHT = "向右滑动";
+ private RectF bgRectF;
+ private Bitmap bmBlock;
+
+ private final Matrix gradientMatrix = new Matrix();
+ private float matrixTranslate;
+ private final Rect textRect = new Rect();
+ private LinearGradient textGradient;
+
+ private ObjectAnimator matrixAnim;
+
+ private String blockText = STRING_SLIDE_TO_RIGHT;
+ private Paint.FontMetrics blockTextMetrics = new Paint.FontMetrics();
+
+ private static final int GRADIENT_OFFSET = 200;
+
+ public void setOnSlidePanelMoveToEndListener(OnSlidePanelMoveToEndListener moveToEndListener) {
+ this.moveToEndListener = moveToEndListener;
+ }
+
+ private void setBlockOffset(int blockOffset) {
+ this.blockOffset = blockOffset;
+ invalidate();
+ }
+
+ private void setMatrixTranslate(float matrixTranslate) {
+ this.matrixTranslate = matrixTranslate;
+ invalidate();
+ }
+
+ public void setText(String text) {
+ this.blockText = text;
+ requestLayout();
+ invalidate();
+ }
+
+ private void init() {
+ bgRectF = new RectF(0, 0, 0, 0);
+ bgPaint.setColor(Color.parseColor("#CC0F1325"));
+ bgPaint.setStyle(Paint.Style.FILL);
+
+ textPaint.setStyle(Paint.Style.FILL);
+ textPaint.setTextSize(textSize);
+ textPaint.setTextAlign(Paint.Align.LEFT);
+ textGradient = new LinearGradient(-GRADIENT_OFFSET, 0, 0, 0, new int[]{0x33ffffff, 0xffffffff, 0x33ffffff}, null, Shader.TileMode.CLAMP);
+ textGradient.setLocalMatrix(gradientMatrix);
+ textPaint.setShader(textGradient);
+ textPaint.getFontMetrics(blockTextMetrics);
+
+ bmBlock = BitmapFactory.decodeResource(getResources(), R.drawable.sweeper_base_slide_block);
+ blockWidth = bmBlock.getWidth();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ int widthSize;
+ int heightSize;
+
+ if (blockText.length() < 5) {
+ textMarginLeft = SHORT_TEXT_MARGIN_LEFT;
+ textMarginRight = SHORT_TEXT_MARGIN_RIGHT;
+ } else {
+ textMarginLeft = NORMAL_TEXT_MARGIN_LEFT;
+ textMarginRight = NORMAL_TEXT_MARGIN_RIGHT;
+ }
+
+ if (widthMode == MeasureSpec.AT_MOST) {
+ // 宽度根据图片大小,字符串长度,各种间隔确定
+ // 高度根据图片大小和上下间隔确定
+ textPaint.getTextBounds(blockText, 0, blockText.length(), textRect);
+ widthSize = BLOCK_START_X * 2 + bmBlock.getWidth() + textMarginLeft + textMarginRight + textRect.width();
+ heightSize = BLOCK_START_Y * 2 + bmBlock.getHeight();
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
+ }
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ private float textOffset = 0;
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ if (bgRectF != null){
+ bgRectF.left = 0;
+ bgRectF.top = 0;
+ bgRectF.right = w;
+ bgRectF.bottom = h;
+ }
+
+ if (matrixAnim != null) {
+ matrixAnim.cancel();
+ }
+ textOffset = (getHeight() - blockTextMetrics.ascent - blockTextMetrics.descent) / 2;
+ matrixAnim = ObjectAnimator.ofFloat(this, "matrixTranslate", 0, w + GRADIENT_OFFSET).setDuration(2000);
+ matrixAnim.setRepeatCount(ValueAnimator.INFINITE);
+ matrixAnim.start();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (matrixAnim != null) {
+ matrixAnim.start();
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (matrixAnim != null) {
+ matrixAnim.cancel();
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ float x = event.getX();
+ float y = event.getY();
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ if (x > BLOCK_START_X + blockOffset && x < blockWidth + BLOCK_START_X + blockOffset && y > BLOCK_START_Y && y < getHeight() - BLOCK_START_Y) {
+ isToEnd = false;
+ lastX = x;
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (lastX != 0) {
+ blockOffset = (int) (x - lastX);
+ if (blockOffset < 0) {
+ blockOffset = 0;
+ }
+ if (blockOffset + BLOCK_START_X + blockWidth > getWidth()) {
+ // 超出右边界
+ blockOffset = getWidth() - BLOCK_START_X - blockWidth;
+ if (!isToEnd) {
+ isToEnd = true;
+ if (moveToEndListener != null) {
+ moveToEndListener.moveToEnd();
+ }
+ startBlockBackAnim();
+ }
+ }
+ invalidate();
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ // 执行滑块回归动画
+ if (!isToEnd) {
+ startBlockBackAnim();
+ }
+ break;
+ default:
+ break;
+ }
+
+ return true;
+ }
+
+ private void startBlockBackAnim() {
+ ObjectAnimator blockBackanimator = ObjectAnimator.ofInt(this, "blockOffset", blockOffset, 0);
+ blockBackanimator.setInterpolator(new DecelerateInterpolator());
+ blockBackanimator.setDuration(1000 * blockOffset / getWidth());
+ blockBackanimator.start();
+ lastX = 0;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ // 画背景
+ canvas.drawRoundRect(bgRectF, (float) getHeight() / 2, (float) getHeight() / 2, bgPaint);
+ // 画文字
+ gradientMatrix.setTranslate(matrixTranslate, 0);
+ textGradient.setLocalMatrix(gradientMatrix);
+ canvas.save();
+ canvas.drawText(blockText, blockWidth + BLOCK_START_X + textMarginLeft, textOffset, textPaint);
+ canvas.restore();
+ // 画滑块
+ canvas.drawBitmap(bmBlock, BLOCK_START_X + blockOffset, BLOCK_START_Y, blockPaint);
+ }
+
+ public interface OnSlidePanelMoveToEndListener {
+ /**
+ * 滑块滑到了末尾
+ */
+ void moveToEnd();
+ }
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SubTaskView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SubTaskView.kt
new file mode 100644
index 0000000000..a3d6374066
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SubTaskView.kt
@@ -0,0 +1,57 @@
+package com.mogo.och.sweeper.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.common.module.utils.DateTimeUtil
+import com.mogo.och.sweeper.R
+import com.mogo.och.sweeper.bean.SubInfo
+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: SubInfo, isSelect: Boolean = false, isLastTask: Boolean = false) {
+ tvSubTaskName.text = taskInfo.taskName
+ var mileage: String = if (taskInfo.mileage < 1000) {
+ "${taskInfo.mileage}米"
+ } else {
+ "${taskInfo.mileage / 1000F}千米"
+ }
+ val time=taskInfo.timeSpent.toLong()
+ var timeSpent=if(DateTimeUtil.secondsToHourStr(time)!=""){
+ "${DateTimeUtil.secondsToHourStr(time)}小时${DateTimeUtil.secondsToMinuteStr(time)}分钟"
+ }else{
+ "${DateTimeUtil.secondsToMinuteStr(time)}分钟"
+ }
+ tvSubTaskDesc.text = "全程约${mileage},预计耗时$timeSpent"
+ tvSubTaskName.setTextColor(if (isSelect) Color.parseColor("#3BD2FF") else Color.parseColor("#FFFFFF"))
+ if (isSelect) {
+ ivSubTaskSelect.visibility = View.VISIBLE
+ ivSubTask.visibility = View.GONE
+ } else {
+ ivSubTaskSelect.visibility = View.GONE
+ ivSubTask.visibility = View.VISIBLE
+ }
+ ivRightDownArrow.visibility = if (isLastTask) View.GONE else View.VISIBLE
+ }
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperCurrentTaskInfoView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperCurrentTaskInfoView.kt
new file mode 100644
index 0000000000..39fc24fd81
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperCurrentTaskInfoView.kt
@@ -0,0 +1,233 @@
+package com.mogo.och.sweeper.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.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
+import com.mogo.eagle.core.utilcode.util.ClickUtils
+import com.mogo.eagle.core.utilcode.util.ToastUtils
+import com.mogo.och.common.module.utils.DateTimeUtil
+import com.mogo.och.sweeper.R
+import com.mogo.och.sweeper.bean.SubInfo
+import com.mogo.och.sweeper.bean.SweeperSubTaskBean
+import com.mogo.och.sweeper.constant.SubTaskTypeEnum
+import com.mogo.och.sweeper.presenter.SweeperPresenter
+import com.mogo.och.sweeper.ui.popwindow.MenuPopWindow
+import kotlinx.android.synthetic.main.sweeper_current_task_info.view.*
+
+/**
+ * 清扫车当前任务信息展示
+ */
+class SweeperCurrentTaskInfoView : ConstraintLayout {
+ private val TAG: String = "SweeperCurrentTaskInfoView"
+
+ //当前任务操作菜单
+ private var mTaskMenuPopWindow: MenuPopWindow? = null
+ private var presenter: SweeperPresenter? = null
+ private var mCurrentPosition = 0
+ private var listTask: List? = null
+ private var mSubTaskType: SubTaskTypeEnum = SubTaskTypeEnum.AUTOPILOT_SUBTYPE
+ private var mSubTaskStatus: Int = 1
+ //当前自动驾驶状态
+ private val mCurrentAutopilotStatus = 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_current_task_info, this)
+ setEnableClickBtn(false)
+ tvStartAuto.setOnClickListener {
+ if (ClickUtils.isFastClick()){//防止重复点击
+ if (mSubTaskStatus==1){
+ ToastUtils.showLong("任务未开始无轨迹,无法启动自驾")
+ return@setOnClickListener
+ }
+ if (mSubTaskType==SubTaskTypeEnum.MANUAL_DRIVING_SUBTYPE){
+ ToastUtils.showLong("人工子任务无轨迹,无法启动自驾")
+ return@setOnClickListener
+ }
+ if (mCurrentAutopilotStatus!=IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING){
+ presenter?.startAutopilot()
+ }
+ }
+ }
+ }
+
+ /**
+ * 设置当前任务数据
+ */
+ fun setData(
+ workModePanelView: SweeperWorkModeView,
+ subTaskBean: SweeperSubTaskBean?,
+ currentPosition: Int,
+ menuItemClickListener: MenuPopWindow.OnMenuItemOnClickListener,
+ presenter: SweeperPresenter?
+ ) {
+ this.presenter = presenter
+ this.mCurrentPosition = currentPosition
+ mTaskMenuPopWindow = MenuPopWindow(context, menuItemClickListener)
+ subTaskBean?.apply {
+ this@SweeperCurrentTaskInfoView.listTask = subList
+ tvTaskName.text = taskName
+ val calendar = DateTimeUtil.formatLongToCalendar(taskStartTime)
+ tvTaskTime.text = DateTimeUtil.formatCalendarToString(calendar, DateTimeUtil.HH_mm)
+ }
+ listTask?.let {
+ mSubTaskStatus=it[currentPosition].taskStatus
+ setEnableClickBtn(mSubTaskStatus==2)
+ }
+ setCurrentData(currentPosition)
+ //任务操作菜单打开关闭处理
+ ivMore.setOnClickListener {
+ if (mTaskMenuPopWindow?.isShowing != true) {
+ mTaskMenuPopWindow?.showAsDropDown(
+ workModePanelView,
+ resources.getDimension(R.dimen.dp_580).toInt(),
+ resources.getDimension(R.dimen.dp_36).toInt()
+ )
+ } else {
+ mTaskMenuPopWindow?.dismiss()
+ }
+ }
+
+ }
+
+ /**
+ * 设置准备就绪按钮时都可以点击
+ */
+ fun setEnableClickBtn(isWorking: Boolean) {
+ readyTaskBtn.isClickable=!isWorking
+ presenter?.setWorking(isWorking)
+ if (isWorking) {
+ tvTaskState.text = "正在作业"
+ readyTaskBtn.text="任务中"
+ readyTaskBtn.setTextColor(Color.parseColor("#FFFFFFFF"))
+ tvTaskState.setBackgroundResource(R.drawable.bg_shape_task_state_working)
+ readyTaskBtn.setBackgroundResource(R.drawable.sweeper_task_working)
+ } else {
+ tvTaskState.text = "暂未准备"
+ readyTaskBtn.text="开始任务"
+ readyTaskBtn.setTextColor(Color.parseColor("#66FFFFFF"))
+ tvTaskState.setBackgroundResource(R.drawable.bg_shape_task_state_not_ready)
+ readyTaskBtn.setBackgroundResource(R.drawable.sweeper_task_not_working)
+ }
+ }
+
+ /**
+ * 设置准备就绪按钮时都可以点击
+ */
+ fun setStartAutoBtn(autopilotState: Int) {
+ when (autopilotState) {
+ IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE -> {
+ tvStartAuto.text="自动驾驶"
+ tvStartAuto.setTextColor(Color.parseColor("#66FFFFFF"))
+ tvStartAuto.setBackgroundResource(R.drawable.sweeper_start_auto_not_running)
+ }
+ IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE -> {
+ tvStartAuto.text="自动驾驶"
+ tvStartAuto.setTextColor(Color.parseColor("#66FFFFFF"))
+ tvStartAuto.setBackgroundResource(R.drawable.sweeper_start_auto_not_running)
+ }
+ IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING -> {
+ tvStartAuto.text="自动驾驶"
+ tvStartAuto.setTextColor(Color.parseColor("#FFFFFFFF"))
+ tvStartAuto.setBackgroundResource(R.drawable.sweeper_start_auto_running)
+ }
+ IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING -> {
+ tvStartAuto.text="平行驾驶"
+ tvStartAuto.setTextColor(Color.parseColor("#FFFFFFFF"))
+ tvStartAuto.setBackgroundResource(R.drawable.sweeper_start_auto_running)
+ }
+ }
+ }
+
+ /**
+ * 开始子任务
+ */
+ private fun startSubTask() {
+ listTask?.let {
+ presenter?.startTask(
+ isFirstSubTask(),
+ isLastSubTask(),
+ it[mCurrentPosition].taskId,
+ if (it[mCurrentPosition].taskType == SubTaskTypeEnum.AUTOPILOT_SUBTYPE.code) SubTaskTypeEnum.AUTOPILOT_SUBTYPE else SubTaskTypeEnum.MANUAL_DRIVING_SUBTYPE,
+ mSubTaskStatus
+ )
+ }
+ }
+
+ /**
+ * 是否第一个子任务
+ */
+ private fun isFirstSubTask(): Boolean {
+ return mCurrentPosition == 0
+ }
+
+ /**
+ * 是否第一个子任务
+ */
+ private fun isLastSubTask(): Boolean {
+ return mCurrentPosition == (listTask?.size?.minus(1))
+ }
+
+ /**
+ * 设置任务状态
+ */
+ fun setTaskStatus(status: Int) {
+ this.mSubTaskStatus = status
+ }
+
+ /**
+ * 填充数据
+ */
+ fun setCurrentData(mCurrentPosition: Int) {
+ listTask?.let {
+ mSubTaskType =
+ if (it[mCurrentPosition].taskType == SubTaskTypeEnum.AUTOPILOT_SUBTYPE.code) SubTaskTypeEnum.AUTOPILOT_SUBTYPE else SubTaskTypeEnum.MANUAL_DRIVING_SUBTYPE
+ if (it.size == 1) {
+ preSubTask.setData(it[mCurrentPosition], isSelect = true, isLastTask = true)
+ currentSubTask.visibility = View.INVISIBLE
+ lastSubTask.visibility = View.INVISIBLE
+ } else if (it.size == 2) {
+ if (mCurrentPosition == 0) {
+ preSubTask.setData(it[mCurrentPosition], isSelect = true)
+ currentSubTask.setData(it[1], isLastTask = true)
+ } else {
+ preSubTask.setData(it[mCurrentPosition - 1])
+ currentSubTask.setData(it[mCurrentPosition], isSelect = true, 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 (mCurrentPosition == 0) {
+ preSubTask.setData(it[mCurrentPosition], isSelect = true)
+ currentSubTask.setData(it[1])
+ lastSubTask.setData(it[2], isLastTask = true)
+ //当前正在执行的任务是最后一个子任务
+ } else if (mCurrentPosition == it.size - 1) {
+ preSubTask.setData(it[mCurrentPosition - 2])
+ currentSubTask.setData(it[mCurrentPosition - 1])
+ lastSubTask.setData(it[mCurrentPosition], isSelect = true, isLastTask = true)
+ } else {
+ preSubTask.setData(it[mCurrentPosition - 1])
+ currentSubTask.setData(it[mCurrentPosition], isSelect = true)
+ lastSubTask.setData(it[mCurrentPosition + 1], isLastTask = true)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperLimitingVelocityView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperLimitingVelocityView.kt
new file mode 100644
index 0000000000..17e414c40d
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperLimitingVelocityView.kt
@@ -0,0 +1,59 @@
+package com.mogo.och.sweeper.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.sweeper.R
+import kotlinx.android.synthetic.main.sweeper_limiting_speed.view.*
+
+class SweeperLimitingVelocityView(
+ context: Context,
+ attrs: AttributeSet? = null,
+) : LinearLayout(context, attrs), ILimitingVelocityListener, IViewControlListener {
+
+ companion object {
+ private const val TAG = "SweeperLimitingVelocityView"
+ }
+
+ init {
+ LayoutInflater.from(context).inflate(R.layout.sweeper_limiting_speed, this, true)
+ }
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ CallerLimitingVelocityListenerManager.addListener(TAG, this)
+ CallerHmiViewControlListenerManager.addListener(LimitingVelocityView_TAG, this)
+ }
+
+ override fun onLimitingVelocityChange(limitingVelocity: Int, sourceType: DataSourceType) {
+ ThreadUtils.runOnUiThread {
+ if (limitingVelocity > 0) {
+ this.visibility = View.VISIBLE
+ tvLimitingVelocity.text = "$limitingVelocity"
+ } else {
+ this.visibility = View.GONE
+ }
+ }
+ }
+
+ override fun visible(v: Int) {
+ super.visible(v)
+ this.visibility = v
+ }
+
+ override fun onDetachedFromWindow() {
+ super.onDetachedFromWindow()
+ CallerLimitingVelocityListenerManager.removeListener(TAG)
+ CallerHmiViewControlListenerManager.removeListener(LimitingVelocityView_TAG)
+ }
+
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperTrafficDataView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperTrafficDataView.kt
new file mode 100644
index 0000000000..e50f631b9a
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperTrafficDataView.kt
@@ -0,0 +1,169 @@
+package com.mogo.och.sweeper.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.IMoGoBatteryManagementSystemListener
+import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisGearStateListener
+import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLamplightListener
+import com.mogo.eagle.core.function.api.autopilot.IMoGoSweeperFutianCleanSystemListener
+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.sweeper.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 sweeperTurnSignal //转向灯
+ : TurnSignalView? = 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)
+ sweeperTurnSignal = findViewById(R.id.sweeperTurnSignal)
+ 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是右转
+ if (lightSwitch != null) {
+ sweeperTurnSignal?.setTurnLight(lightSwitch)
+ }
+ }
+
+ /**
+ * 刹车灯
+ * @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 updateSpeedWithValue(newSpeed: Int) {
+ speedTextView?.text = newSpeed.toString()
+ speedImage?.setBackgroundResource(if (newSpeed > 60) R.drawable.sweeper_traffic_data_speed_warning else R.drawable.sweeper_bg_traffic_data_speed)
+ }
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperTrafficLightView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperTrafficLightView.kt
new file mode 100644
index 0000000000..18ae4794f1
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperTrafficLightView.kt
@@ -0,0 +1,144 @@
+package com.mogo.och.sweeper.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.util.UiThreadHandler
+import com.mogo.och.sweeper.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)
+ }
+
+ /**
+ * 关闭红绿灯预警展示,并重制灯态
+ */
+ 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
+ }
+ }
+
+ /**
+ * @param redNum 红灯倒计时
+ * @param yellowNum 黄灯倒计时
+ * @param greenNum 绿灯倒计时
+ */
+ override fun changeCountdownTrafficLightNum(redNum: Int, yellowNum: Int, greenNum: Int) {
+ when (mCurrentLightId) {
+ TrafficLightEnum.RED -> changeCountdownRed(redNum)
+ TrafficLightEnum.YELLOW -> changeCountdownYellow(yellowNum)
+ TrafficLightEnum.GREEN -> changeCountdownGreen(greenNum)
+ else -> UiThreadHandler.post { sweeper_traffic_light_time_tv.text = "" }
+ }
+ }
+
+ override fun changeCountdownRed(redNum: Int) {
+ UiThreadHandler.post {
+ if (redNum > 0) {
+ sweeper_traffic_light_time_tv.text = redNum.toString()
+ } else {
+ sweeper_traffic_light_time_tv.text = ""
+ }
+ }
+ }
+
+ override fun changeCountdownGreen(greenNum: Int) {
+ UiThreadHandler.post {
+ if (greenNum > 0) {
+ sweeper_traffic_light_time_tv.text = greenNum.toString()
+ } else {
+ sweeper_traffic_light_time_tv.text = ""
+ }
+ }
+ }
+
+ override fun changeCountdownYellow(yellowNum: Int) {
+ UiThreadHandler.post {
+ if (yellowNum > 0) {
+ sweeper_traffic_light_time_tv.text = yellowNum.toString()
+ } else {
+ sweeper_traffic_light_time_tv.text = ""
+ }
+ }
+ }
+
+ /**
+ * 更新红绿灯icon
+ *
+ * @param lightId 0-都是默认,1-红,2-黄,3-绿
+ */
+ private fun updateTrafficLightIcon(lightId: TrafficLightEnum) {
+ UiThreadHandler.post {
+ when (lightId) {
+ TrafficLightEnum.RED -> {
+ sweeper_traffic_light_iv.setImageResource(R.drawable.sweeper_light_red_nor)
+ this@SweeperTrafficLightView.visibility = VISIBLE
+ }
+ TrafficLightEnum.YELLOW -> {
+ sweeper_traffic_light_iv.setImageResource(R.drawable.sweeper_lightyellow_nor)
+ this@SweeperTrafficLightView.visibility = VISIBLE
+ }
+ TrafficLightEnum.GREEN -> {
+ sweeper_traffic_light_iv.setImageResource(R.drawable.sweeper_light_green_nor)
+ this@SweeperTrafficLightView.visibility = VISIBLE
+ }
+ else -> {
+ sweeper_traffic_light_iv.setImageResource(R.drawable.sweeper_light_gay_nor)
+ this@SweeperTrafficLightView.visibility = VISIBLE
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperWorkModeView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperWorkModeView.kt
new file mode 100644
index 0000000000..fae8cfd18f
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/SweeperWorkModeView.kt
@@ -0,0 +1,181 @@
+package com.mogo.och.sweeper.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.sweeper.R
+import com.mogo.och.sweeper.callback.ICleaningModeStateCallback
+import com.mogo.och.sweeper.constant.OperateStateEnum
+import com.mogo.och.sweeper.constant.SubTaskTypeEnum
+import com.mogo.och.sweeper.ui.popwindow.SweeperOperatePanelPopWindow
+import com.mogo.och.sweeper.util.SweeperFutianCmdUtil
+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: SubTaskTypeEnum, 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.code == SubTaskTypeEnum.MANUAL_DRIVING_SUBTYPE.code) {
+ setShowOrHideCleanSystemState(OperateStateEnum.NO_STATUS, cleanSystemState)
+ } else {
+ setShowOrHideCleanSystemState(OperateStateEnum.SUCCESS_STATUS, cleanSystemState)
+ }
+ }
+
+ /**
+ * 设置清扫模式状态显示和隐藏
+ */
+ private fun setShowOrHideCleanSystemState(operateState: OperateStateEnum, cleanSystemState: SweeperFuTianTaskSystemStates?) {
+ when (operateState.code) {
+ OperateStateEnum.SYNCING_STATUS.code -> {
+ groupWorkModelPanel?.visibility = View.GONE
+ tvNoDataDesc?.visibility = View.VISIBLE
+ tvNoDataDesc?.text = "状态同步中,请稍后"
+ mOperatePanelPopWindow?.setIsOutsideTouchable(true)
+ }
+ OperateStateEnum.FAIL_STATUS.code -> {
+ groupWorkModelPanel?.visibility = View.GONE
+ tvNoDataDesc?.visibility = View.VISIBLE
+ tvNoDataDesc?.text = "上装启动失败"
+ mOperatePanelPopWindow?.setIsOutsideTouchable(true)
+ }
+ OperateStateEnum.STARTING_STATUS.code -> {
+ groupWorkModelPanel?.visibility = View.GONE
+ tvNoDataDesc?.visibility = View.VISIBLE
+ tvNoDataDesc?.text = "上装启动中..."
+ mOperatePanelPopWindow?.setIsOutsideTouchable(false)
+ }
+ OperateStateEnum.NO_STATUS.code -> {
+ groupWorkModelPanel?.visibility = View.GONE
+ tvNoDataDesc?.visibility = View.VISIBLE
+ tvNoDataDesc?.text = "暂无"
+ mOperatePanelPopWindow?.setIsOutsideTouchable(true)
+ }
+ else -> {
+ groupWorkModelPanel?.visibility = View.VISIBLE
+ tvNoDataDesc?.visibility = View.GONE
+ setCleanModeData(cleanSystemState)
+ mOperatePanelPopWindow?.setIsOutsideTouchable(true)
+ }
+
+ }
+ }
+
+ override fun cleaningModeState(operateState: OperateStateEnum, cleanSystemState: SweeperFuTianTaskSystemStates?, isSelectPureSweepMode: Boolean) {
+ this.isSelectPureSweepMode = isSelectPureSweepMode
+ this.operateState=operateState
+ setShowOrHideCleanSystemState(operateState, cleanSystemState)
+ }
+
+ /**
+ * 设置清扫模式数据
+ */
+ private fun setCleanModeData(cleanSystemState: SweeperFuTianTaskSystemStates?) {
+ if (isSelectPureSweepMode) {
+ tvCleaningMode?.text = "纯扫模式"
+ groupWorkModelPanel?.visibility = View.VISIBLE
+ tvNoDataDesc?.visibility = View.GONE
+ } else {
+ if (SweeperFutianCmdUtil.checkIfCleanMode(cleanSystemState)) {
+ groupWorkModelPanel?.visibility = View.GONE
+ tvNoDataDesc?.visibility = View.VISIBLE
+ tvNoDataDesc?.text = "暂无"
+ return
+ } else {
+ groupWorkModelPanel?.visibility = View.VISIBLE
+ tvNoDataDesc?.visibility = View.GONE
+ // 作业模式
+ if (cleanSystemState?.secuModWashSweepSts == true) tvCleaningMode?.text = "洗扫模式"
+ if (cleanSystemState?.secuModWashSts == true) tvCleaningMode?.text = "纯洗模式"
+ if (cleanSystemState?.secuWorkTonSts == true) tvCleaningMode?.text = "纯吸模式"
+ if (SweeperFutianCmdUtil.checkIfCleanModePureSweep(cleanSystemState)) tvCleaningMode?.text = "纯扫模式"
+ }
+ }
+ //清扫方向
+ if (SweeperFutianCmdUtil.checkIfCleanDirection(cleanSystemState)) {
+ tvCleaningDirection.visibility = View.GONE
+ } else {
+ tvCleaningDirection.visibility = View.VISIBLE
+ // 左侧
+ if (cleanSystemState?.secuWorkLeftSts == true) tvCleaningDirection?.text = "左侧"
+ // 右侧
+ if (cleanSystemState?.secuWorkRightSts == true) tvCleaningDirection?.text = "右侧"
+ // 两侧
+ if (cleanSystemState?.secuWorkOnBothsidesSts == true) tvCleaningDirection?.text = "两侧"
+ }
+ if (SweeperFutianCmdUtil.checkIfCleanIntensity(cleanSystemState)) {
+ tvCleaningIntensity.visibility = View.GONE
+ } else {
+ tvCleaningIntensity.visibility = View.VISIBLE
+ // 作业强度
+ if (cleanSystemState?.secuWorkStandSts == true) tvCleaningIntensity?.text = "标准"
+ if (cleanSystemState?.secuWorkStrongSts == true) tvCleaningIntensity?.text = "强力"
+ }
+ }
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/TurnSignalView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/TurnSignalView.kt
new file mode 100644
index 0000000000..57394c2ce8
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/TurnSignalView.kt
@@ -0,0 +1,90 @@
+package com.mogo.och.sweeper.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.sweeper.R
+import kotlinx.android.synthetic.main.sweeper_turn_signal.view.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+
+class TurnSignalView : LinearLayout {
+ constructor(context: Context?) : super(context) {}
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ initView(context)
+ }
+
+ private var init: Boolean = false
+
+ constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
+ context,
+ attrs,
+ defStyleAttr
+ ) {
+ }
+
+ constructor(
+ context: Context?,
+ attrs: AttributeSet?,
+ defStyleAttr: Int,
+ defStyleRes: Int
+ ) : super(context, attrs, defStyleAttr, defStyleRes) {
+ }
+
+ private fun initView(context: Context) {
+ LayoutInflater.from(context).inflate(R.layout.sweeper_turn_signal, this)
+ init = true
+ }
+
+ /**
+ * 转向灯动画
+ */
+ fun setTurnLight(directionLight: Chassis.LightSwitch?) {
+ GlobalScope.launch(Dispatchers.Main) {
+ if (!init) {
+ return@launch
+ }
+ //根据左右进行显示和隐藏,实际要判断每个来的时间和频度
+ when (directionLight) {
+ Chassis.LightSwitch.LIGHT_LEFT -> { //左转向
+ leftSelectImage.visibility = View.VISIBLE
+ rightSelectImage.visibility = View.GONE
+ rightSelectImage.clearAnimation()
+ setAnimation(leftSelectImage)
+ }
+ Chassis.LightSwitch.LIGHT_RIGHT -> { //右转向
+ leftSelectImage.visibility = View.GONE
+ rightSelectImage.visibility = View.VISIBLE
+ leftSelectImage.clearAnimation()
+ setAnimation(rightSelectImage)
+ }
+ else -> { //消失
+ leftSelectImage.clearAnimation()
+ rightSelectImage.clearAnimation()
+ leftSelectImage.visibility = View.GONE
+ rightSelectImage.visibility = View.GONE
+ }
+ }
+ }
+ }
+
+ //实现图片闪烁效果
+ private fun setAnimation(imageView: ImageView) {
+ val animationSet = AnimatorSet()
+ val valueAnimator = ObjectAnimator.ofFloat(imageView, "alpha", 0f, 1.0f)
+ val valueAnimatorDisappare = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0f)
+ valueAnimator.duration = 1000
+ valueAnimatorDisappare.duration = 800
+ valueAnimator.repeatCount = -1
+ valueAnimatorDisappare.repeatCount = -1
+ animationSet.playTogether(valueAnimatorDisappare, valueAnimator)
+ animationSet.start()
+ }
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/VerticalDashLineView.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/VerticalDashLineView.java
new file mode 100644
index 0000000000..875722ea11
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/VerticalDashLineView.java
@@ -0,0 +1,64 @@
+package com.mogo.och.sweeper.view;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.DashPathEffect;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Shader;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+/**
+ * 垂直虚线
+ *
+ * @author tongchenfei
+ */
+public class VerticalDashLineView extends View {
+ public VerticalDashLineView(Context context) {
+ this(context,null);
+ }
+
+ public VerticalDashLineView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs,0);
+ }
+
+ public VerticalDashLineView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ private final Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Path dashPath = new Path();
+
+ private void init(){
+ linePaint.setColor(Color.GREEN);
+ linePaint.setStyle(Paint.Style.STROKE);
+ linePaint.setStrokeWidth(2);
+ linePaint.setPathEffect(new DashPathEffect(new float[]{5, 5}, 0));
+ }
+
+ public void setGradient(int startColor, int endColor) {
+ LinearGradient linearGradient = new LinearGradient(0, 0, getWidth(), getHeight(), startColor, endColor, Shader.TileMode.CLAMP);
+ linePaint.setShader(linearGradient);
+ invalidate();
+ }
+
+ public void setColor(int color) {
+ linePaint.setShader(null);
+ linePaint.setColor(color);
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ dashPath.reset();
+ dashPath.moveTo((float) getWidth()/2, 0);
+ dashPath.lineTo((float) getWidth()/2,getHeight());
+ canvas.drawPath(dashPath,linePaint);
+ }
+}
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/WeltMapOverView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/WeltMapOverView.kt
new file mode 100644
index 0000000000..438b14b0e9
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/WeltMapOverView.kt
@@ -0,0 +1,342 @@
+package com.mogo.och.sweeper.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.sweeper.R
+import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean
+import com.mogo.och.sweeper.constant.SweeperConst
+import com.mogo.och.sweeper.database.bean.WeltDataBean
+import com.mogo.och.sweeper.util.SweeperMapAssetStyleUtil
+import kotlinx.android.synthetic.main.sweeper_welt_map_overview.view.*
+
+/**
+ * 作业任务全览图
+ */
+class WeltMapOverView : ConstraintLayout, IMoGoChassisLocationGCJ02Listener {
+ private var mTaskCoordinatesLatLng: MutableList = mutableListOf() //当前大任务的所有起终点集合
+ private var mCarMarker: Marker? = null
+ private var mAMap: AMap? = null
+ private var mWeltPolylines: Polyline? = null
+ private var mRoutePolylines: Polyline?=null
+// private val mLineMarkers: MutableList = mutableListOf()
+ private var mEndStationMarker: Marker? = null
+ private var mFirst: Boolean = false
+
+ //清扫车任务地图
+ private val TAG = "WeltMapOverView"
+
+ constructor(context: Context) : super(context) {}
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ initView(context)
+ }
+
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
+
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {}
+
+ private fun initView(context: Context) {
+ LayoutInflater.from(context).inflate(R.layout.sweeper_welt_map_overview, this)
+ initAMapView()
+ // 注册定位监听
+ CallerChassisLocationGCJ02ListenerManager.addListener(TAG, this)
+ CallerChassisLocationGCJ02ListenerManager.setListenerHz(TAG,5)
+ }
+
+ private fun initAMapView() {
+ mAMap = sweeperTextureMapView.map
+ // 地图文字标注
+ mAMap?.showMapText(true)
+ //显示3D建筑物
+ mAMap?.showBuildings(true)
+ // 设置导航地图模式,aMap是地图控制器对象。
+ mAMap?.mapType = AMap.MAP_TYPE_NIGHT
+ // 关闭显示实时路况图层,aMap是地图控制器对象。
+ mAMap?.isTrafficEnabled = false
+ // 设置 锚点 图标
+ mCarMarker = mAMap?.addMarker(
+ MarkerOptions()
+ .icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_car_big))
+ .anchor(0.5f, 0.5f)
+ )
+ // 设置地图的样式
+ val uiSettings = mAMap?.uiSettings
+ uiSettings?.isZoomControlsEnabled = false // 地图缩放级别的交换按钮
+ uiSettings?.setAllGesturesEnabled(false) // 所有手势
+ uiSettings?.isMyLocationButtonEnabled = false // 显示默认的定位按钮
+ uiSettings?.setLogoBottomMargin(-150) //设置Logo下边界距离屏幕底部的边距,设置为负值即可
+ // 加载自定义样式
+ val customMapStyleOptions = CustomMapStyleOptions()
+ .setEnable(true)
+ .setStyleData(SweeperMapAssetStyleUtil.getAssetsStyle(context, "map_style.data"))
+ .setStyleExtraData(SweeperMapAssetStyleUtil.getAssetsExtraStyle(context, "map_style_extra.data"))
+ // 设置自定义样式
+ mAMap?.setCustomMapStyle(customMapStyleOptions)
+ //mAMap?.moveCamera(CameraUpdateFactory.zoomTo(15f))
+ mAMap?.setOnMapLoadedListener(AMap.OnMapLoadedListener {
+ //mAMap?.moveCamera(CameraUpdateFactory.zoomTo(15f))
+ CallerLogger.d(SceneConstant.M_SWEEPER + TAG, "WeltView---onMapLoaded")
+ // 加载自定义样式
+ val customMapStyleOptions = CustomMapStyleOptions()
+ .setEnable(true)
+ .setStyleData(SweeperMapAssetStyleUtil.getAssetsStyle(context, "map_style.data"))
+ .setStyleExtraData(SweeperMapAssetStyleUtil.getAssetsExtraStyle(context, "map_style_extra.data"))
+ // 设置自定义样式
+ mAMap?.setCustomMapStyle(customMapStyleOptions)
+ // 实时路况图层关闭,必须添加在loaded结束之后,其他位置不生效
+ mAMap?.isTrafficEnabled = false
+ mAMap?.showBuildings(true)
+ })
+ }
+
+ /**
+ * 添加画线颜色值
+ */
+ private fun getRouteColorList(weltData: MutableList):MutableList {
+ val colorList= mutableListOf()
+ var nextWeltDataBean: WeltDataBean?=null
+ for (i in weltData.indices) {
+ val weltDataBean = weltData[i]
+ if(i+110){
+ colorList.add(Color.TRANSPARENT)
+ continue
+ }
+ }
+ if (weltDataBean.weltDistance == SweeperConst.NONWELT) {//非贴边
+ colorList.add(ContextCompat.getColor(context,R.color.sweeper_236299))
+ } else if (weltDataBean.weltDistance < 0) {
+ colorList.add(ContextCompat.getColor(context,R.color.sweeper_c22101))
+ } else if (weltDataBean.weltDistance >= 0 && weltDataBean.weltDistance < 0.1) {
+ colorList.add(ContextCompat.getColor(context,R.color.sweeper_4dffa4))
+ } else if (weltDataBean.weltDistance >= 0.1 && weltDataBean.weltDistance < 0.2) {
+ colorList.add(ContextCompat.getColor(context,R.color.sweeper_ffdd4d))
+ } else if (weltDataBean.weltDistance >= 0.2) {
+ colorList.add(ContextCompat.getColor(context,R.color.sweeper_ff912b))
+ }
+ }
+ return colorList
+ }
+
+ override fun onChassisLocationGCJ02(mogoLocation: MogoLocation?) {
+ ThreadUtils.getSinglePool().run {
+ mogoLocation?.let { gnssInfo ->
+ val currentLatLng = LatLng(gnssInfo.latitude, gnssInfo.longitude)
+ //更新车辆位置
+ mCarMarker?.rotateAngle = (360 - gnssInfo.heading).toFloat()
+ mCarMarker?.position = currentLatLng
+ mCarMarker?.setToTop()
+ //圈定地图显示范围
+ val boundsBuilder = LatLngBounds.Builder()
+ if (mTaskCoordinatesLatLng.size > 0) {
+ //存放经纬度
+ for (i in mTaskCoordinatesLatLng.indices) {
+ val latLng = mTaskCoordinatesLatLng[i]
+ boundsBuilder.include(latLng)
+ }
+ }
+ mRoutePolylines?.points?.forEach {latLng->
+ boundsBuilder.include(latLng)
+ }
+ boundsBuilder.include(currentLatLng)
+ mAMap?.moveCamera(CameraUpdateFactory.newLatLngBoundsRect(boundsBuilder.build(), 100, 100, 100, 100))
+
+ }
+ }
+ }
+
+ /**
+ * 根据贴边数据绘制任务路线
+ */
+ fun drawablePolyline(weltDatas: MutableList?) {
+ weltDatas?.let {
+ val colorList=getRouteColorList(it)
+ val coordinatesLatLngs= mutableListOf()
+ for (i in it.indices) {
+ coordinatesLatLngs.add(LatLng(it[i].locLat,it[i].locLon))
+ }
+ if (coordinatesLatLngs.size > 2) {
+ //设置线段纹理
+ mWeltPolylines?.remove()
+ val polylineOptions = PolylineOptions()
+ polylineOptions.addAll(coordinatesLatLngs)
+ polylineOptions.width(14f) //线段宽度
+ polylineOptions.isUseTexture = false
+ polylineOptions.lineCapType(PolylineOptions.LineCapType.LineCapSquare)
+ polylineOptions.colorValues(colorList)
+ polylineOptions.visible(true)
+ // 绘制线
+ mWeltPolylines = mAMap?.addPolyline(polylineOptions)
+ }
+ }
+ }
+
+ /**
+ * 绘制起点和终点的marker
+ */
+ private fun drawStartAndEndMarker(startPoint: LatLng, endPoint: LatLng) {
+// val startMarker = mAMap?.addMarker(MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_big_start_maker_icon)))
+// startMarker?.position = startPoint
+// mLineMarkers.add(startMarker)
+// val endMarker = mAMap?.addMarker(MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_big_end_maker_icon)))
+// endMarker?.position = endPoint
+// mLineMarkers.add(endMarker)
+ }
+
+ private fun drawEndMarker(endPoint: LatLng){
+ mEndStationMarker?.remove()
+ mEndStationMarker = mAMap?.addMarker(MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_big_end_maker_icon)))
+ mEndStationMarker?.position = endPoint
+ }
+
+ /**
+ * 清除所有标记和路线
+ */
+ fun clearAllMarkerAndPolyline() {
+// for (i in mLineMarkers.indices) {
+// mLineMarkers[i]?.isVisible = false
+// mLineMarkers[i]?.remove()
+// }
+ mEndStationMarker?.remove()
+ mWeltPolylines?.remove()
+ mRoutePolylines?.remove()
+// mLineMarkers.clear()
+ //mFirst = false
+ //showOrHiddenLegendData(false)
+ }
+
+ /**
+ * 设置贴边数据
+ */
+ fun setWeltData(weltDatas: MutableList?, isWeltData: Boolean, distance: String?) {
+ drawablePolyline(weltDatas)
+ ThreadUtils.runOnUiThread {
+ distance?.let {
+ setDistance(it)
+ }
+ }
+ //if (!mFirst && isWeltData) {
+ // mFirst = true
+ // showOrHiddenLegendData(true)
+ //}
+ }
+
+ /**
+ * 任务轨迹数据
+ */
+ fun setRouteList(routeList: ArrayList) {
+ val routeCoordinatesLatLngs= mutableListOf()
+ for (i in routeList.indices) {
+ routeCoordinatesLatLngs.add(LatLng(routeList[i].latitude,routeList[i].longitude))
+ }
+ ThreadUtils.runOnUiThread {
+ drawRouteListPolyline(routeCoordinatesLatLngs)
+ }
+ }
+
+ private fun drawRouteListPolyline(routeList: MutableList) {
+ mRoutePolylines?.remove()
+ val polylineOptions = PolylineOptions()
+ polylineOptions.width(14f) //线段宽度
+ polylineOptions.isUseTexture = false
+ polylineOptions.lineCapType(PolylineOptions.LineCapType.LineCapSquare)
+ polylineOptions.color(ContextCompat.getColor(context,R.color.sweeper_3ba1cc))
+ polylineOptions.addAll(routeList)
+ polylineOptions.visible(true)
+ mRoutePolylines=mAMap?.addPolyline(polylineOptions)
+ }
+
+ /**
+ * 设置当前大任务的所有子任务起终点集合
+ */
+ fun setTaskListCoordinatesLatLng(coordinatesLatLng: MutableList) {
+ ThreadUtils.runOnUiThread {
+ this.mTaskCoordinatesLatLng = coordinatesLatLng
+ if (mTaskCoordinatesLatLng.size > 0) {
+ drawStartAndEndMarker(mTaskCoordinatesLatLng[0], mTaskCoordinatesLatLng[mTaskCoordinatesLatLng.size - 1])
+ }
+ }
+ }
+ /**
+ * 设置当前大任务的所有子任务起终点集合
+ */
+ fun setCurrentTaskCoordinatesLatLng(coordinatesLatLng: LatLng) {
+ ThreadUtils.runOnUiThread {
+ drawEndMarker(coordinatesLatLng)
+ }
+ }
+
+ /**
+ * 设置图例数据
+ */
+ private fun showOrHiddenLegendData(isShow: Boolean) {
+ groupLegend.visibility = if (isShow) View.VISIBLE else View.GONE
+ sweeperLegend1.setData(R.drawable.sweeper_legend1, "a<0")
+ sweeperLegend2.setData(R.drawable.sweeper_legend2, "0≤a<10")
+ sweeperLegend3.setData(R.drawable.sweeper_legend3, "10≤a<20")
+ sweeperLegend4.setData(R.drawable.sweeper_legend4, "a≥20")
+ sweeperLegend5.setData(R.drawable.sweeper_legend5, "非贴边")
+ sweeperLegend6.setData(R.drawable.sweeper_legend6, "未经过")
+ }
+
+ private fun setDistance(distance: String) {
+ taskWeltDistanceTv.text = "贴边:${distance}"
+ }
+
+ fun setProgress(progress: String?) {
+ progress?.let {
+ if ("0" == progress) {
+ taskProgressTv.visibility = View.GONE
+ taskWeltDistanceTv.visibility = View.GONE
+ showOrHiddenLegendData(false)
+ } else {
+ taskProgressTv.visibility = View.VISIBLE
+ taskWeltDistanceTv.visibility = View.VISIBLE
+ taskProgressTv.text = it
+ showOrHiddenLegendData(true)
+ }
+ }
+ }
+
+ fun onCreateView(savedInstanceState: Bundle?) {
+ sweeperTextureMapView.onCreate(savedInstanceState)
+ }
+
+ fun onResume() {
+ sweeperTextureMapView.onResume()
+ }
+
+ fun onPause() {
+ sweeperTextureMapView.onPause()
+ }
+
+ fun onDestroy() {
+ sweeperTextureMapView.onDestroy()
+ }
+
+ fun getSweeperSwitchToSmall(): ImageView {
+ return sweeperSwitchToSmall
+ }
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/WeltSmallMapView.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/WeltSmallMapView.kt
new file mode 100644
index 0000000000..c6082d34cf
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/view/WeltSmallMapView.kt
@@ -0,0 +1,344 @@
+package com.mogo.och.sweeper.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.sweeper.R
+import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean
+import com.mogo.och.sweeper.constant.SweeperConst
+import com.mogo.och.sweeper.database.bean.WeltDataBean
+import com.mogo.och.sweeper.util.SweeperMapAssetStyleUtil
+import kotlinx.android.synthetic.main.sweeper_welt_small_map_view.view.*
+
+
+/**
+ * 作业任务小地图
+ */
+class WeltSmallMapView : ConstraintLayout, IMoGoChassisLocationGCJ02Listener {
+ private var mTaskCoordinatesLatLng: MutableList = mutableListOf() //当前大任务的所有起终点集合
+ private var mCarMarker: Marker? = null
+ private var mAMap: AMap? = null
+ private var mWeltPolylines: Polyline? = null
+ private var mRoutePolylines: Polyline?=null
+// private val mLineMarkers: MutableList = mutableListOf()
+ private var endStationMarker:Marker? = null
+
+ //清扫车任务地图
+ private val TAG = "WeltMapView"
+
+ constructor(context: Context) : super(context) {}
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ initView(context)
+ }
+
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {}
+
+ private fun initView(context: Context) {
+ LayoutInflater.from(context).inflate(R.layout.sweeper_welt_small_map_view, this)
+ initAMapView()
+ // 注册定位监听
+ CallerChassisLocationGCJ02ListenerManager.addListener(TAG, this)
+ CallerChassisLocationGCJ02ListenerManager.setListenerHz(TAG,5)
+ }
+
+ override fun onChassisLocationGCJ02(mogoLocation: MogoLocation?) {
+ d(SceneConstant.M_SWEEPER + TAG, "mogoLocation:$mogoLocation")
+ ThreadUtils.getSinglePool().run {
+ mogoLocation?.let {
+ val currentLatLng = LatLng(it.latitude, it.longitude)
+ drawCarMarker(mogoLocation)
+ //圈定地图显示范围
+ val boundsBuilder = LatLngBounds.Builder()
+ if (mTaskCoordinatesLatLng.size > 0) {
+ //存放经纬度
+ for (i in mTaskCoordinatesLatLng.indices) {
+ boundsBuilder.include(mTaskCoordinatesLatLng[i])
+ }
+ }
+ mRoutePolylines?.points?.forEach {latLng->
+ boundsBuilder.include(latLng)
+ }
+ boundsBuilder.include(currentLatLng)
+ mAMap!!.moveCamera(CameraUpdateFactory.newLatLngBoundsRect(boundsBuilder.build(), 100, 100, 100, 100))
+ }
+ }
+ }
+
+ /**
+ * 绘制自车
+ *
+ * @param location
+ */
+ private fun drawCarMarker(location: MogoLocation?) {
+ if (location == null) return
+ val currentLatLng = LatLng(location.latitude, location.longitude)
+ //更新车辆位置
+ if (mCarMarker != null) {
+ mCarMarker!!.rotateAngle = (360 - location.heading).toFloat()
+ mCarMarker!!.position = currentLatLng
+ mCarMarker!!.setToTop()
+ }
+ }
+
+ private fun initAMapView() {
+ mAMap = sweeperSmallTextureMapView?.map
+ // 地图文字标注
+ mAMap?.showMapText(true)
+ // 设置导航地图模式,aMap是地图控制器对象。
+ mAMap?.mapType = AMap.MAP_TYPE_NIGHT
+ // 关闭显示实时路况图层,aMap是地图控制器对象。
+ mAMap?.isTrafficEnabled = false
+ // 设置 锚点 图标
+ mCarMarker = mAMap?.addMarker(
+ MarkerOptions()
+ .icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_car_small))
+ .anchor(0.5f, 0.5f)
+ )
+ // 设置地图的样式
+ val uiSettings = mAMap?.uiSettings
+ uiSettings?.isZoomControlsEnabled = false // 地图缩放级别的交换按钮
+ uiSettings?.setAllGesturesEnabled(false) // 所有手势
+ uiSettings?.isMyLocationButtonEnabled = false // 显示默认的定位按钮
+ uiSettings?.setLogoBottomMargin(-150) //设置Logo下边界距离屏幕底部的边距,设置为负值即可
+ // 加载自定义样式
+ val customMapStyleOptions = CustomMapStyleOptions()
+ .setEnable(true)
+ .setStyleData(SweeperMapAssetStyleUtil.getAssetsStyle(context, "map_style.data"))
+ .setStyleExtraData(SweeperMapAssetStyleUtil.getAssetsExtraStyle(context, "map_style_extra.data"))
+ // 设置自定义样式
+ mAMap?.setCustomMapStyle(customMapStyleOptions)
+ mAMap?.setOnMapLoadedListener(AMap.OnMapLoadedListener {
+ d(SceneConstant.M_SWEEPER + TAG, "WeltView---onMapLoaded")
+ // 加载自定义样式
+ val customMapStyleOptions = CustomMapStyleOptions()
+ .setEnable(true)
+ .setStyleData(SweeperMapAssetStyleUtil.getAssetsStyle(context, "map_style.data"))
+ .setStyleExtraData(SweeperMapAssetStyleUtil.getAssetsExtraStyle(context, "map_style_extra.data"))
+ // 设置自定义样式
+ mAMap?.setCustomMapStyle(customMapStyleOptions)
+ mAMap?.setPointToCenter(sweeperSmallTextureMapView.width / 2, sweeperSmallTextureMapView.height / 2)
+ })
+ }
+
+ /**
+ * 根据贴边数据绘制任务路线
+ */
+ private fun drawablePolyline(weltDatas: MutableList?) {
+ weltDatas?.let {
+ val colorList = getRouteColorList(it)
+ val coordinatesLatLngs = mutableListOf()
+ for (i in it.indices) {
+ coordinatesLatLngs.add(LatLng(it[i].locLat,it[i].locLon))
+ }
+ if (coordinatesLatLngs.size > 2) {
+ //设置线段纹理
+ mWeltPolylines?.remove()
+ val polylineOptions = PolylineOptions()
+ polylineOptions.addAll(coordinatesLatLngs)
+ polylineOptions.width(14f) //线段宽度
+ polylineOptions.isUseTexture = false
+ polylineOptions.lineCapType(PolylineOptions.LineCapType.LineCapSquare)
+ polylineOptions.colorValues(colorList)
+ polylineOptions.visible(true)
+ // 绘制线
+ mWeltPolylines = mAMap?.addPolyline(polylineOptions)
+ }
+ }
+ }
+
+ /**
+ * 添加画线颜色值
+ */
+ private fun getRouteColorList(weltData: MutableList): MutableList {
+ val colorList = mutableListOf()
+ var nextWeltDataBean: WeltDataBean?=null
+ for (i in weltData.indices) {
+ val weltDataBean = weltData[i]
+ if(i+110){
+ colorList.add(Color.TRANSPARENT)
+ continue
+ }
+ }
+
+ if (weltDataBean.weltDistance == SweeperConst.NONWELT) {//非贴边
+ colorList.add(ContextCompat.getColor(context,R.color.sweeper_236299))
+ } else if (weltDataBean.weltDistance < 0) {
+ colorList.add(ContextCompat.getColor(context,R.color.sweeper_c22101))
+ } else if (weltDataBean.weltDistance >= 0 && weltDataBean.weltDistance < 0.1) {
+ colorList.add(ContextCompat.getColor(context,R.color.sweeper_4dffa4))
+ } else if (weltDataBean.weltDistance >= 0.1 && weltDataBean.weltDistance < 0.2) {
+ colorList.add(ContextCompat.getColor(context,R.color.sweeper_ffdd4d))
+ } else if (weltDataBean.weltDistance >= 0.2) {
+ colorList.add(ContextCompat.getColor(context,R.color.sweeper_ff912b))
+ }
+ }
+ return colorList
+ }
+
+ /**
+ * 添加起点和终点的marker
+ */
+ private fun addStartAndEndMarker(startPoint: LatLng, endPoint: LatLng) {
+// for (i in mLineMarkers.indices) {
+// mLineMarkers[i]?.isVisible = false
+// mLineMarkers[i]?.remove()
+// }
+// mLineMarkers.clear()
+// val startMarker = mAMap?.addMarker(MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_small_start_marker_icon)))
+// startMarker?.position = startPoint
+// mLineMarkers.add(startMarker)
+// val endMarker = mAMap?.addMarker(MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_small_end_marker_icon)))
+// endMarker?.position = endPoint
+// mLineMarkers.add(endMarker)
+ }
+
+ /**
+ * 设置当前大任务的所有子任务起终点集合
+ */
+ fun setTaskListCoordinatesLatLng(coordinatesLatLng: MutableList) {
+ this.mTaskCoordinatesLatLng = coordinatesLatLng
+// if (mTaskCoordinatesLatLng.size > 0) {
+// d(
+// SceneConstant.M_SWEEPER + TAG,
+// "startPoint:${mTaskCoordinatesLatLng[0]} endPoint:${mTaskCoordinatesLatLng[mTaskCoordinatesLatLng.size - 1]}"
+// )
+// addStartAndEndMarker(mTaskCoordinatesLatLng[0], mTaskCoordinatesLatLng[mTaskCoordinatesLatLng.size - 1])
+// }
+ }
+
+ /**
+ * 设置当前大任务的所有子任务起终点集合
+ */
+ fun setCurrentTaskCoordinatesLatLng(coordinatesLatLng: LatLng) {
+ endStationMarker?.remove()
+ endStationMarker = mAMap?.addMarker(MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.sweeper_small_end_marker_icon)))
+ endStationMarker?.position = coordinatesLatLng
+ }
+
+ /**
+ * 清除所有标记和路线
+ */
+ fun clearAllMarkerAndPolyline() {
+// for (i in mLineMarkers.indices) {
+// mLineMarkers[i]?.isVisible = false
+// mLineMarkers[i]?.remove()
+// }
+ endStationMarker?.remove()
+ mWeltPolylines?.remove()
+// mLineMarkers.clear()
+ mRoutePolylines?.remove()
+ //mFirst = false
+ //showOrHiddenWelt(false)
+ }
+
+ fun getSwitchToBig(): ImageView = sweeperSwitchToBig
+
+ /**
+ * 显示或隐藏贴边
+ */
+ private fun showOrHiddenWelt(isShow: Boolean) {
+ taskProgressTv.visibility = if (isShow) View.VISIBLE else View.GONE
+ taskWeltDistanceTv.visibility = if (isShow) View.VISIBLE else View.GONE
+ }
+
+ /**
+ * 设置贴边数据
+ */
+ fun setWeltData(weltDatas: MutableList, isWeltData: Boolean, distance: String) {
+ drawablePolyline(weltDatas)
+ ThreadUtils.runOnUiThread {
+ setWeltDistance(distance)
+ }
+ //if (!mFirst&&isWeltData) {
+ // showOrHiddenWelt(true)
+ // mFirst = true
+ //}
+ }
+
+ /**
+ * 设置贴边距离
+ */
+ private fun setWeltDistance(distance: String) {
+ taskWeltDistanceTv.text = "贴边:${distance}"
+ }
+
+ /**
+ * 设置任务轨迹数据
+ */
+ fun setRouteList(routeList: ArrayList) {
+ val routeCoordinatesLatLngs = mutableListOf()
+ for (i in routeList.indices) {
+ routeCoordinatesLatLngs.add(LatLng(routeList[i].latitude, routeList[i].longitude))
+ }
+ ThreadUtils.runOnUiThread {
+ drawRouteListPolyline(routeCoordinatesLatLngs)
+ }
+ }
+
+ private fun drawRouteListPolyline(routeList: MutableList) {
+ mRoutePolylines?.remove()
+ val polylineOptions = PolylineOptions()
+ polylineOptions.addAll(routeList)
+ polylineOptions.width(14f) //线段宽度
+ polylineOptions.isUseTexture = false
+ polylineOptions.lineCapType(PolylineOptions.LineCapType.LineCapSquare)
+ polylineOptions.color(ContextCompat.getColor(context,R.color.sweeper_3ba1cc))
+ polylineOptions.visible(true)
+ mRoutePolylines=mAMap?.addPolyline(polylineOptions)
+ }
+
+ /**
+ * 设置任务进度
+ */
+ fun setTaskProgress(progress: String?) {
+ if (progress == "0") {
+ taskWeltDistanceTv.visibility = View.GONE
+ taskProgressTv.visibility = View.GONE
+ } else {
+ taskWeltDistanceTv.visibility = View.VISIBLE
+ taskProgressTv.visibility = View.VISIBLE
+ taskProgressTv.text = progress
+ }
+
+ }
+
+ fun onCreateView(savedInstanceState: Bundle?) {
+ sweeperSmallTextureMapView?.onCreate(savedInstanceState)
+ }
+
+ fun onResume() {
+ sweeperSmallTextureMapView?.onResume()
+ }
+
+ fun onPause() {
+ sweeperSmallTextureMapView?.onPause()
+ }
+
+ fun onDestroy() {
+ sweeperSmallTextureMapView?.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/bg_shape_work_mode.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/bg_shape_work_mode.png
new file mode 100644
index 0000000000..1140726f3f
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/bg_shape_work_mode.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/bg_sweeper_operate_panel.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/bg_sweeper_operate_panel.png
new file mode 100644
index 0000000000..943c88912d
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/bg_sweeper_operate_panel.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_ai_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_ai_normal.png
new file mode 100755
index 0000000000..e98738b192
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_ai_normal.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_battery.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_battery.png
new file mode 100644
index 0000000000..5fee53445e
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_battery.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_message_box.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_message_box.png
new file mode 100644
index 0000000000..eaf471cf4c
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_message_box.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_message_box_pressed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_message_box_pressed.png
new file mode 100644
index 0000000000..fd84812942
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_message_box_pressed.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_right_down_arrow.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_right_down_arrow.png
new file mode 100644
index 0000000000..4939b986fe
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_right_down_arrow.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_level_warning.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_level_warning.png
new file mode 100644
index 0000000000..96bf7d213a
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_level_warning.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_nor.png
new file mode 100644
index 0000000000..75dc6a3497
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_nor.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_select.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_select.png
new file mode 100644
index 0000000000..026549d193
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/icon_water_select.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/no_task_data.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/no_task_data.png
new file mode 100644
index 0000000000..3a30c8efe8
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/no_task_data.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_base_slide_block.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_base_slide_block.png
new file mode 100644
index 0000000000..ed7b293b90
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_base_slide_block.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data.png
new file mode 100644
index 0000000000..6349c77a8c
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data_speed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data_speed.png
new file mode 100644
index 0000000000..32151e5ada
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_bg_traffic_data_speed.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_big_end_maker_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_big_end_maker_icon.png
new file mode 100644
index 0000000000..438ee2136a
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_big_end_maker_icon.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_big_start_maker_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_big_start_maker_icon.png
new file mode 100644
index 0000000000..ba3747994c
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_big_start_maker_icon.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_car_big.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_car_big.png
new file mode 100644
index 0000000000..b30095f4c9
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_car_big.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_car_small.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_car_small.png
new file mode 100644
index 0000000000..c3762f55bb
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_car_small.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_card_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_card_normal.png
new file mode 100755
index 0000000000..ac5d521078
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_card_normal.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_card_pressed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_card_pressed.png
new file mode 100755
index 0000000000..34456d135f
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_card_pressed.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_clean_mode_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_clean_mode_icon.png
new file mode 100644
index 0000000000..cd3c35fe82
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_clean_mode_icon.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_close_navi_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_close_navi_icon.png
new file mode 100644
index 0000000000..56525e7ed2
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_close_navi_icon.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_collect_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_collect_normal.png
new file mode 100755
index 0000000000..2b220e1513
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_collect_normal.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_collect_pressed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_collect_pressed.png
new file mode 100755
index 0000000000..3ceca7609c
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_collect_pressed.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_full_screen_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_full_screen_icon.png
new file mode 100644
index 0000000000..f39894922d
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_full_screen_icon.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_ai_select.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_ai_select.png
new file mode 100755
index 0000000000..6da7b81fe4
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_ai_select.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_normal.png
new file mode 100755
index 0000000000..c0a978fc2b
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_normal.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_select.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_select.png
new file mode 100755
index 0000000000..22f88301f9
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_bad_case_select.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_close.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_close.png
new file mode 100755
index 0000000000..d17834748b
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_close.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_open.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_open.png
new file mode 100755
index 0000000000..73b03bc1f3
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_msg_box_open.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_not_select_subtask.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_not_select_subtask.png
new file mode 100755
index 0000000000..dc4c4f6f0d
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_not_select_subtask.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_select_subtask.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_select_subtask.png
new file mode 100755
index 0000000000..ed3b871338
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_icon_select_subtask.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_gay_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_gay_nor.png
new file mode 100644
index 0000000000..2b677df25f
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_gay_nor.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_green_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_green_nor.png
new file mode 100644
index 0000000000..bc9fed952d
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_green_nor.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_red_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_red_nor.png
new file mode 100644
index 0000000000..8732508ded
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_light_red_nor.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_lightyellow_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_lightyellow_nor.png
new file mode 100644
index 0000000000..bae01408fd
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_lightyellow_nor.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_line.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_line.png
new file mode 100755
index 0000000000..570b54f1be
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_line.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_loading_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_loading_nor.png
new file mode 100644
index 0000000000..0ff5309fab
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_loading_nor.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_navi_refresh.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_navi_refresh.png
new file mode 100644
index 0000000000..a3c3c32558
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_navi_refresh.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_och_dot_line.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_och_dot_line.png
new file mode 100644
index 0000000000..a720a532ea
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_och_dot_line.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_btn_bg.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_btn_bg.png
new file mode 100644
index 0000000000..ba41bf3a53
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_btn_bg.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_normal.png
new file mode 100755
index 0000000000..72a8664bef
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_normal.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_pressed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_pressed.png
new file mode 100755
index 0000000000..a765e75a41
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_setting_pressed.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_small_end_marker_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_small_end_marker_icon.png
new file mode 100644
index 0000000000..44eeb23a8f
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_small_end_marker_icon.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_small_start_marker_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_small_start_marker_icon.png
new file mode 100644
index 0000000000..b7cbac3f43
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_small_start_marker_icon.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_start_auto_not_running.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_start_auto_not_running.png
new file mode 100755
index 0000000000..76efae02cf
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_start_auto_not_running.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_start_auto_running.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_start_auto_running.png
new file mode 100755
index 0000000000..bef6342f64
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_start_auto_running.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_big_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_big_normal.png
new file mode 100644
index 0000000000..67c4ded462
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_big_normal.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_big_pressed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_big_pressed.png
new file mode 100755
index 0000000000..dbeae7fe2e
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_big_pressed.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_long.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_long.png
new file mode 100755
index 0000000000..cf3e5a3778
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_long.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_medium.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_medium.png
new file mode 100644
index 0000000000..bdc2725468
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_medium.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_small_normal.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_small_normal.png
new file mode 100755
index 0000000000..4ce0d75174
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_small_normal.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_small_pressed.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_small_pressed.png
new file mode 100755
index 0000000000..7c75d1e495
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_switch_map_small_pressed.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_list_left_select_icon.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_list_left_select_icon.png
new file mode 100644
index 0000000000..14a358eb90
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_list_left_select_icon.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_not_working.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_not_working.png
new file mode 100755
index 0000000000..45af8b7997
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_not_working.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_working.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_working.png
new file mode 100755
index 0000000000..f5bd232a66
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_task_working.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_traffic_data_speed_warning.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_traffic_data_speed_warning.png
new file mode 100644
index 0000000000..f68278023c
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_traffic_data_speed_warning.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_unselect_btn.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_unselect_btn.png
new file mode 100644
index 0000000000..0114bb4f2b
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/sweeper_unselect_btn.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_left_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_left_nor.png
new file mode 100644
index 0000000000..05e741771b
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_left_nor.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_left_select.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_left_select.png
new file mode 100644
index 0000000000..74ffe011f8
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_left_select.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_right_nor.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_right_nor.png
new file mode 100644
index 0000000000..ae19bd2d81
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_right_nor.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_right_select.png b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_right_select.png
new file mode 100644
index 0000000000..b6c41d676e
Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/res/drawable-xhdpi/turn_signal_right_select.png differ
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_bubble.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_bubble.xml
new file mode 100644
index 0000000000..9533060ae5
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_bubble.xml
@@ -0,0 +1,16 @@
+
+
+ -
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_clean_mode.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_clean_mode.xml
new file mode 100644
index 0000000000..57588e065f
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_clean_mode.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_dialog_no_title.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_dialog_no_title.xml
new file mode 100644
index 0000000000..e6970921d5
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_dialog_no_title.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_left_bottom_round.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_left_bottom_round.xml
new file mode 100644
index 0000000000..76e59781e4
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_left_bottom_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_left_right_bottom_round.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_left_right_bottom_round.xml
new file mode 100644
index 0000000000..bd0ab9d1e1
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_left_right_bottom_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_right_bottom_round.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_right_bottom_round.xml
new file mode 100644
index 0000000000..7fc3db37cc
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_right_bottom_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_panel.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_panel.xml
new file mode 100644
index 0000000000..3a6f72848e
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_panel.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_state_not_ready.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_state_not_ready.xml
new file mode 100644
index 0000000000..c808b231e8
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_state_not_ready.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_state_working.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_state_working.xml
new file mode 100644
index 0000000000..ad4e25124f
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_task_state_working.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_welt_panel.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_welt_panel.xml
new file mode 100644
index 0000000000..a6c900aa78
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_shape_welt_panel.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_close.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_close.xml
new file mode 100644
index 0000000000..8455e0cafb
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_close.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_default.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_default.xml
new file mode 100644
index 0000000000..3de0910dcd
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_disabled.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_disabled.xml
new file mode 100644
index 0000000000..16e880f1a2
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_disabled.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_open.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_open.xml
new file mode 100644
index 0000000000..ec0eeb317b
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_open.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_pressed.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_pressed.xml
new file mode 100644
index 0000000000..4e57ba75b0
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_sweeper_operate_panel_btn_pressed.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_task_menu.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_task_menu.xml
new file mode 100644
index 0000000000..1df3248028
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/bg_task_menu.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/icon_more.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/icon_more.xml
new file mode 100644
index 0000000000..3d348cf41a
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/icon_more.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_ai_collect_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_ai_collect_selector.xml
new file mode 100755
index 0000000000..b0d14bd0c6
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_ai_collect_selector.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_bad_case_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_bad_case_selector.xml
new file mode 100755
index 0000000000..0ad963da07
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_bad_case_selector.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_bg_waring_limiting_velocity.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_bg_waring_limiting_velocity.xml
new file mode 100644
index 0000000000..fe190c59ee
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_bg_waring_limiting_velocity.xml
@@ -0,0 +1,21 @@
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_collect_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_collect_selector.xml
new file mode 100644
index 0000000000..8ed41c58fb
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_collect_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend1.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend1.xml
new file mode 100644
index 0000000000..3698943bc9
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend1.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend2.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend2.xml
new file mode 100644
index 0000000000..d521b0a45d
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend2.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend3.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend3.xml
new file mode 100644
index 0000000000..59edb172fa
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend3.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend4.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend4.xml
new file mode 100644
index 0000000000..2a4efb7072
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend4.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend5.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend5.xml
new file mode 100644
index 0000000000..c3ac48e545
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend5.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend6.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend6.xml
new file mode 100644
index 0000000000..a8b8ac1b06
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_legend6.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_list_left_top_line.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_list_left_top_line.xml
new file mode 100644
index 0000000000..9d92ddd223
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_list_left_top_line.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_message_box.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_message_box.xml
new file mode 100644
index 0000000000..64c1e9d72e
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_message_box.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operate_panel_btn1_bg_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operate_panel_btn1_bg_selector.xml
new file mode 100644
index 0000000000..ba7719ba91
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operate_panel_btn1_bg_selector.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operate_panel_btn2_bg_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operate_panel_btn2_bg_selector.xml
new file mode 100755
index 0000000000..c51538216c
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operate_panel_btn2_bg_selector.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_bg.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_bg.xml
new file mode 100644
index 0000000000..4d612cb98f
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_bg.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_bg_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_bg_selector.xml
new file mode 100755
index 0000000000..996c623455
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_bg_selector.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_select_bg.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_select_bg.xml
new file mode 100644
index 0000000000..647222f919
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_operation_status_select_bg.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_oprate_panel_cancel_btn.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_oprate_panel_cancel_btn.xml
new file mode 100644
index 0000000000..7728783fa7
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_oprate_panel_cancel_btn.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_oprate_panel_reset_btn.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_oprate_panel_reset_btn.xml
new file mode 100644
index 0000000000..a0be0f0b9e
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_oprate_panel_reset_btn.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_panel_anchor_bkg.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_panel_anchor_bkg.xml
new file mode 100644
index 0000000000..21b39b7e37
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_panel_anchor_bkg.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_panel_bkg.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_panel_bkg.xml
new file mode 100644
index 0000000000..69539ed40f
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_panel_bkg.xml
@@ -0,0 +1,19 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_refresh.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_refresh.xml
new file mode 100644
index 0000000000..58e3089f6f
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_refresh.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_selector_msg_box.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_selector_msg_box.xml
new file mode 100644
index 0000000000..142a5bc514
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_selector_msg_box.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_setting_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_setting_selector.xml
new file mode 100644
index 0000000000..a6d5c8df82
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_setting_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_station_green_dash_line.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_station_green_dash_line.xml
new file mode 100644
index 0000000000..ff80eb9103
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_station_green_dash_line.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_station_v_green_dash.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_station_v_green_dash.xml
new file mode 100644
index 0000000000..f43c213363
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_station_v_green_dash.xml
@@ -0,0 +1,11 @@
+
+
+ -
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_card_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_card_selector.xml
new file mode 100644
index 0000000000..70950d6361
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_card_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_bg.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_bg.xml
new file mode 100644
index 0000000000..943ebcac05
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_bg.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_big_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_big_selector.xml
new file mode 100644
index 0000000000..9acad62868
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_big_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_small_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_small_selector.xml
new file mode 100644
index 0000000000..3a4b699d93
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_switch_map_small_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_dividing_line1_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_dividing_line1_selector.xml
new file mode 100644
index 0000000000..b00fbd8bd6
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_dividing_line1_selector.xml
@@ -0,0 +1,8 @@
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_dividing_line2_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_dividing_line2_selector.xml
new file mode 100644
index 0000000000..55353f3ca8
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_dividing_line2_selector.xml
@@ -0,0 +1,8 @@
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_list_btn.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_list_btn.xml
new file mode 100644
index 0000000000..9307ba16bd
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_list_btn.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_list_not_selected.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_list_not_selected.xml
new file mode 100644
index 0000000000..11995408cb
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_list_not_selected.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_list_selected.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_list_selected.xml
new file mode 100644
index 0000000000..6d189929bc
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_task_list_selected.xml
@@ -0,0 +1,10 @@
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_water_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_water_selector.xml
new file mode 100755
index 0000000000..9c959df076
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/sweeper_water_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/turn_signal_left_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/turn_signal_left_selector.xml
new file mode 100755
index 0000000000..45c8f084e4
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/turn_signal_left_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/drawable/turn_signal_right_selector.xml b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/turn_signal_right_selector.xml
new file mode 100755
index 0000000000..97e3b8de55
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/drawable/turn_signal_right_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_manual_driving.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_manual_driving.xml
new file mode 100644
index 0000000000..c6fca84ec2
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_manual_driving.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_no_title.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_no_title.xml
new file mode 100644
index 0000000000..4ed2048fdd
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/dialog_sweeper_no_title.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/fragment_och_sweeper.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/fragment_och_sweeper.xml
new file mode 100644
index 0000000000..5f11cfe729
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/fragment_och_sweeper.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/fragment_welt_map_overview.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/fragment_welt_map_overview.xml
new file mode 100644
index 0000000000..e5655ea229
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/fragment_welt_map_overview.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_amap_navi_view.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_amap_navi_view.xml
new file mode 100644
index 0000000000..4653dc9dcf
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_amap_navi_view.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_base_fragment.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_base_fragment.xml
new file mode 100644
index 0000000000..1039ecdcc6
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_base_fragment.xml
@@ -0,0 +1,272 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_current_task_info.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_current_task_info.xml
new file mode 100644
index 0000000000..1b0482afa6
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_current_task_info.xml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_item_legend.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_item_legend.xml
new file mode 100644
index 0000000000..cb9c40f195
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_item_legend.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_item_task_info.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_item_task_info.xml
new file mode 100644
index 0000000000..69ec1c1128
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_item_task_info.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_limiting_speed.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_limiting_speed.xml
new file mode 100644
index 0000000000..1938d21ff5
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_limiting_speed.xml
@@ -0,0 +1,17 @@
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_no_data_common_view.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_no_data_common_view.xml
new file mode 100644
index 0000000000..2532275d52
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_no_data_common_view.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_operate_panel_view.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_operate_panel_view.xml
new file mode 100644
index 0000000000..5c4e019611
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_operate_panel_view.xml
@@ -0,0 +1,298 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_popwindow_operate_panel.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_popwindow_operate_panel.xml
new file mode 100644
index 0000000000..2c4a7c470e
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_popwindow_operate_panel.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_subtask_view.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_subtask_view.xml
new file mode 100644
index 0000000000..25964e716b
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_subtask_view.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_task_menu.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_task_menu.xml
new file mode 100644
index 0000000000..f62a58d93c
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_task_menu.xml
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_test_bar_view.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_test_bar_view.xml
new file mode 100644
index 0000000000..4322fdf328
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_test_bar_view.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_traffic_data.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_traffic_data.xml
new file mode 100644
index 0000000000..7c71a6b184
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_traffic_data.xml
@@ -0,0 +1,169 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_traffic_light_view.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_traffic_light_view.xml
new file mode 100644
index 0000000000..dd319f141c
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_traffic_light_view.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_turn_signal.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_turn_signal.xml
new file mode 100644
index 0000000000..6ad67d647f
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_turn_signal.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_welt_map_overview.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_welt_map_overview.xml
new file mode 100644
index 0000000000..16a9957c97
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_welt_map_overview.xml
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_welt_small_map_view.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_welt_small_map_view.xml
new file mode 100644
index 0000000000..515958f87d
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_welt_small_map_view.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_work_mode.xml b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_work_mode.xml
new file mode 100644
index 0000000000..f2e743be58
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/layout/sweeper_work_mode.xml
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/values/attrs.xml b/OCH/sweeper/sweeper-cloud/src/main/res/values/attrs.xml
new file mode 100644
index 0000000000..396db92f74
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/values/attrs.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/values/colors.xml b/OCH/sweeper/sweeper-cloud/src/main/res/values/colors.xml
new file mode 100644
index 0000000000..996be7663a
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/values/colors.xml
@@ -0,0 +1,65 @@
+
+
+ #FF1FA7FF
+ #FFFFFFFF
+ #FFFFFFFF
+ #FF51649D
+ #7F8299EB
+
+ #51649D
+ #427d8e
+ #1FA7FF
+ #3FC281
+ #427d8e
+ #3FC281
+
+ #FFFFFF
+ #99FFFFFF
+ #FF52BBFF
+
+ #BF30334C
+ #fff
+ #f1f1f1
+
+ #7DE261
+ #FF2B2B
+ #E3BC59
+ #FFF
+ #256BFF
+ #FFFFFF
+
+ #DB3137
+ #3E77F6
+ #323C6F
+
+ #19FFFFFF
+ #FFFFFF
+
+ #FFFFA28B
+ #FFDA1100
+ #FF60FFD3
+ #FF006D43
+ #FFFFE198
+ #FFFF9B00
+
+ #7DE261
+ #f00
+ #BF30334C
+ #548DB8
+ #1FA7FF
+ #3769B5
+ #BF30334C
+
+
+ #C22101
+
+ #4DFFA4
+
+ #FFDD4D
+
+ #FF912B
+
+ #3BA1CC
+
+ #236299
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/values/dimens.xml b/OCH/sweeper/sweeper-cloud/src/main/res/values/dimens.xml
new file mode 100644
index 0000000000..8cc4e2b53a
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/values/dimens.xml
@@ -0,0 +1,154 @@
+
+
+
+ 300dp
+ 348dp
+ 211dp
+ 276dp
+
+
+ 220dp
+ 98dp
+ 159dp
+
+ 32dp
+ 20dp
+ 26dp
+ 42dp
+
+ 15dp
+
+ 20dp
+ 36dp
+ 28dp
+ 36dp
+
+ 3dp
+ 3dp
+ 17dp
+ 17dp
+
+
+ 300dp
+ 270dp
+ 30dp
+ 24dp
+ 24dp
+ 1dp
+ 30dp
+ 23dp
+ 30dp
+ 146dp
+ 20dp
+ 23dp
+ 30dp
+ 23dp
+ 26dp
+ 34dp
+ 20dp
+ 80dp
+ 3dp
+ 34dp
+ 20dp
+ 28dp
+ 27dp
+
+ 25.6dp
+ 20dp
+ 20dp
+ 64dp
+ 16dp
+
+ 40dp
+ 40dp
+ 46dp
+ 24dp
+
+ 530dp
+ 492dp
+
+ 20dp
+ 20dp
+ 70dp
+ 130dp
+ 93dp
+ 150dp
+ 70dp
+
+ 24dp
+ 616dp
+ 180dp
+
+ 112dp
+ 112dp
+
+ 92dp
+
+ 30dp
+ 616dp
+ 754dp
+
+ 40dp
+ 13dp
+ 12dp
+ 350dp
+
+ 460dp
+ 30dp
+
+ 110dp
+ 40dp
+ 320dp
+ 20dp
+ 40dp
+ 320dp
+ 460dp
+ 70dp
+ 460dp
+ 130dp
+ 30dp
+
+ 10dp
+ 20dp
+ 200dp
+ 52dp
+ 65dp
+ 20dp
+ 50dp
+ 20dp
+ 38dp
+ 33dp
+ 368dp
+ 76dp
+ 60dp
+
+ 276dp
+ 112dp
+ 22dp
+ 36dp
+ 50dp
+ 822dp
+
+ 46dp
+ 700dp
+ 120dp
+ 560dp
+ 116dp
+ 50dp
+
+ 225dp
+ 154dp
+ 60dp
+ 40dp
+ 23dp
+ 210dp
+ 120dp
+ 15dp
+ 17dp
+ 140dp
+ 130dp
+ 60dp
+
+ 13dp
+ 32dp
+
\ No newline at end of file
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/values/strings.xml b/OCH/sweeper/sweeper-cloud/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..825239b64f
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/values/strings.xml
@@ -0,0 +1,28 @@
+
+ 近距视角
+ 远距视角
+ 启动中…
+ 启动成功
+ 启动失败
+ 自动驾驶
+ 路线列表
+ 路线:
+ 起点:
+ 终点:
+ 确认
+ 准备出发
+ 自动驾驶中,不可切换路线
+ 当前行程未完成,不可切换路线
+ 当前暂无任务
+ 起点:
+ 终点:
+ 更换路线成功
+ 更换路线失败
+ 起点:
+ 终点:
+ 当前站点:
+ 下一站:
+ 自动驾驶状态为0不可用
+ 预计等待%d秒
+ 请保持档位在N档并拉起手刹后启动自动驾驶
+
diff --git a/OCH/sweeper/sweeper-cloud/src/main/res/values/style.xml b/OCH/sweeper/sweeper-cloud/src/main/res/values/style.xml
new file mode 100644
index 0000000000..1f8f971a41
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/main/res/values/style.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/OCH/sweeper/sweeper-cloud/src/test/java/com/mogo/och/sweeper/ExampleUnitTest.kt b/OCH/sweeper/sweeper-cloud/src/test/java/com/mogo/och/sweeper/ExampleUnitTest.kt
new file mode 100644
index 0000000000..1afdb5acad
--- /dev/null
+++ b/OCH/sweeper/sweeper-cloud/src/test/java/com/mogo/och/sweeper/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.mogo.och.sweeper
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 881db2900c..79b3909b30 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -272,7 +272,8 @@ android {
apply from: "./script/productFlavors/charter.gradle"
apply from: "./script/productFlavors/noop.gradle"
apply from: "./script/productFlavors/shuttle.gradle"
- apply from: "./script/productFlavors/sweeper.gradle"
+ apply from: "./script/productFlavors/sweeperOperate.gradle"
+ apply from: "./script/productFlavors/sweeperCloud.gradle"
apply from: "./script/productFlavors/taxi.gradle"
// 配置不同渠道参数,直接影响功能完整度
apply from: "./script/vehicleFlavors/fPadLenovo.gradle"
diff --git a/app/script/flavorfilter/flavors.json b/app/script/flavorfilter/flavors.json
index 9fd192a912..a03317857b 100644
--- a/app/script/flavorfilter/flavors.json
+++ b/app/script/flavorfilter/flavors.json
@@ -3,7 +3,10 @@
"noop" :{
"driver":["fPadLenovo"]
},
- "sweeper" :{
+ "sweeperOperate" :{
+ "driver": ["ochFT"]
+ },
+ "sweeperCloud" :{
"driver": ["ochFT"]
},
"shuttle" :{
@@ -36,7 +39,7 @@
}
},
"yantai": {
- "sweeper" :{
+ "sweeperOperate" :{
"driver": ["ochFT"]
},
"shuttle" :{
diff --git a/app/script/productFlavors/sweeperCloud.gradle b/app/script/productFlavors/sweeperCloud.gradle
new file mode 100644
index 0000000000..5c9bbc338c
--- /dev/null
+++ b/app/script/productFlavors/sweeperCloud.gradle
@@ -0,0 +1,32 @@
+project.android.productFlavors {
+ // 清扫车业务
+ sweeperCloud {
+ dimension "product"
+
+ manifestPlaceholders = [
+ // 标识
+ CHANNEL_VALUE_HEAD: "Sweeper",
+ // 在启动的时候把Task给清空
+ ACTIVITY_ROOT : true,
+ // Activity的朝向
+ SCREEN_ORIENTATION:"landscape",
+ ]
+
+ // ①标识
+ buildConfigField 'String', 'APP_IDENTITY_MODE_HEAD', "\"Sweeper\""
+
+ // ②连接的工控机IP地址
+ buildConfigField 'String', 'ADAS_CONNECT_IP', "\"192.168.8.102\""
+
+ // ③是否需要重写状态栏
+ buildConfigField 'boolean', 'IS_REPLACE_STATUSVIEW', 'false'
+
+ // ④构建 是否支持多屏异显异交互
+ buildConfigField 'boolean', 'IS_MULTI_DISPLAY', 'false'
+
+
+ if(isCurrentFlavors("sweeperCloud")){
+ project.dependencies.add('implementation', project.project(':OCH:sweeper:sweeper-cloud'))
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/script/productFlavors/sweeper.gradle b/app/script/productFlavors/sweeperOperate.gradle
similarity index 93%
rename from app/script/productFlavors/sweeper.gradle
rename to app/script/productFlavors/sweeperOperate.gradle
index 8493f0b84b..5a576b8117 100644
--- a/app/script/productFlavors/sweeper.gradle
+++ b/app/script/productFlavors/sweeperOperate.gradle
@@ -1,6 +1,6 @@
project.android.productFlavors {
// 清扫车业务
- sweeper {
+ sweeperOperate {
dimension "product"
manifestPlaceholders = [
@@ -25,7 +25,7 @@ project.android.productFlavors {
buildConfigField 'boolean', 'IS_MULTI_DISPLAY', 'false'
- if(isCurrentFlavors("sweeper")){
+ if(isCurrentFlavors("sweeperOperate")){
project.dependencies.add('implementation', project.project(':OCH:sweeper:sweeper'))
}
}
diff --git a/settings.gradle b/settings.gradle
index 2099541b75..bcbe858e68 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -64,6 +64,7 @@ include ':OCH:mogo-och-taxi-passenger'
include ':OCH:mogo-och-noop'
include(':OCH:mogo-och-common-module')
include ':OCH:sweeper:sweeper'
+include ':OCH:sweeper:sweeper-cloud'
include ':OCH:mogo-och-charter'
include ':OCH:mogo-och-charter-passenger'
include ':OCH:mogo-och-shuttle'