endSitePoint;
+ public String carNumber;
+ public long createTime;
+ public long startTime;
+ public List< Double > startSiteGcjPoint;
+ public List< Double > endSiteGcjPoint;
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperOperationStatusRequest.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperOperationStatusRequest.java
new file mode 100644
index 0000000000..c8b9995b24
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperOperationStatusRequest.java
@@ -0,0 +1,42 @@
+package com.mogo.och.sweeper.bean;
+
+import com.mogo.cloud.passport.MoGoAiCloudClientConfig;
+
+public
+/**
+ * @author congtaowang
+ * @since 2021/3/22
+ *
+ * 小巴车运营状态请求参数
+ */
+class SweeperOperationStatusRequest {
+
+ private String sn;
+ private double lat;
+ private double lon;
+ public SweeperOperationStatusRequest(double lon, double lat) {
+ this.sn = MoGoAiCloudClientConfig.getInstance().getSn();
+ this.lat = lat;
+ this.lon = lon;
+ }
+ public void setLat(double lat) {
+ this.lat = lat;
+ }
+
+ public void setLon(double lon) {
+ this.lon = lon;
+ }
+
+ public String getSn() {
+ return sn;
+ }
+
+ public double getLat() {
+ return lat;
+ }
+
+ public double getLon() {
+ return lon;
+ }
+
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperOperationStatusResponse.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperOperationStatusResponse.java
new file mode 100644
index 0000000000..664def47df
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperOperationStatusResponse.java
@@ -0,0 +1,20 @@
+package com.mogo.och.sweeper.bean;
+
+import com.mogo.eagle.core.data.BaseData;
+
+/**
+ * @author congtaowang
+ * @since 2021/3/22
+ *
+ * 小巴车运营状态返回参数
+ */
+public class SweeperOperationStatusResponse extends BaseData {
+
+ public Result data;
+
+ public static class Result {
+
+ public int serviceStatus;//0:已收车,1:已出车
+
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperOrderBean.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperOrderBean.java
new file mode 100644
index 0000000000..14be117b5b
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperOrderBean.java
@@ -0,0 +1,86 @@
+package com.mogo.och.sweeper.bean;
+
+/**
+ * @author congtaowang
+ * @since 2021/3/23
+ *
+ * 小巴订单
+ */
+public class SweeperOrderBean {
+
+ /**
+ * orderNo number
+ * passengerPhone string 下单用户电话
+ * startStationId integer 开始站点
+ * startStationName string
+ * endStationId integer 结束站点
+ * endStationName string
+ */
+
+ private String orderNo;
+ private String passengerPhone;
+ private int startStationId;//乘客上车点
+ private String startStationName;
+ private String endStationName;
+ private int endStationId;//乘客下车点
+
+ public void setOrderNo(String orderNo) {
+ this.orderNo = orderNo;
+ }
+
+ public void setPassengerPhone(String passengerPhone) {
+ this.passengerPhone = passengerPhone;
+ }
+
+ public void setStartStationId(int startStationId) {
+ this.startStationId = startStationId;
+ }
+
+ public void setStartStationName(String startStationName) {
+ this.startStationName = startStationName;
+ }
+
+ public void setEndStationName(String endStationName) {
+ this.endStationName = endStationName;
+ }
+
+ public void setEndStationId(int endStationId) {
+ this.endStationId = endStationId;
+ }
+
+ public String getOrderNo() {
+ return orderNo;
+ }
+
+ public String getPassengerPhone() {
+ return passengerPhone;
+ }
+
+ public int getStartStationId() {
+ return startStationId;
+ }
+
+ public String getStartStationName() {
+ return startStationName;
+ }
+
+ public String getEndStationName() {
+ return endStationName;
+ }
+
+ public int getEndStationId() {
+ return endStationId;
+ }
+
+ @Override
+ public String toString() {
+ return "BusOrderBean{" +
+ "orderNo=" + orderNo +
+ ", passengerPhone='" + passengerPhone + '\'' +
+ ", startStationId=" + startStationId +
+ ", startStationName='" + startStationName + '\'' +
+ ", endStationName='" + endStationName + '\'' +
+ ", endStationId=" + endStationId +
+ '}';
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperOrdersResponse.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperOrdersResponse.java
new file mode 100644
index 0000000000..38ab2a6e4e
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperOrdersResponse.java
@@ -0,0 +1,23 @@
+package com.mogo.och.sweeper.bean;
+
+import com.mogo.eagle.core.data.BaseData;
+
+import java.util.List;
+
+/**
+ * @author: wangmingjun
+ * @date: 2021/10/19
+ */
+public class SweeperOrdersResponse extends BaseData {
+ public Result data;
+ public static class Result{
+ public List orders;
+ }
+
+ @Override
+ public String toString() {
+ return "BusOrdersResponse{" +
+ "data=" + data +
+ '}';
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperQueryLineStationsRequest.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperQueryLineStationsRequest.java
new file mode 100644
index 0000000000..2289886b1a
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperQueryLineStationsRequest.java
@@ -0,0 +1,61 @@
+package com.mogo.och.sweeper.bean;
+
+import com.mogo.cloud.passport.MoGoAiCloudClientConfig;
+/**
+ * @author congtaowang
+ * @since 2021/3/22
+ *
+ * 根据车机行驶线路站点信息
+ */
+public class SweeperQueryLineStationsRequest {
+
+ private String sn;
+ private double lat;
+ private double lon;
+ private boolean markDrivingStatus; // 默认false;true:是否需要返回站点的行驶状态,对应返回的drivingStatus
+ // 0 - 关闭、1 - 启动
+// public String status;
+ public SweeperQueryLineStationsRequest(double lon, double lat, boolean markDrivingStatus) {
+ this.sn = MoGoAiCloudClientConfig.getInstance().getSn();
+ this.lat = lat;
+ this.lon = lon;
+ this.markDrivingStatus = markDrivingStatus;
+ }
+
+ public boolean isMarkDrivingStatus() {
+ return markDrivingStatus;
+ }
+
+ public void setMarkDrivingStatus(boolean markDrivingStatus) {
+ this.markDrivingStatus = markDrivingStatus;
+ }
+
+ public void setLat(double lat) {
+ this.lat = lat;
+ }
+
+ public void setLon(double lon) {
+ this.lon = lon;
+ }
+
+ public String getSn() {
+ return sn;
+ }
+
+ public double getLat() {
+ return lat;
+ }
+
+ public double getLon() {
+ return lon;
+ }
+ // public BusOperationStatusRequest shutdown() {
+// status = "0";
+// return this;
+// }
+//
+// public BusOperationStatusRequest launch() {
+// status = "1";
+// return this;
+// }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperQueryLinesResponse.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperQueryLinesResponse.java
new file mode 100644
index 0000000000..e1cf271b2d
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperQueryLinesResponse.java
@@ -0,0 +1,23 @@
+package com.mogo.och.sweeper.bean;
+
+import com.mogo.eagle.core.data.BaseData;
+
+import java.util.List;
+
+/**
+ * @author: wangmingjun
+ * @date: 2022/2/9
+ */
+public class SweeperQueryLinesResponse extends BaseData {
+ public List data;
+
+ public static class Result {
+
+ public int lineId;//线路id
+ public String name;//线路名字
+ public int choose; // 1:绑定 2:未被绑定
+ public String startSiteName;//始发站名称
+ public String endSiteName;//终点名称
+
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperResetDrivingLineRequest.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperResetDrivingLineRequest.java
new file mode 100644
index 0000000000..718ba66504
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperResetDrivingLineRequest.java
@@ -0,0 +1,17 @@
+package com.mogo.och.sweeper.bean;
+
+import com.mogo.cloud.passport.MoGoAiCloudClientConfig;
+
+/**
+ * @author: wangmingjun
+ * @date: 2021/10/18
+ */
+public class SweeperResetDrivingLineRequest {
+ public String sn;
+ public int lineId; //切换到的线路id
+
+ public SweeperResetDrivingLineRequest(int lineId) {
+ sn = MoGoAiCloudClientConfig.getInstance().getSn();
+ this.lineId = lineId;
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperRoutePlanningUpdateReqBean.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperRoutePlanningUpdateReqBean.java
new file mode 100644
index 0000000000..9d58dbb4c4
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperRoutePlanningUpdateReqBean.java
@@ -0,0 +1,30 @@
+package com.mogo.och.sweeper.bean;
+
+import java.util.List;
+
+/**
+ * Created by pangfan on 2021/8/19
+ *
+ * 订单状态更新请求数据结构
+ */
+public class SweeperRoutePlanningUpdateReqBean {
+ public String sn;
+ public int lineId;
+ public int startSiteId;
+ public int endSiteId;
+ public List points;
+
+ public static class Result {
+ public Double latitude;
+ public Double longitude;
+ }
+
+ public SweeperRoutePlanningUpdateReqBean(String sn, int lineId, int startSiteId
+ , int endSiteId, List points) {
+ this.sn = sn;
+ this.lineId = lineId;
+ this.startSiteId = startSiteId;
+ this.endSiteId = endSiteId;
+ this.points = points;
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperRoutesResponse.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperRoutesResponse.java
new file mode 100644
index 0000000000..6779f61b80
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperRoutesResponse.java
@@ -0,0 +1,27 @@
+package com.mogo.och.sweeper.bean;
+
+import com.mogo.eagle.core.data.BaseData;
+
+/**
+ * 网约车小巴路线接口请求响应结果
+ *
+ * @author tongchenfei
+ */
+public class SweeperRoutesResponse extends BaseData {
+ private SweeperRoutesResult data;
+
+ public SweeperRoutesResult getResult() {
+ return data;
+ }
+
+ public void setResult(SweeperRoutesResult data) {
+ this.data = data;
+ }
+
+ @Override
+ public String toString() {
+ return "BusRoutesResponse{" +
+ "data=" + data +
+ '}';
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperRoutesResult.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperRoutesResult.java
new file mode 100644
index 0000000000..545304b948
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperRoutesResult.java
@@ -0,0 +1,69 @@
+package com.mogo.och.sweeper.bean;
+
+import java.util.List;
+
+/**
+ * 网约车小巴路线接口返回接口数据封装
+ *
+ * @author tongchenfei
+ */
+public class SweeperRoutesResult {
+ private List sites;
+ private int lineId;
+ private String name;
+ private int lineType; //线路类型,0:环形
+ private String description;
+ private int status;
+
+ //线路轨迹相关字段
+ public String csvFileUrl = ""; //轨迹文件下载的cos url,默认“”
+ public String csvFileMd5 = ""; //轨迹文件md5,默认“”
+ public String txtFileUrl = ""; //打点文件下载的cos url,默认“”
+ public String txtFileMd5 = ""; //轨迹文件md5,默认“”
+ public long contrailSaveTime; //上传轨迹完成时间戳ms:用于MEC本地手动导入轨迹验证时不会被云端轨迹覆盖
+ public String carModel = ""; //[optional] 车型号(如红旗H9),默认“”,暂不加入校验逻辑、用于人工排查问题
+ public String csvFileUrlDPQP = ""; //轨迹文件下载的cos url,默认“”
+ public String csvFileMd5DPQP = ""; //轨迹文件md5,默认“”
+ public String txtFileUrlDPQP = ""; //打点文件下载的cos url,默认“”
+ public String txtFileMd5DPQP = ""; //轨迹文件md5,默认“”
+ public long contrailSaveTimeDPQP; //上传轨迹完成时间戳ms:用于MEC本地手动导入轨迹验证时不会被云端轨迹覆盖
+
+ public int getLineId() {
+ return lineId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public List getSites() {
+ return sites;
+ }
+
+ public void setSite(List site) {
+ this.sites = sites;
+ }
+
+ @Override
+ public String toString() {
+ return "BusRoutesResult{" +
+ "sites=" + sites +
+ ", lineId=" + lineId +
+ ", name='" + name + '\'' +
+ ", lineType=" + lineType +
+ ", description='" + description + '\'' +
+ ", status=" + status +
+ ", csvFileUrl='" + csvFileUrl + '\'' +
+ ", csvFileMd5='" + csvFileMd5 + '\'' +
+ ", txtFileUrl='" + txtFileUrl + '\'' +
+ ", txtFileMd5='" + txtFileMd5 + '\'' +
+ ", contrailSaveTime=" + contrailSaveTime +
+ ", carModel='" + carModel + '\'' +
+ ", csvFileUrlDPQP='" + csvFileUrlDPQP + '\'' +
+ ", csvFileMd5DPQP='" + csvFileMd5DPQP + '\'' +
+ ", txtFileUrlDPQP='" + txtFileUrlDPQP + '\'' +
+ ", txtFileMd5DPQP='" + txtFileMd5DPQP + '\'' +
+ ", contrailSaveTimeDPQP=" + contrailSaveTimeDPQP +
+ '}';
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperStationBean.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperStationBean.java
new file mode 100644
index 0000000000..ad4fef2b65
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperStationBean.java
@@ -0,0 +1,162 @@
+package com.mogo.och.sweeper.bean;
+
+/**
+ * 单个网约车小巴车站信息
+ *
+ * @author tongchenfei
+ */
+public class SweeperStationBean {
+// private int lineId;
+// private int siteId;
+// private String siteName;
+// private String cityCode;
+// private String areaCode;
+// private String areaName;
+// private double lat;
+// private double lon;
+// private String siteDesc;
+// private int siteState;
+// private int isCurrentSite;// @see OchBusConst 是否是当前站 1:是 2:下一站 0:普通站
+// private int siteColor;
+// private String peoples;
+// private int ifStop; // 是否需要停靠、1需要、0不需要
+
+
+ private String name;
+ private String description;
+ private String cityCode;
+ private double lon; //高精坐标
+ private double lat; //高精坐标
+ private int businessType; //站点类型,9:taxi,10:bus
+ private double gcjLon; //高德
+ private double gcjLat; //高德
+ private int status;
+ private int siteId;
+ private int seq;
+ private int drivingStatus;//行驶信息,0初始值;1已经过;2当前站;3未到站
+ private int ifStop = 1; // 是否需要停靠、1需要、0不需要 // TODO: 2021/10/19 原来站点里有设计是否需要停靠字段,现设计暂无,默认都需要停靠
+ private boolean leaving;
+
+ public double getGcjLon() {
+ return gcjLon;
+ }
+
+ public double getGcjLat() {
+ return gcjLat;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public void setCityCode(String cityCode) {
+ this.cityCode = cityCode;
+ }
+
+ public void setLon(double lon) {
+ this.lon = lon;
+ }
+
+ public void setLat(double lat) {
+ this.lat = lat;
+ }
+
+ public void setBusinessType(int businessType) {
+ this.businessType = businessType;
+ }
+
+ public void setStatus(int status) {
+ this.status = status;
+ }
+
+ public void setSiteId(int siteId) {
+ this.siteId = siteId;
+ }
+
+ public void setSeq(int seq) {
+ this.seq = seq;
+ }
+
+ public void setDrivingStatus(int drivingStatus) {
+ this.drivingStatus = drivingStatus;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getCityCode() {
+ return cityCode;
+ }
+
+
+ public int getBusinessType() {
+ return businessType;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ public int getSiteId() {
+ return siteId;
+ }
+
+ public int getSeq() {
+ return seq;
+ }
+
+ public int getDrivingStatus() {
+ return drivingStatus;
+ }
+
+ public double getLon() {
+ return lon;
+ }
+
+ public double getLat() {
+ return lat;
+ }
+
+ public void setIfStop(int ifStop) {
+ this.ifStop = ifStop;
+ }
+
+ public int getIfStop() {
+ return ifStop;
+ }
+
+ public void setLeaving(boolean leaving) {
+ this.leaving = leaving;
+ }
+
+ public boolean isLeaving() {
+ return leaving;
+ }
+
+ @Override
+ public String toString() {
+ return "BusStationBean{" +
+ "name='" + name + '\'' +
+ ", description='" + description + '\'' +
+ ", cityCode='" + cityCode + '\'' +
+ ", lon=" + lon +
+ ", lat=" + lat +
+ ", businessType=" + businessType +
+ ", status=" + status +
+ ", siteId=" + siteId +
+ ", seq=" + seq +
+ ", drivingStatus=" + drivingStatus +
+ ", ifStop=" + ifStop +
+ ", leaving=" + leaving +
+ '}';
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperUpdateSiteStatusRequest.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperUpdateSiteStatusRequest.java
new file mode 100644
index 0000000000..422d5113fa
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/bean/SweeperUpdateSiteStatusRequest.java
@@ -0,0 +1,26 @@
+package com.mogo.och.sweeper.bean;
+
+import com.mogo.cloud.passport.MoGoAiCloudClientConfig;
+
+/**
+ * @author congtaowang
+ * @since 2021/3/22
+ *
+ * 小巴车运营状态请求参数
+ */
+public class SweeperUpdateSiteStatusRequest {
+
+ public String sn;
+ public int seq;//站点序号
+ public int siteId;//站点id
+ public double lon;
+ public double lat;
+
+ public SweeperUpdateSiteStatusRequest(int seq, int siteId, double lon, double lat) {
+ this.sn = MoGoAiCloudClientConfig.getInstance().getSn();
+ this.seq = seq;
+ this.siteId = siteId;
+ this.lon = lon;
+ this.lat = lat;
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/ICarOperationStatusCallback.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/ICarOperationStatusCallback.java
new file mode 100644
index 0000000000..cdd2a06f24
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/ICarOperationStatusCallback.java
@@ -0,0 +1,9 @@
+package com.mogo.och.sweeper.callback;
+
+/**
+ * @author: wangmingjun
+ * @date: 2021/10/22
+ */
+public interface ICarOperationStatusCallback {
+ void changeOperationStatus(boolean changeStatus);
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/IRefreshSweeperStationsCallback.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/IRefreshSweeperStationsCallback.java
new file mode 100644
index 0000000000..f6fd3ae0ab
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/IRefreshSweeperStationsCallback.java
@@ -0,0 +1,13 @@
+package com.mogo.och.sweeper.callback;
+
+import com.mogo.och.sweeper.bean.SweeperStationBean;
+
+import java.util.List;
+
+/**
+ * @author: wangmingjun
+ * @date: 2021/10/22
+ */
+public interface IRefreshSweeperStationsCallback {
+ void refreshBusStations(String lineName, List stationList, int currentStation, int nextStation, boolean isArrived);
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/ISlidePannelHideCallback.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/ISlidePannelHideCallback.java
new file mode 100644
index 0000000000..246ccd2118
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/ISlidePannelHideCallback.java
@@ -0,0 +1,9 @@
+package com.mogo.och.sweeper.callback;
+
+/**
+ * @author: wangmingjun
+ * @date: 2021/10/22
+ */
+public interface ISlidePannelHideCallback {
+ void hideSlidePanel();
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/ISweeperControllerStatusCallback.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/ISweeperControllerStatusCallback.java
new file mode 100644
index 0000000000..95543610ff
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/ISweeperControllerStatusCallback.java
@@ -0,0 +1,17 @@
+package com.mogo.och.sweeper.callback;
+
+import android.location.Location;
+
+/**
+ * Created on 2021/9/10
+ *
+ * Model->Presenter回调:状态控制器监听(accOn、adas ui show、voice ui show、push ui show、v2x ui show等等)
+ */
+public interface ISweeperControllerStatusCallback {
+ // 是否vr map模式
+ void onVRModeChanged(boolean isVRMode);
+ // 自车定位
+ void onCarLocationChanged(Location location);
+ //开始开启自动驾驶
+ void startOpenAutopilot();
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/ISweeperLinesCallback.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/ISweeperLinesCallback.java
new file mode 100644
index 0000000000..74e166b736
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/callback/ISweeperLinesCallback.java
@@ -0,0 +1,12 @@
+package com.mogo.och.sweeper.callback;
+
+import com.mogo.och.sweeper.bean.SweeperQueryLinesResponse;
+
+/**
+ * @author: wangmingjun
+ * @date: 2022/2/9
+ */
+public interface ISweeperLinesCallback {
+ void onBusLinesChange(SweeperQueryLinesResponse lines);
+ void onChangeLineIdSuccess();
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/constant/SweeperConst.kt b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/constant/SweeperConst.kt
new file mode 100644
index 0000000000..9a534d3a85
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/constant/SweeperConst.kt
@@ -0,0 +1,79 @@
+package com.mogo.och.sweeper.constant
+
+import com.mogo.commons.debug.DebugConfig
+
+/**
+ * Created on 2021/12/6
+ */
+class SweeperConst {
+ companion object {
+
+ private const val BASE_URL_OCH_DEV = "http://tech-dev.zhidaohulian.com"
+ private const val BASE_URL_OCH_QA = "https://tech-qa.zhidaohulian.com"
+ private const val BASE_URL_OCH_RELEASE = "https://tech.zhidaohulian.com"
+
+ @JvmStatic
+ fun getBaseUrl(): String {
+ return when (DebugConfig.getNetMode()) {
+ DebugConfig.NET_MODE_DEV, DebugConfig.NET_MODE_DEMO -> BASE_URL_OCH_DEV
+ DebugConfig.NET_MODE_QA -> BASE_URL_OCH_QA
+ DebugConfig.NET_MODE_RELEASE -> BASE_URL_OCH_RELEASE
+ else -> BASE_URL_OCH_RELEASE
+ }
+ }
+
+ // OCH arouter 路由path
+ const val PATH = "/och/api"
+
+ // 测试用的广播
+ const val BROADCAST_TEST_SWEEPER_CONTROL_TYPE_EXTRA_KEY = "sceneType"
+ // 无状态
+ const val STATION_STATUS_IDLE = 0
+ // 已过站(历史站)
+ const val STATION_STATUS_LEAVING = 1
+ // 到站(当前站)
+ const val STATION_STATUS_STOPPED = 2
+ // 未到站(未到站)
+ const val STATION_STATUS_ARRIVING = 3
+
+ // 上报心跳轮询ms
+ const val LOOP_PERIOD_60S = 60 * 1000L
+ // 开始服务启动自动驾驶等待时间(埋点上传)
+ const val LOOP_PERIOD_15S = 15 * 1000L
+ const val LOOP_PERIOD_1S = 1 * 1000L
+ const val LOOP_DELAY = 100L
+
+ // 下发给MEC轨迹信息间隔时间 10秒
+ const val LOOP_PERIOD_10S = 10 * 1000L
+ // 尝试下发给MEC轨迹最多10次
+ const val LOOP_SEND_TRAJ_TIMES = 10
+
+ //起点UUID
+ const val SWEEPER_START_MAP_MAKER = "sweeper_start_map_maker";
+ //终点UUID
+ const val SWEEPER_END_MAP_MAKER = "sweeper_end_map_maker";
+
+ // 埋点key:接管后点击'自动驾驶'按钮启动
+ const val EVENT_KEY_RESTART_AUTOPILOT = "event_key_och_sweeper_restart_autopilot"
+ // 埋点key:开始服务开启自动驾驶(成功/失败)
+ const val EVENT_KEY_START_SERVICE = "event_key_och_sweeper_start_service"
+ const val EVENT_PARAM_SN = "sn"
+ const val EVENT_PARAM_TIME = "time"
+ const val EVENT_PARAM_START_NAME = "start_name"
+ const val EVENT_PARAM_END_NAME = "end_name"
+ const val EVENT_PARAM_LINE_ID = "line_id"
+ const val EVENT_PARAM_START_RESULT = "start_autopilot" // true/false
+ const val EVENT_PARAM_PLATE_NUM = "plate_number" // 车牌号
+ const val EVENT_PARAM_ENV_ONLINE = "env_online" // 是否线上环境:true/false
+
+ /**
+ * 订单起终点Marker类型
+ */
+ const val TYPE_MARKER_SWEEPER_ORDER = "TYPE_MARKER_SWEEPER_ORDER"
+
+ const val TIMER_START_AUTOPILOT_INTERVAL = 20 * 1000L
+
+ //围栏到站 暂定10米
+ const val ARRIVE_AT_END_STATION_DISTANCE = 10
+ }
+}
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperTabFragment.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperTabFragment.java
new file mode 100644
index 0000000000..552523aaa0
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperTabFragment.java
@@ -0,0 +1,571 @@
+package com.mogo.och.sweeper.fragment;
+
+import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS;
+import static com.mogo.och.sweeper.constant.SweeperConst.TIMER_START_AUTOPILOT_INTERVAL;
+
+import android.animation.ObjectAnimator;
+import android.content.Intent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.animation.LinearInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.Group;
+
+import com.mogo.commons.AbsMogoApplication;
+import com.mogo.commons.debug.DebugConfig;
+import com.mogo.commons.mvp.IView;
+import com.mogo.commons.mvp.MvpFragment;
+import com.mogo.commons.mvp.Presenter;
+import com.mogo.eagle.core.data.config.HmiBuildConfig;
+import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotRecordListener;
+import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener;
+import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager;
+import com.mogo.eagle.core.function.call.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.hmi.ui.widget.TrafficDataView;
+import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
+import com.mogo.eagle.core.utilcode.util.ToastUtils;
+import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
+import com.mogo.map.MogoMapUIController;
+import com.mogo.map.MogoMarkerManager;
+import com.mogo.map.listener.IMogoMapListener;
+import com.mogo.map.uicontroller.VisualAngleMode;
+import com.mogo.module.common.MogoApisHandler;
+import com.mogo.module.common.constants.DataTypes;
+import com.mogo.module.common.view.OnPreventFastClickListener;
+import com.mogo.och.sweeper.R;
+import com.mogo.och.sweeper.bean.SweeperRoutesResult;
+import com.mogo.och.sweeper.constant.SweeperConst;
+import com.mogo.och.sweeper.model.SweeperOrderModel;
+import com.mogo.och.sweeper.util.BDRouteDataTestUtils;
+import com.mogo.och.sweeper.view.SlidePanelView;
+
+import mogo.telematics.pad.MessagePad;
+import record_cache.RecordPanelOuterClass;
+
+/**
+ * 网约车基础Fragment,主要负责布局通用界面,处理站点面板和通话面板互斥情况
+ *
+ * 部分业务放在了此处处理
+ *
+ * @author tongchenfei
+ */
+public abstract class BaseSweeperTabFragment> extends MvpFragment implements IMogoMapListener, IMoGoAutopilotRecordListener {
+
+ private static final String TAG = "BaseOchFragment";
+
+ protected SlidePanelView slidePanelView;
+ private RelativeLayout ctvAutopilotStatus;
+ private ImageView ctvAutopilotStatusIv;
+ private TextView ctvAutopilotStatusTv;
+ protected TextView tvOperationStatus;
+ protected RelativeLayout mSettingBtn;
+ protected RelativeLayout mBadcaseBtn;
+ protected RelativeLayout mAICollectBtn;
+ public boolean isOperationStatus;//false-收车,true-出车
+ private FrameLayout flStationPanelContainer;
+ private Group groupTestPanel;
+ private FrameLayout flSpeed;
+// private BusArcView mouduleArc;
+ private TrafficDataView mTrafficDataView;
+ private ImageView mUpgradeTipIv;
+ // private BusTrafficLightView mTrafficLightView;
+
+ public static final String TYPE_ENTRANCE = "entrance";
+
+ //远景和中景的切换
+ private ImageView mSwitchMapModeImage;
+ private LinearLayout mSwitchMapModeLayout;
+
+ private ObjectAnimator autopilotLoadingAnimator;
+
+ public boolean isAnimateRunning = false;
+
+ /**
+ * 滑动按钮触发的事件
+ */
+ private final SlidePanelView.OnSlidePanelMoveToEndListener onSlideToEndListener = () -> {
+ // 此处做一个代理,处理一下共有情况
+ if (getSlidePanelOnEndListener() != null) {
+ getSlidePanelOnEndListener().moveToEnd();
+ }
+ };
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.sweeper_base_fragment;
+ }
+
+ private View panelView;
+
+ @Override
+ protected void initViews() {
+ groupTestPanel = findViewById(R.id.groupTestPanel);
+ slidePanelView = findViewById(R.id.module_mogo_och_slide_panel);
+ ctvAutopilotStatus = findViewById(R.id.module_mogo_och_autopilot_status);
+ ctvAutopilotStatusIv = findViewById(R.id.sweeper_autopilot_btn_iv);
+ ctvAutopilotStatusTv = findViewById(R.id.sweeper_autopolot_btn_tv);
+ flStationPanelContainer = findViewById(R.id.module_mogo_och_station_panel_container);
+
+ // mTrafficLightView = findViewById(R.id.bus_traffic_light_view);
+ // CallerHmiManager.INSTANCE.setProxyTrafficLightView(mTrafficLightView);
+
+ tvOperationStatus = findViewById(R.id.module_mogo_och_operation_status);
+
+ flSpeed = (FrameLayout) findViewById(R.id.fl_speed);
+ mTrafficDataView = (TrafficDataView) findViewById(R.id.sweeper_arc);
+
+ panelView = LayoutInflater.from(getContext()).inflate(getStationPanelViewId(), flStationPanelContainer);
+ slidePanelView.setOnSlidePanelMoveToEndListener(onSlideToEndListener);
+
+ mSwitchMapModeLayout = findViewById(R.id.sweeper_switch_model_layout);
+ mSwitchMapModeImage = findViewById(R.id.sweeper_switch_model_icon);
+ updateSwitchMapIcon();
+
+ mSwitchMapModeLayout.setOnClickListener(new OnPreventFastClickListener() {
+
+ @Override
+ public void onClickImpl(View v) {
+ //切换地图的远近视图
+ if (MogoMapUIController.getInstance().getCurrentMapVisualAngle().isLongSight()) {
+ MogoMarkerManager.getInstance(AbsMogoApplication.getApp()).visibleAllMarkers();
+ MogoMapUIController.getInstance().changeMapVisualAngle(VisualAngleMode.MODE_MEDIUM_SIGHT, null);
+ mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_medium);
+ } else if (MogoMapUIController.getInstance().getCurrentMapVisualAngle().isMediumSight()) {
+ MogoMarkerManager.getInstance(AbsMogoApplication.getApp())
+ .inVisibleWithoutMarkers(DataTypes.TYPE_MARKER_ADAS, SweeperConst.TYPE_MARKER_SWEEPER_ORDER);
+ MogoMapUIController.getInstance().changeMapVisualAngle(VisualAngleMode.MODE_LONG_SIGHT, null);
+ mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_long);
+ }
+ }
+ });
+
+ if (DebugConfig.isDebug()) {
+ mTrafficDataView.setLongClickable(true);
+ mTrafficDataView.setOnLongClickListener(v -> {
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "长按显示状态工具栏");
+ Intent intent = new Intent();
+ intent.putExtra("oper", 52);
+ MogoApisHandler.getInstance().getApis().getIntentManagerApi().invoke("com.mogo.mock", intent);
+ return true;
+ });
+ }
+ initListener();
+ ctvAutopilotStatus.setOnClickListener(new OnPreventFastClickListener(){
+
+ @Override
+ public void onClickImpl(View v) {
+// if (CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState() != IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE){
+ restartAutopilot();
+// }else {
+// ToastUtils.showShort(getResources().getString(R.string.sweeper_auto_disable_tip));
+// }
+ }
+ });
+
+ setAutopilotBtnStatus(CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState());
+ // 模拟 不可自动驾驶,目前场景是刚开机,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.btnAutopilotArrive).setOnClickListener(view ->
+ debugArrivedStation()
+ );
+
+ findViewById(R.id.btnAutopilotRoute).setOnClickListener(view -> debugArrivedRoute());
+
+ tvOperationStatus.setOnClickListener(view -> {
+ onChangeOperationStatus();
+ });
+
+ mSettingBtn = findViewById(R.id.module_mogo_och_setting_layout);
+ mSettingBtn.setOnClickListener(v -> {
+ // TODO: 2021/12/9
+ CallerHmiManager.INSTANCE.showToolsView();
+ });
+
+ // mBadcaseBtn的visible显示逻辑在showBadcaseEntrance内处理
+ mBadcaseBtn = findViewById(R.id.module_mogo_och_badcase_rl);
+// CallerHmiManager.INSTANCE.registerBadCaseCallback(
+// () -> { // onShow()
+// return mBadcaseBtn; },
+// () -> { // onHide()
+// return null; });
+
+ if (mBadcaseBtn != null) {
+ CallerDevaToolsManager.INSTANCE.initBadCase(mBadcaseBtn);
+ if (!HmiBuildConfig.isShowBadCaseView) {
+ CallerAutopilotRecordListenerManager.INSTANCE.addListener(TAG, this);
+ }
+ }
+
+ mAICollectBtn = findViewById(R.id.module_mogo_och_ai_collet_rl);
+ if (mAICollectBtn != null){
+ CallerDevaToolsManager.INSTANCE.initAiCollect(mAICollectBtn);
+ }
+ }
+
+ private void updateSwitchMapIcon(){
+ if (MogoMapUIController.getInstance().getCurrentMapVisualAngle().isLongSight()) {
+ mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_long);
+ } else if (MogoMapUIController.getInstance().getCurrentMapVisualAngle().isMediumSight()) {
+ mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_medium);
+ } else {
+ mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_medium);
+ }
+ }
+
+ private void debugArrivedRoute() {
+ BDRouteDataTestUtils.converToRouteData();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ if (!HmiBuildConfig.isShowBadCaseView) {
+ CallerAutopilotRecordListenerManager.INSTANCE.removeListener(TAG);
+ }
+ }
+
+
+ @Override
+ public void onAutopilotRecordResult(@Nullable RecordPanelOuterClass.RecordPanel recordPanel) {
+// if (!HmiBuildConfig.isShowBadCaseView && recordPanel != null && recordPanel.getType() == 1 && recordPanel.getStat() == 100) {
+// CallerDevaToolsManager.INSTANCE.onReceiveBadCaseRecord(recordPanel);
+// }
+ }
+
+ @Override
+ public void onAutopilotRecordConfig(@NonNull MessagePad.RecordDataConfig config) {
+ }
+
+
+ /**
+ * 测试到站
+ */
+ protected abstract void debugArrivedStation();
+
+ private void initListener() {
+ MogoApisHandler.getInstance().getApis().getRegisterCenterApi().registerMogoMapListener(TYPE_ENTRANCE, this);
+ }
+
+ protected void onChangeOperationStatus() {
+
+ }
+
+ /**
+ * 展示滑动按钮
+ *
+ * @param text 指定的文字
+ */
+ public void showSlidePanle(String text) {
+ if (isOperationStatus) {
+ getActivity().runOnUiThread(() -> {
+ slidePanelView.setText(text);
+ slidePanelView.setVisibility(View.VISIBLE);
+ });
+ }
+ }
+
+ /**
+ * 隐藏滑动按钮
+ */
+ public void hideSlidePanel() {
+ getActivity().runOnUiThread(() -> {
+ slidePanelView.setVisibility(View.GONE);
+ });
+ }
+
+ /**
+ * 改变自动驾驶状态
+ *
+ * @param autopilotStatus 0:不可用 1:可用状态 2:自动驾驶中
+ */
+ public void onAutopilotStatusChanged(int autopilotStatus) {
+ getActivity().runOnUiThread(() -> {
+ changeAutopilotBtnView(autopilotStatus, isAnimateRunning);
+ });
+ }
+
+ public void setAutopilotBtnStatus(int autopilotStatus) {
+ if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE
+ == autopilotStatus) {//0不可用
+ ctvAutopilotStatusTv.setTextColor(getResources().getColor(R.color.sweeper_autopilot_text_color_disable));
+ ctvAutopilotStatusTv.setText(getResources().getString(R.string.sweeper_loading_autopilot_runnig_tv));
+ ctvAutopilotStatusIv.setImageResource(R.drawable.sweeper_disable_autopilot_icon);
+ ctvAutopilotStatus.setSelected(false);
+ ctvAutopilotStatus.setFocusableInTouchMode(true);
+
+ } else {
+ ctvAutopilotStatusTv.setTextColor(getResources().getColor(R.color.sweeper_autopilot_text_color_normal));
+ ctvAutopilotStatusTv.setText(getResources().getString(R.string.sweeper_loading_autopilot_runnig_tv));
+ ctvAutopilotStatusIv.setImageResource(R.drawable.sweeper_ic_autopilot);
+ ctvAutopilotStatus.setFocusableInTouchMode(true);
+ if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE == autopilotStatus) {//1可用
+ ctvAutopilotStatus.setSelected(false);
+ }else if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING == autopilotStatus){
+ ctvAutopilotStatus.setSelected(true);
+ }
+ }
+ }
+
+ public void updateAutopilotStatus(int autopilotStatus){
+ if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING
+ == autopilotStatus) {//2 running
+ ctvAutopilotStatusIv.setImageResource(R.drawable.sweeper_right_autopilot_icon);
+ ctvAutopilotStatusTv.setTextColor(getResources().getColor(R.color.sweeper_autopilot_text_color_normal));
+ ctvAutopilotStatusTv.setText(getResources().getString(R.string.sweeper_loading_autopilot_success_tv));
+ ctvAutopilotStatus.setSelected(false);
+ ctvAutopilotStatus.setFocusableInTouchMode(false);
+ }else {
+ ctvAutopilotStatusIv.setImageResource(R.drawable.sweeper_wrong_autopilot_icon);
+ ctvAutopilotStatusTv.setTextColor(getResources().getColor(R.color.sweeper_autopilot_text_color_normal));
+ ctvAutopilotStatusTv.setText(getResources().getString(R.string.sweeper_loading_autopilot_failure_tv));
+ ctvAutopilotStatus.setFocusableInTouchMode(false);
+ ctvAutopilotStatus.setSelected(false);
+ }
+ UiThreadHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ setAutopilotBtnStatus(autopilotStatus);
+ }
+ },1000);
+ }
+
+ private void changeAutopilotBtnView(int autopilotStatus, boolean isAnimateRunning) {
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "onStateChangeChangeAutopilotBtnView: "
+ + autopilotStatus + "isAnimateRunning = " + isAnimateRunning);
+ if (isAnimateRunning && IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING
+ != autopilotStatus) {
+ // 主动开启自动驾驶中,不为2(为0、1)则继续loading
+ return;
+ }
+ if (isAnimateRunning){
+ stopAutopilotAnimation();
+ updateAutopilotStatus(autopilotStatus);
+ }else {
+ setAutopilotBtnStatus(autopilotStatus);
+ }
+
+ }
+
+ /**
+ * 隐藏【自动驾驶】按钮
+ */
+ public void hideAutopilotBiz() {
+ getActivity().runOnUiThread(() -> {
+// ctvAutopilotStatus.setVisibility(View.GONE);
+// slidePanelView.setVisibility(View.GONE);
+ });
+ }
+
+ /**
+ * 展示【自动驾驶】按钮
+ */
+ public void showAutopilotBiz() {
+ getActivity().runOnUiThread(() -> {
+ ctvAutopilotStatus.setVisibility(View.VISIBLE);
+ });
+ }
+
+ public void hidPanel() {
+ getActivity().runOnUiThread(() -> {
+ flStationPanelContainer.setVisibility(View.GONE);
+ });
+ }
+
+ public void showPanel() {
+ getActivity().runOnUiThread(() -> {
+ flStationPanelContainer.setVisibility(View.VISIBLE);
+ });
+ }
+
+ public View getPanelView() {
+ return panelView;
+ }
+
+ public SlidePanelView.OnSlidePanelMoveToEndListener getSlidePanelOnEndListener() {
+ return null;
+ }
+
+ /**
+ * 获取站点面板view,在{@link #initViews()}时候添加到container中
+ *
+ * @return 站点面板view
+ */
+ public abstract int getStationPanelViewId();
+
+ /**
+ * 获取清扫车操作面板layout id
+ * @return
+ */
+ public abstract int getSweepOperatePanelViewId();
+
+ /**
+ * 重新开启自动驾驶
+ */
+ public abstract void restartAutopilot();
+
+ /**
+ * 模拟自动驾驶返回状态
+ *
+ * @param status
+ */
+ public abstract void debugAutoPilotStatus(int status);
+
+ /**
+ * 开启自动驾驶中间动画
+ */
+ public void startAutopilotAnimation() {
+ isAnimateRunning = true;
+ ctvAutopilotStatusTv.setText(getResources().getString(R.string.sweeper_loading_autopilot_tv));
+ ctvAutopilotStatusTv.setTextColor(getResources().getColor(R.color.sweeper_autopilot_text_color_normal));
+ ctvAutopilotStatus.setSelected(false);
+ ctvAutopilotStatus.setFocusableInTouchMode(true);
+ ctvAutopilotStatusIv.setImageResource(R.drawable.sweeper_loading_autopilot_icon);
+ if (autopilotLoadingAnimator == null) {
+ autopilotLoadingAnimator = ObjectAnimator.ofFloat(ctvAutopilotStatusIv, "rotation", 0f, 360f);
+ autopilotLoadingAnimator.setInterpolator(new LinearInterpolator());
+ autopilotLoadingAnimator.setRepeatCount(-1);//无限循环
+ autopilotLoadingAnimator.setDuration(1000);//设置持续时间
+ }
+ autopilotLoadingAnimator.start();//动画开始
+
+ startingAutoApilotCountDown();
+
+ }
+
+ private void startingAutoApilotCountDown(){
+ //10s 若自动驾驶没有开启,则结束动画
+ UiThreadHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() { //未启动成功做处理
+ if (isAnimateRunning){// 只判断动画是否在进行,根据自动驾驶当前状态去设置自动驾驶状态
+ stopAutopilotAnimation();
+ updateAutopilotStatus(CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState());
+ }
+ }
+ },TIMER_START_AUTOPILOT_INTERVAL);
+
+ }
+ /**
+ * 停止自动驾驶中间动画
+ */
+ protected void stopAutopilotAnimation() {
+ if (autopilotLoadingAnimator != null) {
+ autopilotLoadingAnimator.end();
+ ctvAutopilotStatusIv.clearAnimation();
+ autopilotLoadingAnimator = null;
+ isAnimateRunning = false;
+ }
+ }
+
+ /**
+ * 迈速表实时更新
+ *
+ * @param newSpeed
+ */
+ public void updateSpeedView(float newSpeed) {
+ int speed = (int) (Math.abs(newSpeed) * 3.6F); // 倒车时工控机反馈定位信息中speed为负值
+ if (mTrafficDataView != null){
+ mTrafficDataView.updateSpeedWithValue(speed);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ MogoApisHandler.getInstance().getApis().getRegisterCenterApi().unregisterMogoMapListener(TYPE_ENTRANCE);
+ }
+
+ @Override
+ public void onMapVisualAngleChanged(VisualAngleMode visualAngleMode) {
+ if (visualAngleMode.isMediumSight()) {
+ mSwitchMapModeLayout.setVisibility(View.VISIBLE);
+ } else if (visualAngleMode.isLongSight()) {
+ mSwitchMapModeLayout.setVisibility(View.VISIBLE);
+ } else if (visualAngleMode.isCloseSight()) {
+ mSwitchMapModeLayout.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * bus调试面板打开关闭
+ */
+ public void debugTestBar() {
+ if (groupTestPanel.getVisibility() == View.VISIBLE) {
+ groupTestPanel.setVisibility(View.GONE);
+ } else {
+ groupTestPanel.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Bus调试信息:线路、轨迹等信息
+ *
+ * START
+ */
+ private View busTestBar;
+ private TextView lineIdTV;
+ private TextView trajMd5TV;
+ private TextView stopMd5TV;
+ private TextView trajMd5DPQPTV;
+ private TextView stopMd5DPQPTV;
+
+ public void showHideTestBar() {
+ if (busTestBar == null) {
+ busTestBar = findViewById(R.id.module_mogo_och_sweeper_test_bar);
+ lineIdTV = findViewById(R.id.sweeper_test_bar_current_line_id);
+ trajMd5TV = findViewById(R.id.sweeper_test_bar_current_traj_md5);
+ stopMd5TV = findViewById(R.id.sweeper_test_bar_current_stop_md5);
+ trajMd5DPQPTV = findViewById(R.id.sweeper_test_bar_current_traj_md5_dpqp);
+ stopMd5DPQPTV = findViewById(R.id.sweeper_test_bar_current_stop_md5_dpqp);
+ }
+
+ if (busTestBar.getVisibility() == View.VISIBLE) {
+ busTestBar.setVisibility(View.GONE);
+ } else {
+ SweeperRoutesResult routesResult = SweeperOrderModel.getInstance().getBusRoutesResult();
+ lineIdTV.setText("lineId:" + (routesResult == null ? "" : String.valueOf(routesResult.getLineId())));
+ trajMd5TV.setText("TMd5:" + (routesResult == null ? "" : routesResult.csvFileMd5));
+ stopMd5TV.setText("SMd5:" + (routesResult == null ? "" : routesResult.txtFileMd5));
+ trajMd5DPQPTV.setText("TMd5DPQP:" + (routesResult == null ? "" : routesResult.csvFileMd5DPQP));
+ stopMd5DPQPTV.setText("SMd5DPQP:" + (routesResult == null ? "" : routesResult.txtFileMd5DPQP));
+ busTestBar.setVisibility(View.VISIBLE);
+ }
+ }
+
+ public void updateSweeperTestBarInfo() {
+ if (busTestBar != null && busTestBar.getVisibility() == View.VISIBLE) {
+ SweeperRoutesResult routesResult = SweeperOrderModel.getInstance().getBusRoutesResult();
+ lineIdTV.setText("lineId:" + (routesResult == null ? "" : String.valueOf(routesResult.getLineId())));
+ trajMd5TV.setText("TMd5:" + (routesResult == null ? "" : routesResult.csvFileMd5));
+ stopMd5TV.setText("SMd5:" + (routesResult == null ? "" : routesResult.txtFileMd5));
+ trajMd5DPQPTV.setText("TMd5DPQP:" + (routesResult == null ? "" : routesResult.csvFileMd5DPQP));
+ stopMd5DPQPTV.setText("SMd5DPQP:" + (routesResult == null ? "" : routesResult.txtFileMd5DPQP));
+ }
+ }
+ /**
+ * END
+ */
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/fragment/SweeperFragment.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/fragment/SweeperFragment.java
new file mode 100644
index 0000000000..e47c57a817
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/fragment/SweeperFragment.java
@@ -0,0 +1,406 @@
+package com.mogo.och.sweeper.fragment;
+
+import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS;
+
+import android.content.Intent;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import com.mogo.commons.AbsMogoApplication;
+import com.mogo.commons.debug.DebugConfig;
+import com.mogo.commons.voice.AIAssist;
+import com.mogo.eagle.core.data.map.CenterLine;
+import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener;
+import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager;
+import com.mogo.eagle.core.function.call.map.CallerHDMapManager;
+import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
+import com.mogo.eagle.core.utilcode.util.ToastUtils;
+import com.mogo.map.MogoMarkerManager;
+import com.mogo.map.marker.IMogoMarker;
+import com.mogo.map.marker.MogoMarkerOptions;
+import com.mogo.och.sweeper.R;
+import com.mogo.och.sweeper.bean.SweeperStationBean;
+import com.mogo.och.sweeper.constant.SweeperConst;
+import com.mogo.och.sweeper.presenter.SweeperPresenter;
+import com.mogo.och.sweeper.ui.SweeperSwitchLineActivity;
+import com.mogo.och.sweeper.view.SlidePanelView;
+import com.mogo.och.common.module.utils.OCHThreadPoolManager;
+
+import java.util.List;
+
+
+/**
+ * 网约车小巴界面
+ *
+ * @author tongchenfei
+ */
+public class SweeperFragment extends BaseSweeperTabFragment
+ implements SlidePanelView.OnSlidePanelMoveToEndListener, View.OnClickListener {
+ private static final String TAG = "SweeperFragment";
+
+ private TextView mCurrentStationName;
+ private TextView mNextStationName;
+ private TextView mCurrentTag;
+ private TextView mNextTag;
+ private TextView mSwitchLine; //切换路线
+ private TextView mLineName;
+ private int mCurrentStation = 0;
+
+ private View mSweepers;
+
+ private SweeperStationBean startStation = null;
+ private SweeperStationBean endStation = null;
+
+ @Override
+ public String getTagName() {
+ return "SweepersFragment";
+ }
+
+ @Override
+ protected void initViews() {
+ super.initViews();
+ mSweepers = findViewById(R.id.module_och_sweeper_tag);
+ mCurrentStationName = findViewById(R.id.module_och_sweeper_current_station);
+ mCurrentTag = findViewById(R.id.module_och_sweeper_current_station_anchor);
+ mNextStationName = findViewById(R.id.module_och_sweeper_order_end_station);
+ mNextTag = findViewById(R.id.module_och_sweeper_next_station_anchor);
+ mSwitchLine = findViewById(R.id.switch_line_btn);
+ mLineName = findViewById(R.id.module_och_sweeper_line_name);
+
+ if (DebugConfig.isDebug()) {
+ mSweepers.setOnClickListener(view -> {
+ ToastUtils.showShort("重置了车站状态");
+ mPresenter.querySweepersRoutes();
+ });
+
+ //debug下调用测试面板
+ mCurrentStationName.setOnLongClickListener(v -> {
+ debugTestBar();
+ showHideTestBar();
+ return true;
+ });
+ }
+
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "initView: " + CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState());
+ // 初始化的时候设置 UI 按钮状态
+ switch (CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState()) {
+ case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE:
+ hideAutopilotBiz();
+ break;
+ case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE:
+ showAutopilotBiz();
+ onAutopilotStatusChanged(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE);
+ break;
+ case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING:
+ showAutopilotBiz();
+ onAutopilotStatusChanged(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING);
+ break;
+ default:
+ break;
+ }
+ mSwitchLine.setOnClickListener(this);
+ }
+
+ @Override
+ protected void debugArrivedStation() {
+ mPresenter.onAutopilotArriveAtStation(null);
+ }
+
+ @NonNull
+ @Override
+ protected SweeperPresenter createPresenter() {
+ return new SweeperPresenter(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ /**
+ * 根据站点列表信息刷新车站面板,滑块面板
+ *
+ * @param stationList 车站列表信息
+ * @param currentStation 当前站点
+ * @param nextStation 下个站点
+ * @param isArrived 是否都站
+ */
+ public void refreshSweeperStations(String lineName, List stationList
+ , int currentStation, int nextStation, boolean isArrived) {
+ mCurrentStation = currentStation;
+ if (getActivity() == null) {
+ return;
+ }
+ getActivity().runOnUiThread(() -> {
+ if (stationList == null) {
+ // 获取小巴数据失败
+ return;
+ }
+
+ // 渲染小巴路线数据
+ renderCurrentStationStatus(lineName,stationList, currentStation, nextStation, isArrived);
+ });
+ }
+
+ /**
+ * 重新刷新站点信息 isArrived 是否到站
+ */
+ private void renderCurrentStationStatus(String lineName, List stationList, int currentStation
+ , int nextStation, boolean isArrived) {
+ CallerLogger.INSTANCE.d(M_BUS + "MapMaker ", "currentStation=" + currentStation + ",nextStation=" + nextStation + "isArrived=" + isArrived);
+ String currentStationName = null;
+ String nextStationName = null;
+
+ boolean isArriveEndStation = false;
+ boolean isArriveAtStation = false;
+ boolean isArriveAtStartStation = false;
+
+ mLineName.setText(lineName);
+
+ // 获取当前站点的名称
+ currentStationName = stationList.get(currentStation).getName();
+
+ startStation = stationList.get(0);
+ endStation = stationList.get(stationList.size() - 1);
+
+ // 是否到达起点
+ if (currentStation == 0) {
+ isArriveAtStartStation = true;
+ mCurrentTag.setText(getResources().getString(R.string.sweeper_arrive_to_end_start));
+
+ setOrRemoveMapMaker(true, SweeperConst.SWEEPER_START_MAP_MAKER, startStation.getLat()
+ , startStation.getLon(),R.raw.star_marker);
+ setOrRemoveMapMaker(true, SweeperConst.SWEEPER_END_MAP_MAKER, endStation.getLat()
+ , endStation.getLon(),R.raw.end_marker);
+ } else if (currentStation > 0 && currentStation < stationList.size() - 1) {// 是否到达站点
+ isArriveAtStation = true;
+ mCurrentTag.setText(getResources().getString(R.string.sweeper_arrive_to_current_tag));
+ mNextTag.setText(getResources().getString(R.string.sweeper_arrive_to_next_tag));
+
+ setOrRemoveMapMaker(false, SweeperConst.SWEEPER_START_MAP_MAKER, startStation.getLat()
+ , startStation.getLon(),R.raw.star_marker);
+ setOrRemoveMapMaker(true, SweeperConst.SWEEPER_END_MAP_MAKER, endStation.getLat()
+ , endStation.getLon(),R.raw.end_marker);
+ } else if (currentStation == stationList.size() - 1) {// 是否到达终点
+ isArriveEndStation = true;
+ nextStationName = "--";
+ mNextTag.setText(getResources().getString(R.string.sweeper_arrive_to_end_end));
+
+ setOrRemoveMapMaker(false, SweeperConst.SWEEPER_START_MAP_MAKER, startStation.getLat()
+ , startStation.getLon(),R.raw.star_marker);
+
+ if (isArrived) {
+ setOrRemoveMapMaker(false, SweeperConst.SWEEPER_END_MAP_MAKER, endStation.getLat()
+ , endStation.getLon(),R.raw.end_marker);
+ } else {
+ setOrRemoveMapMaker(true, SweeperConst.SWEEPER_END_MAP_MAKER, endStation.getLat()
+ , endStation.getLon(),R.raw.end_marker);
+ }
+ }
+
+ // 获取下一站点名称
+ if (nextStation > currentStation && nextStation <= stationList.size() - 1) {
+ nextStationName = stationList.get(nextStation).getName();
+ }
+
+ // 是否到达终点
+ if ( nextStation == stationList.size() - 1 || nextStation == -1) {
+ mNextTag.setText(getResources().getString(R.string.sweeper_arrive_to_end_end));
+ }else {
+ mNextTag.setText(getResources().getString(R.string.sweeper_arrive_to_next_tag));
+ }
+
+ if (currentStation == 0 && isArrived){
+ showOrHideSwitchLineBtn(true);
+ }else {
+ showOrHideSwitchLineBtn(false);
+ }
+
+ // 重置滑动按钮文字
+ if (isArriveEndStation) {
+ showSlidePanle("单程结束");
+ } else if (isArriveAtStartStation) {
+ showSlidePanle("滑动出发");
+ } else if (isArriveAtStation) {
+ showSlidePanle("滑动出发");
+ }
+
+ mCurrentStationName.setText(currentStationName);
+ mNextStationName.setText(nextStationName);
+ updateSweeperTestBarInfo();
+ }
+
+ private void showOrHideSwitchLineBtn(boolean isShow) {
+ if (isShow){
+ mSwitchLine.setVisibility(View.VISIBLE);
+ }else {
+ mSwitchLine.setVisibility(View.GONE);
+ }
+ }
+
+ public void hideOchSweeper() {
+// tvNotice.setVisibility(View.GONE);
+ }
+
+ @Override
+ public int getStationPanelViewId() {
+ return R.layout.fragment_och_sweeper;
+ }
+
+ @Override
+ public int getSweepOperatePanelViewId() {
+ return R.layout.sweeper_operate_panel_view;
+ }
+
+ @Override
+ public void restartAutopilot() {
+ if (!isAnimateRunning) {
+ mPresenter.restartAutopilot();
+ }
+ }
+
+ @Override
+ public SlidePanelView.OnSlidePanelMoveToEndListener getSlidePanelOnEndListener() {
+ return this;
+ }
+
+ @Override
+ public void moveToEnd() {
+ // 开启自动驾驶到下一站
+ if (isAnimateRunning){
+ stopAutopilotAnimation();
+ }
+ mPresenter.autoDriveToNextStation(false);
+ }
+
+ /**
+ * 设置自动驾驶可用状态
+ */
+ public void onAutopilotEnableChange(boolean isEnable) {
+ if (isEnable) {
+ showAutopilotBiz();
+ } else {
+ hideAutopilotBiz();
+ }
+ }
+
+ @Override
+ protected void onChangeOperationStatus() {
+ super.onChangeOperationStatus();
+ mPresenter.onChangeOperationStatus();
+ }
+
+ /**
+ * 修改经营状态
+ *
+ * @param launch true-收车,false-出车
+ */
+ public void changeOperationStatus(boolean launch) {
+ isOperationStatus = launch;
+ if (launch) {
+ // 出车的时候重制站点状态
+ mPresenter.querySweepersRoutes();
+ tvOperationStatus.setText("收车");
+ showPanel();
+ } else {
+ AIAssist.getInstance(getContext()).speakTTSVoice("已收车");
+ tvOperationStatus.setText("出车");
+ hideSlidePanel();
+ hidPanel();
+
+ //移除起点终点
+ if (null != startStation) {
+ setOrRemoveMapMaker(false, SweeperConst.SWEEPER_START_MAP_MAKER, startStation.getLat()
+ , startStation.getLon(),R.raw.star_marker);
+ }
+ if (null != endStation) {
+ setOrRemoveMapMaker(false, SweeperConst.SWEEPER_END_MAP_MAKER, endStation.getLat()
+ , endStation.getLon(),R.raw.end_marker);
+ }
+ }
+ }
+
+ /**
+ * VR模式切换
+ *
+ * @param isVRMode
+ */
+ public void onVRModeChanged(boolean isVRMode) {
+ if (mRootView != null) {
+ mRootView.setVisibility(isVRMode ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ /**
+ * 绘制地图起点终点
+ *
+ * @param isAdd
+ * @param uuid
+ */
+ private void setOrRemoveMapMaker(boolean isAdd, String uuid, double lat, double longi,int resourceId) {
+ if (isAdd) {
+ Runnable setMapMarkerRunnable = new Runnable() {
+ @Override
+ public void run() {
+ CallerLogger.INSTANCE.d(M_BUS + "setMapMaker= "+Thread.currentThread().getName(),
+ uuid + "=latitude=" + lat + ",longitude=" + longi);
+
+ MogoMarkerOptions options = new MogoMarkerOptions()
+ .owner(SweeperConst.TYPE_MARKER_SWEEPER_ORDER)
+ .anchor(0.5f, 0.5f)
+ .set3DMode(true)
+ .gps(true)
+ .controlAngle(true)
+ .icon3DRes(resourceId)
+ .latitude(lat)
+ .longitude(longi);
+ IMogoMarker marker = MogoMarkerManager.getInstance(AbsMogoApplication.getApp()) .addMarker(uuid, options);
+ CenterLine centerLine = CallerHDMapManager.INSTANCE.getCenterLineInfo(
+ longi,lat,-1);
+ if (null != centerLine){ // 有可能鹰眼map为空没有角度。判空使用后可能造成maker角度跟道路角度不一致
+ marker.setRotateAngle(centerLine.getAngle().floatValue());
+ }
+ }
+ };
+
+ OCHThreadPoolManager.getsInstance().execute(setMapMarkerRunnable);
+
+ }else {
+ Runnable removeMapMarkerRunnable = new Runnable() {
+ @Override
+ public void run() {
+ CallerLogger.INSTANCE.d(M_BUS + "RemoveMapMaker="+Thread.currentThread().getName(),
+ uuid+"=latitude="+lat+",longitude="+longi);
+ MogoMarkerManager.getInstance(AbsMogoApplication.getApp()).removeMarkers(uuid);
+ }
+ };
+
+ OCHThreadPoolManager.getsInstance().execute(removeMapMarkerRunnable);
+ }
+ }
+
+ @Override
+ public void debugAutoPilotStatus(int status) {
+ mPresenter.debugAutoPilotStatus(status);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v.getId() == R.id.switch_line_btn) {//切换路线条件: 自动驾驶过程中,点击则toast提示:自动驾驶中,不可切换路线
+ //本次行程未结束,不支持切换路线。点击则toast提示:当前行程未完成,不可切换路线
+ if (CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState()
+ == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) {
+ ToastUtils.showLong(getResources().getString(R.string.sweeper_switch_line_btn_warning1));
+ return;
+ }
+ if (mCurrentStation > 0) {
+ ToastUtils.showLong(getResources().getString(R.string.sweeper_switch_line_btn_warning2));
+ return;
+ }
+ Intent intent = new Intent(getContext(), SweeperSwitchLineActivity.class);
+ startActivity(intent);
+ }
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/model/SweeperLineModel.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/model/SweeperLineModel.java
new file mode 100644
index 0000000000..e297e5053e
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/model/SweeperLineModel.java
@@ -0,0 +1,86 @@
+package com.mogo.och.sweeper.model;
+
+import android.content.Context;
+
+import com.mogo.commons.AbsMogoApplication;
+import com.mogo.eagle.core.utilcode.util.NetworkUtils;
+import com.mogo.eagle.core.utilcode.util.ToastUtils;
+import com.mogo.och.sweeper.bean.SweeperQueryLinesResponse;
+import com.mogo.och.sweeper.bean.SweeperRoutesResponse;
+import com.mogo.och.sweeper.callback.ISweeperLinesCallback;
+import com.mogo.och.sweeper.net.SweeperServiceManager;
+import com.mogo.och.sweeper.net.ISweeperServiceCallback;
+
+/**
+ * @author: wangmingjun
+ * @date: 2022/2/9
+ */
+public class SweeperLineModel {
+ private static volatile SweeperLineModel sInstance;
+ private Context mContext;
+ private ISweeperLinesCallback mBusLinesCallback;
+ public static SweeperLineModel getInstance() {
+ if ( sInstance == null ) {
+ synchronized ( SweeperLineModel.class ) {
+ if ( sInstance == null ) {
+ sInstance = new SweeperLineModel();
+ }
+ }
+ }
+ return sInstance;
+ }
+ private SweeperLineModel() {
+
+ }
+ public void init() {
+ mContext = AbsMogoApplication.getApp();
+ }
+ public void setBusLinesCallback(ISweeperLinesCallback callback){
+ mBusLinesCallback = callback;
+ }
+ public void queryBusLines(){
+ SweeperServiceManager.getInstance().queryBusLines(mContext, new ISweeperServiceCallback() {
+ @Override
+ public void onSuccess(SweeperQueryLinesResponse data) {
+ if (null == data && mBusLinesCallback != null) {
+ mBusLinesCallback.onBusLinesChange(null);
+ return;
+ }
+
+ if (mBusLinesCallback != null){
+ mBusLinesCallback.onBusLinesChange(data);
+ }
+ }
+
+ @Override
+ public void onFail(String failMsg) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ }else {
+ ToastUtils.showShort("查询所有绑定路线失败:"+failMsg);
+ }
+ }
+ });
+ }
+
+ public void commitSwitchLineId(int lineId){
+ SweeperServiceManager.getInstance().resetStationStatus(mContext,lineId, new ISweeperServiceCallback() {
+ @Override
+ public void onSuccess(SweeperRoutesResponse o) {
+ if (mBusLinesCallback != null){
+ mBusLinesCallback.onChangeLineIdSuccess();
+ }
+ }
+
+ @Override
+ public void onFail(String failMsg) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ }else {
+ ToastUtils.showShort("切换路线失败:"+failMsg);
+ }
+ }
+ });
+ }
+
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/model/SweeperOrderModel.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/model/SweeperOrderModel.java
new file mode 100644
index 0000000000..e5c1505746
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/model/SweeperOrderModel.java
@@ -0,0 +1,908 @@
+package com.mogo.och.sweeper.model;
+
+import static com.mogo.eagle.core.data.deva.chain.ChainConstant.CHAIN_ALIAS_CODE_OCH_BUS_START_AUTOPILOT;
+import static com.mogo.eagle.core.data.deva.chain.ChainConstant.CHAIN_LINK_ADAS;
+import static com.mogo.eagle.core.data.deva.chain.ChainConstant.CHAIN_LINK_LOG_WEB_SOCKET_AUTOPILOT;
+import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS;
+import static com.mogo.och.sweeper.constant.SweeperConst.STATION_STATUS_STOPPED;
+
+import android.content.Context;
+import android.location.Location;
+import android.os.Handler;
+import android.os.Message;
+
+import androidx.annotation.NonNull;
+
+import com.amap.api.maps.model.LatLng;
+import com.elegant.network.utils.GsonUtil;
+import com.mogo.cloud.commons.utils.CoordinateUtils;
+import com.mogo.commons.AbsMogoApplication;
+import com.mogo.commons.debug.DebugConfig;
+import com.mogo.commons.voice.AIAssist;
+import com.mogo.eagle.core.data.BaseData;
+import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters;
+import com.mogo.eagle.core.data.config.FunctionBuildConfig;
+import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotPlanningListener;
+import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotManager;
+import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager;
+import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotPlanningListenerManager;
+import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
+import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
+import com.mogo.eagle.core.utilcode.util.NetworkUtils;
+import com.mogo.eagle.core.utilcode.util.ToastUtils;
+import com.mogo.map.navi.IMogoCarLocationChangedListener2;
+import com.mogo.module.common.MogoApisHandler;
+import com.mogo.och.sweeper.bean.SweeperOperationStatusResponse;
+import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean;
+import com.mogo.och.sweeper.bean.SweeperRoutesResponse;
+import com.mogo.och.sweeper.bean.SweeperRoutesResult;
+import com.mogo.och.sweeper.bean.SweeperStationBean;
+import com.mogo.och.sweeper.bean.QueryLeaveAwayPassengersResponse;
+import com.mogo.och.sweeper.callback.ICarOperationStatusCallback;
+import com.mogo.och.sweeper.callback.ISweeperControllerStatusCallback;
+import com.mogo.och.sweeper.callback.IRefreshSweeperStationsCallback;
+import com.mogo.och.sweeper.callback.ISlidePannelHideCallback;
+import com.mogo.och.sweeper.constant.SweeperConst;
+import com.mogo.och.sweeper.net.SweeperServiceManager;
+import com.mogo.och.sweeper.net.ISweeperServiceCallback;
+import com.mogo.och.sweeper.presenter.SweeperModelLoopManager;
+import com.mogo.och.sweeper.util.SweeperAnalyticsManager;
+import com.mogo.och.sweeper.util.SweeperTrajectoryManager;
+import com.mogo.och.common.module.utils.CoordinateCalculateRouteUtil;
+import com.mogo.och.common.module.utils.PinYinUtil;
+import com.mogo.service.statusmanager.IMogoStatusChangedListener;
+import com.mogo.service.statusmanager.StatusDescriptor;
+import com.zhjt.service.chain.ChainLog;
+import com.zhjt.service.chain.TracingConstants;
+
+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 SweeperOrderModel {
+ private final String TAG = SweeperOrderModel.class.getSimpleName();
+ private int currentLineId = -1;
+ private int backgroundCurrentStationIndex = 0;//A->B 此处值是A站点索引
+ /**
+ * 运营状态、后端更具运营状态来判断车辆是否派单
+ */
+ private boolean mIsWorking = false;
+ private static volatile SweeperOrderModel sInstance;
+ public double mLongitude = 0;
+ public double mLatitude = 0;
+ private Context mContext;
+ private final List stationList = new ArrayList<>();
+ private SweeperRoutesResult sweeperRoutesResult = null;
+ /**
+ * 用来表示是否正在开往下一站
+ */
+ private boolean isGoingToNextStation = false;
+ // 运营类型
+ private static final int VEHICLE_TYPE = 10;
+ private static final int MSG_QUERY_BUS_STATION = 1001;
+ private static final long QUERY_BUS_STATION_DELAY = 5000;
+
+ private ICarOperationStatusCallback carOperationStatusCallback;
+ private IRefreshSweeperStationsCallback refreshBusStationsCallback;
+ private ISlidePannelHideCallback slidePannelHideCallback;
+ private ISweeperControllerStatusCallback mControllerStatusCallback; //Model->Presenter:VR mode等
+
+ List points = new ArrayList<>();//全路径信息
+
+ private boolean hadQueryLeaveAwayPassager = false;
+
+ private volatile boolean isArrivedStation = false;
+
+ private final Handler handler = new Handler(new Handler.Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ if ( msg.what == MSG_QUERY_BUS_STATION ) {
+ SweeperOrderModel.getInstance().querySweeperRoutes();
+ return true;
+ }
+ return false;
+ }
+ });
+
+ public static SweeperOrderModel getInstance() {
+ if ( sInstance == null ) {
+ synchronized ( SweeperOrderModel.class ) {
+ if ( sInstance == null ) {
+ sInstance = new SweeperOrderModel();
+ }
+ }
+ }
+ return sInstance;
+ }
+
+ private SweeperOrderModel() {
+
+ }
+
+ public void init() {
+ mContext = AbsMogoApplication.getApp();
+ // 2021/10/20 衡阳小巴业务,使用LenovoPad时需要此app自己获取坐标并上传
+ String productFlavor = DebugConfig.getProductFlavor();
+ if (productFlavor != null && productFlavor.contains("fPadLenovoOchBus")) {
+ MogoApisHandler.getInstance()
+ .getApis()
+ .getRegisterCenterApi()
+ .registerCarLocationChangedListener(TAG, mCarLocationChangedListener2);
+ MogoApisHandler.getInstance()
+ .getApis()
+ .getStatusManagerApi()
+ .registerStatusChangedListener( TAG, StatusDescriptor.VR_MODE, mMogoStatusChangedListener );
+
+ //自动驾驶路线规划接口
+ CallerAutopilotPlanningListenerManager.INSTANCE.addListener(TAG, moGoAutopilotPlanningListener);
+ }
+
+ //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_BUS + TAG,"UndeliverableException");
+ }
+ if ((e instanceof IOException)) {//
+ // fine, irrelevant network problem or API that throws on cancellation
+ CallerLogger.INSTANCE.d(M_BUS + TAG,"IOException");
+ return;
+ }
+ if (e instanceof InterruptedException) {
+ // fine, some blocking code was interrupted by a dispose call
+ CallerLogger.INSTANCE.d(M_BUS + TAG,"InterruptedException");
+ return;
+ }
+ if ((e instanceof NullPointerException) || (e instanceof IllegalArgumentException)) {
+ // that's likely a bug in the application
+ CallerLogger.INSTANCE.d(M_BUS + TAG,"NullPointerException or IllegalArgumentException");
+ Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
+ return;
+ }
+ if (e instanceof IllegalStateException) {
+ // that's a bug in RxJava or in a custom operator
+ CallerLogger.INSTANCE.d(M_BUS + TAG,"IllegalStateException");
+ Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
+ return;
+ }
+ CallerLogger.INSTANCE.d(M_BUS + TAG,"Undeliverable exception");
+ }
+ });
+
+ }
+
+ public void setCarOperationStatusCallback(ICarOperationStatusCallback callback){
+ this.carOperationStatusCallback = callback;
+ }
+
+ public void setRefreshBusStationsCallback(IRefreshSweeperStationsCallback callback){
+ this.refreshBusStationsCallback = callback;
+ }
+
+ public void setSlidePannelHideCallback(ISlidePannelHideCallback callback){
+ this.slidePannelHideCallback = callback;
+ }
+
+ public void setControllerStatusCallback(ISweeperControllerStatusCallback callback) {
+ this.mControllerStatusCallback = callback;
+ }
+
+ private final IMoGoAutopilotPlanningListener moGoAutopilotPlanningListener = new IMoGoAutopilotPlanningListener() {
+
+ @Override
+ public void onAutopilotTrajectory(@NonNull List trajectoryInfos) {
+
+ }
+
+ @Override
+ public void onAutopilotRotting(MessagePad.GlobalPathResp routeList) {
+ if (null != routeList && routeList.getWayPointsList().size() > 0){
+ points.clear();
+ points.addAll(coordinateConverterWgsToGcjList(mContext,routeList.getWayPointsList()));
+ updateOrderRoute();
+ }
+ }
+
+ };
+
+ 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 updateOrderRoute() {
+ if (!isGoingToNextStation || backgroundCurrentStationIndex+1 >= stationList.size() || points.size() == 0){
+ return;
+ }
+
+ SweeperStationBean currentStation = stationList.get( backgroundCurrentStationIndex);
+ SweeperStationBean nextStation = stationList.get( backgroundCurrentStationIndex +1);
+
+ SweeperServiceManager.getInstance().updateOrderRoute(mContext, currentLineId, currentStation.getSiteId()
+ , nextStation.getSiteId(), points, new ISweeperServiceCallback() {
+ @Override
+ public void onSuccess(BaseData o) {
+
+ }
+
+ @Override
+ public void onFail(String failMsg) {
+ if (isGoingToNextStation){//重试
+ updateOrderRoute();
+ }
+ }
+ });
+ }
+
+ public void debugUpdateOrderRoute(List list){
+ points.clear();
+ points.addAll(coordinateConverterWgsToGcjList(mContext,list));
+ updateOrderRoute();
+ }
+
+ public void release(){
+ startOrStopOrderLoop(false);
+ MogoApisHandler.getInstance()
+ .getApis()
+ .getStatusManagerApi()
+ .unregisterStatusChangedListener(TAG, StatusDescriptor.VR_MODE, mMogoStatusChangedListener);
+
+ // 注销到达起始站围栏监听
+ MogoApisHandler.getInstance()
+ .getApis()
+ .getRegisterCenterApi()
+ .unregisterCarLocationChangedListener(TAG, mCarLocationChangedListener2);
+
+ //自动驾驶路线规划接口
+ CallerAutopilotPlanningListenerManager.INSTANCE.removeListener(moGoAutopilotPlanningListener);
+ }
+
+ private Object readResolve() {
+ // 阻止反序列化,必须实现 Serializable 接口
+ return sInstance;
+ }
+
+ private 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 IMogoCarLocationChangedListener2 mCarLocationChangedListener2 = new IMogoCarLocationChangedListener2() {
+
+ @Override
+ public void onCarLocationChanged2( Location location ) {
+// CallerLogger.INSTANCE.d(M_BUS + TAG,"location = "+location.getLongitude()+","+location.getLatitude());
+ mLongitude = location.getLongitude();
+ mLatitude = location.getLatitude();
+ if (mControllerStatusCallback != null) {
+ mControllerStatusCallback.onCarLocationChanged(location);
+ }
+
+ //是否到站的围栏判断 离站状态并且自动驾驶还未触发到站
+ if (isGoingToNextStation && !isArrivedStation){
+ judgeStartStation(location);
+ }
+ }
+ };
+
+ //根据围栏判断,是否到达起点
+ private void judgeStartStation(Location location) {
+
+ if (backgroundCurrentStationIndex +1 > stationList.size() - 1 ){
+ return;
+ }
+ SweeperStationBean upcomingStation = stationList.get( backgroundCurrentStationIndex +1);
+
+ double startLon = upcomingStation.getGcjLon();
+ double startLat = upcomingStation.getGcjLat();
+ double distance = CoordinateUtils.calculateLineDistance(
+ startLon, startLat,
+ location.getLongitude(), location.getLatitude() );
+
+ Logger.i(TAG, "judgeStartStation() distance = " + distance);
+
+ if ( distance > SweeperConst.ARRIVE_AT_END_STATION_DISTANCE ) {
+ distance = CoordinateUtils.calculateLineDistance(startLon, startLat,
+ CallerAutoPilotStatusListenerManager.INSTANCE.getCurWgs84Lon(),
+ CallerAutoPilotStatusListenerManager.INSTANCE.getCurWgs84Lat());
+ }
+
+ if ( distance <= SweeperConst.ARRIVE_AT_END_STATION_DISTANCE ) {
+ onArriveAt(null); //无自动驾驶到站信息传null
+ return;
+ }
+ }
+
+ /**
+ * 查询小巴路线
+ */
+ public void querySweeperRoutes() {
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "查询小巴路线");
+ SweeperServiceManager.getInstance().queryBusRoutes(mContext, new ISweeperServiceCallback() {
+ @Override
+ public void onSuccess(SweeperRoutesResponse data) {
+ if ( data == null
+ || data.getResult() == null
+ || data.getResult().getSites() == null
+ || data.getResult().getSites().isEmpty() ) {
+ return;
+ }
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "获取到小巴路线数据: " + data );
+ renderBusStationsStatus( data.getResult());
+ }
+ @Override
+ public void onFail(String failMsg) {
+ // 重复请求小巴路线,直至成功
+ queryBusStationDelay();
+ }
+ });
+
+ }
+
+ /**
+ * 测试、重置站点状态
+ */
+ public void debugResetStationStatus() {
+ CallerLogger.INSTANCE.d( M_BUS + TAG, "测试、重置站点状态");
+ SweeperServiceManager.getInstance().resetStationStatus(mContext, currentLineId
+ , new ISweeperServiceCallback() {
+ @Override
+ public void onSuccess(SweeperRoutesResponse o) {
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "获取到小巴路线数据: " + o);
+ isGoingToNextStation = false;
+ if (o.getResult() == null || o.getResult().getSites() == null || o.getResult().getSites().isEmpty()) {
+ return;
+ }
+ renderBusStationsStatus(o.getResult());
+ }
+
+ @Override
+ public void onFail(String failMsg) {
+ // 重复请求小巴路线,直至成功
+ queryBusStationDelay();
+ }
+ });
+
+ }
+
+ /**
+ * 离站上报
+ */
+ public void leaveStation(boolean isOneWayOver,boolean isRestart){
+ CallerLogger.INSTANCE.d(M_BUS + TAG,"leaveStation-backgroundCurrentStationIndex = "+backgroundCurrentStationIndex);
+ SweeperServiceManager.getInstance().leaveStation(mContext, stationList.get(backgroundCurrentStationIndex).getSeq()
+ , stationList.get(backgroundCurrentStationIndex).getSiteId(), new ISweeperServiceCallback() {
+ @Override
+ public void onSuccess(SweeperRoutesResponse o) {
+ if ( o.getResult() == null || o.getResult().getSites() == null || o.getResult().getSites().isEmpty() ) {
+ return;
+ }
+ isArrivedStation = false;
+ if (!isOneWayOver){
+ CallerLogger.INSTANCE.d( M_BUS + TAG, "自动驾驶开启开往下一站====" );
+ //需要更改当前站和下一站的状态 然后渲染
+ leaveStationSuccess(o.getResult(),isRestart);
+ }else {
+ CallerLogger.INSTANCE.d( M_BUS + TAG, "单程真的结束了====" );
+ isGoingToNextStation = false;
+ backgroundCurrentStationIndex = 0;
+ CallerAutoPilotManager.INSTANCE.cancelAutoPilot();
+ querySweeperRoutes();
+ }
+ }
+ @Override
+ public void onFail(String failMsg) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ }else{
+ ToastUtils.showShort("离站上报失败:"+failMsg);
+ }
+ }
+ });
+ }
+
+ /**
+ * 离站上报成功后渲染站点
+ * 服务端返回的OchBusRoutesResult逻辑, 离开站为当前站, 到达下一站后才会将下一站置为当前站,
+ * 车机端展示是离开当前站,下一站设置为当前站, 所以服务端数据回来要做处理,不能直接渲染
+ */
+ @ChainLog(
+ linkChainLog = CHAIN_LINK_LOG_WEB_SOCKET_AUTOPILOT,
+ linkCode = CHAIN_LINK_ADAS,
+ endpoint = TracingConstants.Endpoint.PAD,
+ nodeAliasCode = CHAIN_ALIAS_CODE_OCH_BUS_START_AUTOPILOT,
+ paramIndexes = {0},
+ clientPkFileName = "sn"
+ )
+ private void leaveStationSuccess(SweeperRoutesResult result, boolean isRestart) {
+ renderBusStationsStatus(result);
+ if (slidePannelHideCallback != null) {
+ slidePannelHideCallback.hideSlidePanel();
+ }
+ //开启自动驾驶
+ startAutopilot(isRestart);
+ if (isGoingToNextStation) {
+ // 为了避免恢复自动驾驶时重复的接口请求
+ return;
+ }
+ isGoingToNextStation = true;
+ AIAssist.getInstance( mContext ).speakTTSVoice( "欢迎乘坐’蘑菇车联‘无人驾驶小巴车,请您坐好,注意乘车安全,行程即将开始" );
+ }
+
+ /**
+ * 开启自动驾驶
+ * @param isRestart
+ */
+ private void startAutopilot(boolean isRestart) {
+
+ triggerStartServiceEvent(isRestart, false);
+
+ isArrivedStation = false;
+// SweeperStationBean currentStation = stationList.get( backgroundCurrentStationIndex);
+// SweeperStationBean nextStation = stationList.get( backgroundCurrentStationIndex + 1);
+
+// if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE
+// == CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState()) {
+// ToastUtils.showShort("自动驾驶状态为不可用!");
+// }
+ AutopilotControlParameters parameters = new AutopilotControlParameters();
+// parameters.isSpeakVoice = !isRestart;
+// parameters.routeID = sweeperRoutesResult.getLineId();
+// parameters.routeName = sweeperRoutesResult.getName();
+// parameters.startName = PinYinUtil.getPinYinHeadChar(currentStation.getName());
+// parameters.endName = PinYinUtil.getPinYinHeadChar(nextStation.getName());
+// parameters.startLatLon = new AutopilotControlParameters
+// .AutoPilotLonLat( currentStation.getLat(), currentStation.getLon() );
+// parameters.endLatLon = new AutopilotControlParameters
+// .AutoPilotLonLat( nextStation.getLat(), nextStation.getLon() );
+// parameters.vehicleType = VEHICLE_TYPE;
+// if (parameters.autoPilotLine == null) {
+// parameters.autoPilotLine = new AutopilotControlParameters.AutoPilotLine(
+// sweeperRoutesResult.getLineId(),
+// sweeperRoutesResult.csvFileUrl, sweeperRoutesResult.csvFileMd5,
+// sweeperRoutesResult.txtFileUrl, sweeperRoutesResult.txtFileMd5,
+// sweeperRoutesResult.contrailSaveTime, sweeperRoutesResult.carModel,
+// sweeperRoutesResult.csvFileUrlDPQP, sweeperRoutesResult.csvFileMd5DPQP,
+// sweeperRoutesResult.txtFileUrlDPQP, sweeperRoutesResult.txtFileMd5DPQP,
+// sweeperRoutesResult.contrailSaveTimeDPQP);
+// }
+// CallerLogger.INSTANCE.d( M_BUS + TAG, "开启自动驾驶====" + GsonUtil.jsonFromObject(parameters)
+// +" startLatLon="+currentStation.getName()+",endLatLon="+nextStation.getName());
+ CallerLogger.INSTANCE.d( M_BUS + TAG, "开启自动驾驶====" + GsonUtil.jsonFromObject(parameters));
+ CallerAutoPilotManager.INSTANCE.startAutoPilot(parameters);
+
+ if (mControllerStatusCallback != null) {
+ mControllerStatusCallback.startOpenAutopilot();
+ }
+ }
+
+ /**
+ * 到站后重置站点状态
+ */
+ private void arriveSiteStation(boolean isRestart) {
+ if ( backgroundCurrentStationIndex +1 > stationList.size() - 1 ) { //到站短时间内调用多次
+ CallerLogger.INSTANCE.e( M_BUS + TAG, "数组越界" );
+ return;
+ }
+ int arrivedStationIndex = 0;
+ if (!isRestart){
+ arrivedStationIndex = backgroundCurrentStationIndex + 1;
+ }
+ CallerLogger.INSTANCE.d(M_BUS + TAG,"arriveSiteStation-currentStationIndex = "+ arrivedStationIndex);
+
+ SweeperServiceManager.getInstance().arriveSiteStation(mContext
+ , stationList.get(arrivedStationIndex).getSeq(), stationList.get(arrivedStationIndex).getSiteId()
+ , new ISweeperServiceCallback() {
+ @Override
+ public void onSuccess(BaseData o) {
+ CallerLogger.INSTANCE.d(M_BUS + TAG,"arriveSiteStation success");
+ if (!isRestart){
+ renderArriveBusStation();
+ }
+ }
+
+ @Override
+ public void onFail(String failMsg) {
+// if (!NetworkUtils.isConnected(mContext)) {
+// ToastUtils.showShort("网络异常,请稍后重试");
+// }else {
+// ToastUtils.showShort("离站上报失败:"+failMsg);
+// }
+
+ }
+ });
+ }
+
+ private void renderArriveBusStation() {
+ List site = sweeperRoutesResult.getSites();
+ if (site != null && site.size() > 0){
+ backgroundCurrentStationIndex ++;
+ if (refreshBusStationsCallback != null){
+ refreshBusStationsCallback.refreshBusStations(sweeperRoutesResult.getName(),stationList, backgroundCurrentStationIndex
+ , getNextStopStation(),true);
+ }
+ }
+ }
+
+ /**
+ * 收车
+ */
+ public void stopTakeOrder(){
+ SweeperServiceManager.getInstance().stopTakeOrder(mContext, new ISweeperServiceCallback() {
+ @Override
+ public void onSuccess(BaseData o) {
+ mIsWorking = !mIsWorking;
+ closeBeautificationMode();
+ carOperationStatusCallback.changeOperationStatus(isWorking());
+ startOrStopOrderLoop(mIsWorking);
+ SweeperTrajectoryManager.getInstance().stopTrajReqLoop();
+ }
+ @Override
+ public void onFail(String failMsg) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ }else {
+ ToastUtils.showShort("收车失败:"+failMsg);
+ }
+ }
+ });
+ }
+
+ /**
+ * 关闭美化模式
+ */
+ private void closeBeautificationMode() {
+ if (FunctionBuildConfig.isDemoMode) {//收车结束美化
+ FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData = false;
+ CallerAutoPilotManager.INSTANCE.setIPCDemoMode(false);
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "美化模式-ignore:置为false(收车)");
+ }
+ }
+
+ /**
+ * 出车
+ */
+ public void startTakeOrder(){
+ SweeperServiceManager.getInstance().startTakeOrder(mContext, new ISweeperServiceCallback() {
+ @Override
+ public void onSuccess(BaseData o) {
+ mIsWorking = !mIsWorking;
+ startOrStopOrderLoop(mIsWorking);
+ if ( stationList != null && stationList.size() > 0 ) {
+ AIAssist.getInstance( mContext ).speakTTSVoice( "车辆已整备完毕,请前往"
+ + stationList.get( backgroundCurrentStationIndex ).getName() + "站点" );
+ }
+ carOperationStatusCallback.changeOperationStatus(isWorking());
+ querySweeperRoutes();
+ }
+ @Override
+ public void onFail(String failMsg) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ }else {
+ ToastUtils.showShort("出车失败:"+failMsg);
+ }
+ }
+ });
+ }
+
+ /**
+ * 查询运营状态
+ */
+ public void queryOperationStatus() {
+ CallerLogger.INSTANCE.d( M_BUS + TAG, "查询运营状态");
+ SweeperServiceManager.getInstance().queryOperationStatus(mContext
+ , new ISweeperServiceCallback() {
+ @Override
+ public void onSuccess(SweeperOperationStatusResponse o) {
+ if ( o.data != null ) {
+ mIsWorking = o.data.serviceStatus == 1;
+ CallerLogger.INSTANCE.d( M_BUS + TAG, "查询运营状态 result.status: " + o.data.serviceStatus);
+ startOrStopOrderLoop(mIsWorking);
+ }
+ carOperationStatusCallback.changeOperationStatus(isWorking());
+ }
+ @Override
+ public void onFail(String failMsg) {
+ if (!NetworkUtils.isConnected(mContext)) {
+ ToastUtils.showShort("网络异常,请稍后重试");
+ }else {
+ ToastUtils.showShort("出车收车状态查询:"+failMsg);
+ }
+// queryOperationStatus();
+ }
+ });
+ }
+
+ /**
+ * 开启自动驾驶到下一站
+ */
+ public void autoDriveToNextStation( boolean isRestart ) {
+// if ( backgroundCurrentStationIndex >= stationList.size() - 1 ) {
+// // 当前站是最后一站,结束当前行程
+// travelOver();
+// return;
+// }
+// leaveStation(false,isRestart);
+ startAutopilot(isRestart);
+ }
+
+ /**
+ * 渲染站点信息
+ * 服务端返回的OchBusRoutesResult逻辑, 离开站为当前站, 到达下一站后才会将下一站置为当前站,
+ * 车机端展示 离开站为当前站点,前往站为下一站, 下一站到站后在置为当前站
+ * @param result
+ */
+ private void renderBusStationsStatus(SweeperRoutesResult result) {
+ if (result == null) return;
+ sweeperRoutesResult = result;
+ List site = result.getSites();
+ currentLineId = result.getLineId();
+ stationList.clear();
+ stationList.addAll( site );
+ for ( int i = 0; i < stationList.size(); i++ ) {
+ SweeperStationBean s = stationList.get( i );
+
+ CallerLogger.INSTANCE.d( M_BUS + "renderBusStationsStatus--",
+ "Index="+ i+" ,name = "+s.getName()+" ,"+s.isLeaving()+","+s.getDrivingStatus());
+
+ // 是否正在开往下一站
+ if ( s.isLeaving()) {
+ isGoingToNextStation = true;
+ }
+ // 当前站点信息
+ if (s.getDrivingStatus() == STATION_STATUS_STOPPED ) {
+ backgroundCurrentStationIndex = i;
+ break;
+ }
+ }
+
+ SweeperStationBean currentStation = stationList.get(backgroundCurrentStationIndex);
+
+ CallerLogger.INSTANCE.d( M_BUS + TAG,
+ "渲染站点信息服务端currentStationIndex="+backgroundCurrentStationIndex
+ +" isLeaving()="+currentStation.isLeaving());
+
+ //当前站点是始发站,告诉服务端到达始发站。 如果没有这个节点, 服务器不知道始发站到达状态
+ // ,订单开始站下在始发站的状态流转有问题
+ if (backgroundCurrentStationIndex == 0 && !currentStation.isLeaving()){
+ arriveSiteStation(true);
+ }
+
+ // 美化是否开始
+ if (FunctionBuildConfig.isDemoMode && (backgroundCurrentStationIndex >= 0
+ && backgroundCurrentStationIndex <= stationList.size()-1)
+ && stationList.get(backgroundCurrentStationIndex).isLeaving()){//行驶过程中设置美化
+ FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData = true;
+ CallerAutoPilotManager.INSTANCE.setIPCDemoMode(true);
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "美化模式-ignore:置为true(每次滑动出发)");
+ }
+
+ if (refreshBusStationsCallback != null){
+ refreshBusStationsCallback.refreshBusStations(result.getName(),stationList
+ , backgroundCurrentStationIndex, getNextStopStation(),!currentStation.isLeaving());
+ }
+
+ if ( currentStation.isLeaving() && slidePannelHideCallback != null) {
+ slidePannelHideCallback.hideSlidePanel();
+ }
+
+ //需放在currentStationIndex赋值之后
+ SweeperTrajectoryManager.getInstance().syncTrajectoryInfo();
+ }
+
+ /**
+ * 根据订单状态、获取下一站靠站的的站点
+ *
+ * @return -1 当前已是最后一个站点
+ */
+ private int getNextStopStation() {
+ if ( backgroundCurrentStationIndex >= stationList.size() - 1 ) {
+ return -1;
+ }
+ int nextStationIndex = backgroundCurrentStationIndex + 1;
+ for ( ; nextStationIndex < stationList.size() - 1; nextStationIndex++ ) {
+ if ( stationList.get( nextStationIndex ).getIfStop() == 1 ) {
+ break;
+ }
+ break;
+ }
+ return nextStationIndex;
+ }
+
+ /**
+ * 延时查询站点信心
+ */
+ private void queryBusStationDelay() {
+ handler.sendEmptyMessageDelayed( MSG_QUERY_BUS_STATION, QUERY_BUS_STATION_DELAY );
+ }
+
+ /**
+ * 在踩刹车、控制方向盘等操作后,会停止自动驾驶,重启自动驾驶的话相当于重新设置自动驾驶目的地
+ */
+ public void restartAutopilot() {
+// CallerLogger.INSTANCE.d( M_BUS + TAG, "重启自动驾驶===" + isGoingToNextStation );
+// autoDriveToNextStation( true );
+ //直接开启自动驾驶
+ startAutopilot(true);
+ }
+
+ /**
+ * 播报下车乘客信息
+ *
+ * @param awayPassengersResponse
+ */
+ private void playLeavePassengersMsg( QueryLeaveAwayPassengersResponse awayPassengersResponse ) {
+ CallerLogger.INSTANCE.d( M_BUS + TAG, "播报下车乘客信息currentStationIndex="
+ + String.valueOf(backgroundCurrentStationIndex + 1));
+
+ if ( backgroundCurrentStationIndex +1 > stationList.size() - 1 ) {
+ return;
+ }
+ String station = stationList.get( backgroundCurrentStationIndex+1 ).getName();
+ StringBuilder builder = new StringBuilder( "已到达" );
+ builder.append( station );
+ if ( !station.endsWith( "站" ) ) {
+ builder.append( "站" );
+ }
+ if ( awayPassengersResponse == null || awayPassengersResponse.data == null
+ || awayPassengersResponse.data.orders == null || awayPassengersResponse.data.orders.isEmpty() ) {
+ CallerLogger.INSTANCE.d( M_BUS + TAG, "播报下车乘客信息为null");
+ } else {
+ builder.append( ",请尾号为 " );
+ for ( QueryLeaveAwayPassengersResponse.LeaveAwayPassenger leaveAwayPassenger : awayPassengersResponse.data.orders ) {
+ if ( leaveAwayPassenger == null ) {
+ continue;
+ }
+ String tailNum = null;
+ try {
+ tailNum = leaveAwayPassenger.passengerPhone.substring(leaveAwayPassenger.passengerPhone.length() - 4);
+ } catch (Exception e) {
+ e.printStackTrace();
+ tailNum = leaveAwayPassenger.passengerPhone;
+ }
+ builder.append( tailNum ).append( "。" );
+ }
+ builder.append( "的乘客下车" );
+ }
+ builder.append(",带好随身物品,下车请注意安全");
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "TTS:" + builder.toString());
+ AIAssist.getInstance( mContext ).speakTTSVoice( builder.toString() );
+ }
+
+ /**
+ * 修改小巴运营状态
+ */
+ public void onChangeOperationStatus() {
+ CallerLogger.INSTANCE.d( M_BUS + TAG, "修改小巴运营状态");
+ if (isWorking()){//收车
+ stopTakeOrder();
+ }else {//出车
+ startTakeOrder();
+ }
+ }
+
+ /**
+ * 行程结束
+ */
+ private void travelOver() {
+
+ if ( backgroundCurrentStationIndex >= stationList.size() ) {
+ CallerLogger.INSTANCE.e( M_BUS + TAG, "travel over index out of station list" );
+ return;
+ }
+ CallerLogger.INSTANCE.d( M_BUS + TAG, "单程结束====" );
+ CallerAutoPilotManager.INSTANCE.cancelAutoPilot();
+ AIAssist.getInstance( mContext ).speakTTSVoice( "感谢您体验'蘑菇车联'无人驾驶小巴车,请您携带好随身物品,我们下次再见" );
+ leaveStation(true,true);
+ }
+
+ public boolean isWorking() {
+ return mIsWorking;
+ }
+
+ /**
+ * 到站
+ * @param data
+ */
+ public void onArriveAt( MessagePad.ArrivalNotification data){
+// if ( backgroundCurrentStationIndex +1 > stationList.size() - 1 ) {
+// CallerLogger.INSTANCE.e( M_BUS + TAG, "到站异常,取消后续操作结束" );
+// return;
+// }
+
+ if (isArrivedStation) return;
+ isArrivedStation = true;
+
+ if (FunctionBuildConfig.isDemoMode && backgroundCurrentStationIndex <= stationList.size() - 1) {//到达一站结束美化
+ FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData = false;
+ CallerAutoPilotManager.INSTANCE.setIPCDemoMode(false);
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "美化模式-ignore:置为false(到最后一站)");
+ }
+ CallerLogger.INSTANCE.d( M_BUS + TAG, "到站====currentStationIndex=" + backgroundCurrentStationIndex);
+ isGoingToNextStation = false;
+
+// arriveSiteStation(false);//到站上报
+ }
+
+ public boolean isGoingToNextStation() {
+ return isGoingToNextStation;
+ }
+
+ // 车机端上传心跳数据(只在出车状态时上传)
+ public void runCarHeartbeat() {
+ SweeperServiceManager.getInstance().runCarHeartbeat(mContext, mLongitude, mLatitude,
+ new ISweeperServiceCallback() {
+ @Override
+ public void onSuccess(BaseData data) {
+
+ }
+
+ @Override
+ public void onFail(String failMsg) {
+
+ }
+ });
+ }
+
+ private void startOrStopOrderLoop(boolean start) {
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "startOrStopOrderLoop() " + start);
+ if (start) {
+ SweeperModelLoopManager.getInstance().startHeartbeatLoop();
+ } else {
+ SweeperModelLoopManager.getInstance().stopHeartbeatLoop();
+ }
+ }
+
+ public void triggerStartServiceEvent(boolean isRestart, boolean send) {
+ if (stationList == null || backgroundCurrentStationIndex >= stationList.size()-1) {
+ return;
+ }
+ SweeperStationBean currentStation = stationList.get( backgroundCurrentStationIndex);
+ SweeperStationBean nextStation = stationList.get( backgroundCurrentStationIndex +1);
+ SweeperAnalyticsManager.getInstance().triggerStartAutopilotEvent(isRestart, send,
+ currentStation.getName(), nextStation.getName(), currentLineId);
+ }
+
+ public SweeperRoutesResult getBusRoutesResult() {
+ return sweeperRoutesResult;
+ }
+
+ public int getCurrentStationIndex() {
+ return backgroundCurrentStationIndex;
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/net/ISweeperApiService.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/net/ISweeperApiService.java
new file mode 100644
index 0000000000..db8c6b3264
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/net/ISweeperApiService.java
@@ -0,0 +1,117 @@
+package com.mogo.och.sweeper.net;
+import com.mogo.eagle.core.data.BaseData;
+import com.mogo.och.sweeper.bean.SweeperOperationStatusRequest;
+import com.mogo.och.sweeper.bean.SweeperQueryLinesResponse;
+import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean;
+import com.mogo.och.sweeper.bean.SweeperRoutesResponse;
+import com.mogo.och.sweeper.bean.CarHeartbeatReqBean;
+import com.mogo.och.sweeper.bean.SweeperQueryLineStationsRequest;
+import com.mogo.och.sweeper.bean.SweeperOperationStatusResponse;
+import com.mogo.och.sweeper.bean.SweeperResetDrivingLineRequest;
+import com.mogo.och.sweeper.bean.SweeperUpdateSiteStatusRequest;
+
+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;
+
+/**
+ * 小巴车相关接口
+ *
+ * @author tongchenfei
+ *
+ * wiki: http://wiki.zhidaohulian.com/pages/viewpage.action?pageId=48970072
+ */
+public interface ISweeperApiService {
+ /**
+ * 根据车机坐标获取所在区域全部站点信息
+ *
+ * @param request 请求参数
+ * @return 接口返回数据
+ */
+ @Headers( {"Content-Type:application/json;charset=UTF-8"} )
+ @POST( "/autopilot-car-hailing/line/v2/driver/bus/lineDataWithDriver/query" )
+ Observable querySiteByCoordinate(@Header ("appId") String appId, @Header("ticket") String ticket, @Body SweeperQueryLineStationsRequest request);
+
+ /**
+ * 重置巴士路线: 点击小巴车tab 或者出车后会使用
+ *
+ * @param request 请求参数{"destLine":1,"sn":"F803EB2046PZD00229"} 这个接口是重置bus线路的, 不是重置线路中站点的
+ * @return 返回值是重置后的车站列表
+ */
+ @Headers( {"Content-Type:application/json;charset=UTF-8"} )
+ @POST( "/autopilot-car-hailing/car/v2/driver/bus/drivingLine/reset" )
+ Observable resetStationStatus(@Header ("appId") String appId, @Header("ticket") String ticket, @Body SweeperResetDrivingLineRequest request);
+
+ /**
+ * 离站,通知服务器
+ * @param request
+ * @return
+ */
+ @Headers({"Content-Type:application/json;charset=UTF-8"})
+ @POST("/autopilot-car-hailing/car/v2/driver/bus/driving/away")
+ Observable leaveStation(@Header ("appId") String appId, @Header("ticket") String ticket, @Body SweeperUpdateSiteStatusRequest request);
+
+ /**
+ * 到站 更新到站信息
+ * @param request
+ * @return
+ */
+ @Headers({"Content-type:application/json;charset=UTF-8"})
+ @POST("/autopilot-car-hailing/order/v2/driver/bus/driving/attachSite")
+ Observable< BaseData > arriveSiteStation(@Header ("appId") String appId,@Header("ticket") String ticket,@Body SweeperUpdateSiteStatusRequest request);
+
+ /**
+ * 出车
+ * @param request
+ * @return
+ */
+ @Headers( {"Content-type:application/json;charset=UTF-8"} )
+ @POST("/autopilot-car-hailing/car/v2/driver/bus/startTakeOrder")
+ Observable startTakeOrder(@Header ("appId") String appId,@Header("ticket") String ticket,@Body SweeperOperationStatusRequest request);
+
+ /**
+ * 收车
+ * @param request
+ * @return
+ */
+ @Headers({"Content-type:application/json;charset=UTF-8"})
+ @POST("/autopilot-car-hailing/car/v2/driver/bus/stopTakeOrder")
+ Observable stopTakeOrder(@Header ("appId") String appId,@Header("ticket") String ticket,@Body SweeperOperationStatusRequest request);
+
+ /**
+ * 查询小巴出车/收车状态
+ * @param sn
+ * @return
+ */
+ @Headers({"Content-type:application/json;charset=UTF-8"})
+ @GET("/autopilot-car-hailing/car/v2/driver/bus/takeOrderStatus/query")
+ Observable queryOperationStatus(@Header ("appId") String appId, @Header("ticket") String ticket, @Query("sn") String sn);
+
+ /**
+ * 车机端上传心跳数据(只在出车状态时上传):包含高德坐标系经纬度
+ * @param data
+ * @return
+ */
+ @Headers( {"Content-type:application/json;charset=UTF-8"} )
+ @POST( "/autopilot-car-hailing/location/v2/driver/bus/heartbeat" )
+ Observable runCarHeartbeat(@Header ("appId") String appId,@Header("ticket") String ticket,@Body CarHeartbeatReqBean data);
+
+ /**
+ * 查询车辆配置的所有路线
+ * @param appId
+ * @param ticket
+ * @param sn
+ * @return
+ */
+ @GET("/autopilot-car-hailing/line/v2/driver/bus/bindLine/query")
+ Observable queryBusLines(@Header ("appId") String appId, @Header("ticket") String ticket, @Query("sn") String sn);
+
+ @Headers( {"Content-type:application/json;charset=UTF-8"} )
+ @POST( "/autopilot-car-hailing/location/v2/driver/bus/saveLineCoordinate" )
+ Observable updateOrderRoute(@Header ("appId") String appId, @Header("ticket") String ticket, @Body SweeperRoutePlanningUpdateReqBean data);
+}
+
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/net/ISweeperServiceCallback.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/net/ISweeperServiceCallback.java
new file mode 100644
index 0000000000..0a57b49d1e
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/net/ISweeperServiceCallback.java
@@ -0,0 +1,15 @@
+package com.mogo.och.sweeper.net;
+
+/**
+ * @author: wangmingjun
+ * @date: 2021/10/20
+ */
+public interface ISweeperServiceCallback< T >{
+ void onSuccess(T o);
+
+ void onFail(String failMsg);
+
+ default void onError() {
+
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/net/SweeperServiceManager.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/net/SweeperServiceManager.java
new file mode 100644
index 0000000000..f6cd975dbd
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/net/SweeperServiceManager.java
@@ -0,0 +1,225 @@
+package com.mogo.och.sweeper.net;
+import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS;
+
+import android.content.Context;
+
+import com.mogo.cloud.passport.MoGoAiCloudClientConfig;
+import com.mogo.eagle.core.data.BaseData;
+import com.mogo.eagle.core.network.MoGoRetrofitFactory;
+import com.mogo.eagle.core.network.RequestOptions;
+import com.mogo.eagle.core.network.SubscribeImpl;
+import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
+import com.mogo.och.sweeper.bean.SweeperQueryLinesResponse;
+import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean;
+import com.mogo.och.sweeper.bean.SweeperRoutesResponse;
+import com.mogo.och.sweeper.bean.CarHeartbeatReqBean;
+import com.mogo.och.sweeper.bean.SweeperOperationStatusRequest;
+import com.mogo.och.sweeper.bean.SweeperOperationStatusResponse;
+import com.mogo.och.sweeper.bean.SweeperQueryLineStationsRequest;
+import com.mogo.och.sweeper.bean.SweeperResetDrivingLineRequest;
+import com.mogo.och.sweeper.bean.SweeperUpdateSiteStatusRequest;
+import com.mogo.och.sweeper.constant.SweeperConst;
+import com.mogo.och.sweeper.model.SweeperOrderModel;
+
+import java.util.List;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * @author: wangmingjun
+ * @date: 2021/10/20
+ */
+public class SweeperServiceManager {
+
+ private static final String TAG = SweeperServiceManager.class.getSimpleName();
+
+ private final ISweeperApiService mService;
+
+ private static final class SingletonHolder {
+ private static final SweeperServiceManager INSTANCE = new SweeperServiceManager();
+ }
+
+ public static SweeperServiceManager getInstance(){
+ return SingletonHolder.INSTANCE;
+ }
+
+ private SweeperServiceManager(){
+ mService = MoGoRetrofitFactory.getInstance(SweeperConst.getBaseUrl()).create(ISweeperApiService.class);
+ }
+
+ /**
+ * 查询小巴车线路
+ * @param context
+ * @param callback
+ */
+ public void queryBusRoutes(Context context, ISweeperServiceCallback callback) {
+ //获取当前高德坐标
+
+ mService.querySiteByCoordinate(MoGoAiCloudClientConfig.getInstance().getServiceAppId()
+ ,MoGoAiCloudClientConfig.getInstance().getToken()
+ , new SweeperQueryLineStationsRequest(SweeperOrderModel.getInstance().mLongitude
+ , SweeperOrderModel.getInstance().mLatitude,true))
+ .subscribeOn( Schedulers.io() ).observeOn( AndroidSchedulers.mainThread() )
+ .subscribe( getSubscribeImpl(context,callback,"querySiteByCoordinate"));
+ }
+
+ /**
+ * 重置线路站点
+ * @param context
+ * @param lineId
+ * @param callback
+ */
+ public void resetStationStatus(Context context, int lineId, ISweeperServiceCallback callback){
+ mService.resetStationStatus(MoGoAiCloudClientConfig.getInstance().getServiceAppId()
+ ,MoGoAiCloudClientConfig.getInstance().getToken(),new SweeperResetDrivingLineRequest(lineId))
+ .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
+ .subscribe(getSubscribeImpl(context,callback,"debugResetStationStatus"));
+ }
+
+ /**
+ * 离站上报
+ * @param context
+ * @param seq
+ * @param siteId
+ * @param callback
+ */
+ public void leaveStation(Context context, int seq, int siteId, ISweeperServiceCallback callback){
+ mService.leaveStation(MoGoAiCloudClientConfig.getInstance().getServiceAppId()
+ ,MoGoAiCloudClientConfig.getInstance().getToken()
+ ,new SweeperUpdateSiteStatusRequest(seq,siteId, SweeperOrderModel.getInstance().mLongitude
+ , SweeperOrderModel.getInstance().mLatitude))
+ .subscribeOn( Schedulers.io() )
+ .observeOn( AndroidSchedulers.mainThread() )
+ .subscribe(getSubscribeImpl(context,callback,"leaveStation"));
+ }
+
+ /**
+ * 到站更新站点状态
+ * @param context
+ * @param seq
+ * @param siteId
+ * @param callback
+ */
+ public void arriveSiteStation(Context context, int seq, int siteId, ISweeperServiceCallback callback){
+ mService.arriveSiteStation(MoGoAiCloudClientConfig.getInstance().getServiceAppId()
+ ,MoGoAiCloudClientConfig.getInstance().getToken()
+ ,new SweeperUpdateSiteStatusRequest(seq,siteId
+ , SweeperOrderModel.getInstance().mLongitude, SweeperOrderModel.getInstance().mLatitude))
+ .subscribeOn( Schedulers.io() )
+ .observeOn( AndroidSchedulers.mainThread() )
+ .subscribe(getSubscribeImpl(context,callback,"leaveStation"));
+ }
+
+ /**
+ * 收车
+ * @param context
+ * @param callback
+ */
+ public void stopTakeOrder(Context context, ISweeperServiceCallback callback){
+ mService.stopTakeOrder(MoGoAiCloudClientConfig.getInstance().getServiceAppId()
+ ,MoGoAiCloudClientConfig.getInstance().getToken()
+ ,new SweeperOperationStatusRequest(SweeperOrderModel.getInstance().mLongitude
+ , SweeperOrderModel.getInstance().mLatitude))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(getSubscribeImpl(context,callback,"stopTakeOrder"));
+ }
+
+ /**
+ * 出车
+ * @param context
+ * @param callback
+ */
+ public void startTakeOrder(Context context, ISweeperServiceCallback callback){
+ mService.startTakeOrder(MoGoAiCloudClientConfig.getInstance().getServiceAppId()
+ ,MoGoAiCloudClientConfig.getInstance().getToken()
+ ,new SweeperOperationStatusRequest(SweeperOrderModel.getInstance().mLongitude
+ , SweeperOrderModel.getInstance().mLatitude))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(getSubscribeImpl(context,callback,"startTakeOrder"));
+ }
+
+ /**
+ * 查询出车/收车状态
+ * @param context
+ * @param callback
+ */
+ public void queryOperationStatus(Context context, ISweeperServiceCallback callback){
+ mService.queryOperationStatus(MoGoAiCloudClientConfig.getInstance().getServiceAppId()
+ ,MoGoAiCloudClientConfig.getInstance().getToken(),MoGoAiCloudClientConfig.getInstance().getSn())
+ .subscribeOn( Schedulers.io() )
+ .observeOn( AndroidSchedulers.mainThread() )
+ .subscribe(getSubscribeImpl(context,callback,"queryOperationStatus"));
+ }
+
+
+ public void queryBusLines(Context context, ISweeperServiceCallback callback){
+ mService.queryBusLines(MoGoAiCloudClientConfig.getInstance().getServiceAppId()
+ ,MoGoAiCloudClientConfig.getInstance().getToken(),MoGoAiCloudClientConfig.getInstance().getSn())
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(getSubscribeImpl(context,callback,"queryBusLines"));
+ }
+
+ public void updateOrderRoute(Context context,int lineId, int startSiteId, int endSiteId
+ , List< SweeperRoutePlanningUpdateReqBean.Result > points
+ , ISweeperServiceCallback callback){
+ mService.updateOrderRoute(MoGoAiCloudClientConfig.getInstance().getServiceAppId()
+ ,MoGoAiCloudClientConfig.getInstance().getToken()
+ ,new SweeperRoutePlanningUpdateReqBean(MoGoAiCloudClientConfig.getInstance().getSn()
+ ,lineId,startSiteId,endSiteId, points))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(getSubscribeImpl(context,callback,"updateOrderRoute"));
+ }
+
+ /**
+ * 车机端上传心跳数据(只在出车状态时上传):包含高德坐标系经纬度
+ * @param context
+ * @param lon
+ * @param lat
+ * @param callback
+ */
+ public void runCarHeartbeat(Context context, double lon, double lat,
+ ISweeperServiceCallback callback) {
+ mService.runCarHeartbeat(MoGoAiCloudClientConfig.getInstance().getServiceAppId()
+ ,MoGoAiCloudClientConfig.getInstance().getToken(),new CarHeartbeatReqBean(
+ MoGoAiCloudClientConfig.getInstance().getSn(), lon, lat))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(getSubscribeImpl(context, callback, "runCarHeartbeat"));
+ }
+
+ private SubscribeImpl getSubscribeImpl(Context context, ISweeperServiceCallback callback, String apiName){
+ return new SubscribeImpl(RequestOptions.create(context)){
+ @Override
+ public void onSuccess(T o) {
+ super.onSuccess(o);
+ CallerLogger.INSTANCE.e(M_BUS + TAG,apiName + ": onSuccess() " + o.msg);
+ if (callback != null) {
+ callback.onSuccess(o);
+ }
+ }
+
+ @Override
+ public void onError(String message, int code) {
+ super.onError(message, code);
+ CallerLogger.INSTANCE.e(M_BUS + TAG,apiName + ": onError() " +"msg="+ message+" code="+code);
+ if (callback != null) {
+ callback.onFail("msg="+ message+" code="+code);
+ }
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ super.onError(e);
+ CallerLogger.INSTANCE.e(M_BUS + TAG,apiName + ": onError() " +" e="+e.getMessage());
+ if (callback != null) {
+ callback.onFail(e.getMessage());
+ }
+ }
+ };
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/presenter/SweeperLinePresenter.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/presenter/SweeperLinePresenter.java
new file mode 100644
index 0000000000..5cfb5b80f2
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/presenter/SweeperLinePresenter.java
@@ -0,0 +1,79 @@
+package com.mogo.och.sweeper.presenter;
+
+import android.os.Looper;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.mogo.commons.mvp.Presenter;
+import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
+import com.mogo.och.sweeper.bean.SweeperQueryLinesResponse;
+import com.mogo.och.sweeper.callback.ISweeperLinesCallback;
+import com.mogo.och.sweeper.model.SweeperLineModel;
+import com.mogo.och.sweeper.model.SweeperOrderModel;
+import com.mogo.och.sweeper.ui.SweeperSwitchLineView;
+
+/**
+ * @author: wangmingjun
+ * @date: 2022/2/9
+ */
+public class SweeperLinePresenter extends Presenter implements ISweeperLinesCallback {
+
+ public SweeperLinePresenter(SweeperSwitchLineView view) {
+ super(view);
+ SweeperLineModel.getInstance().init();
+ SweeperOrderModel.getInstance().init();
+ }
+
+ @Override
+ public void onCreate(@NonNull LifecycleOwner owner) {
+ super.onCreate(owner);
+ initListener();
+ }
+
+ private void initListener() {
+ SweeperLineModel.getInstance().setBusLinesCallback(this);
+ }
+
+ private void runOnUIThread( Runnable executor ) {
+ if ( executor == null ) {
+ return;
+ }
+ if ( Looper.myLooper() != Looper.getMainLooper() ) {
+ UiThreadHandler.post( executor );
+ } else {
+ executor.run();
+ }
+ }
+
+ @Override
+ public void onBusLinesChange(SweeperQueryLinesResponse lines) {
+ runOnUIThread(() -> mView.onBusLinesChange(lines));
+ }
+
+ @Override
+ public void onChangeLineIdSuccess() {
+ runOnUIThread(() -> mView.onChangeLineIdSuccess());
+ }
+
+ public void queryBusLines(){
+ SweeperLineModel.getInstance().queryBusLines();
+ }
+
+ public void commitSwitchLineId(int lineId){
+ SweeperLineModel.getInstance().commitSwitchLineId(lineId);
+ }
+
+ public void removeListener(){
+ SweeperLineModel.getInstance().setBusLinesCallback(null);
+ }
+
+ public void queryBusRoutes(){
+ SweeperOrderModel.getInstance().querySweeperRoutes();
+ }
+
+ @Override
+ public void onDestroy(@NonNull LifecycleOwner owner) {
+ super.onDestroy(owner);
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/presenter/SweeperModelLoopManager.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/presenter/SweeperModelLoopManager.java
new file mode 100644
index 0000000000..ac03cc4800
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/presenter/SweeperModelLoopManager.java
@@ -0,0 +1,55 @@
+package com.mogo.och.sweeper.presenter;
+
+import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS;
+
+import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
+import com.mogo.och.sweeper.constant.SweeperConst;
+import com.mogo.och.sweeper.model.SweeperOrderModel;
+
+import java.util.concurrent.TimeUnit;
+
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * Created on 2021/11/22
+ *
+ * 管理轮询逻辑(订单轮询、新单轮询、新单抢单结果轮询等等)
+ */
+public class SweeperModelLoopManager {
+
+ private static final String TAG = SweeperModelLoopManager.class.getSimpleName();
+
+ private static final class SingletonHolder {
+ private static final SweeperModelLoopManager INSTANCE = new SweeperModelLoopManager();
+ }
+
+ public static SweeperModelLoopManager getInstance() {
+ return SingletonHolder.INSTANCE;
+ }
+
+ private Disposable mHeartbeatDisposable; //心跳轮询
+
+ public void startHeartbeatLoop() {
+ if (mHeartbeatDisposable != null && !mHeartbeatDisposable.isDisposed()) {
+ return;
+ }
+ CallerLogger.INSTANCE.i(M_BUS + TAG, "startHeartbeatLoop()");
+ mHeartbeatDisposable = Observable.interval(SweeperConst.LOOP_DELAY,
+ SweeperConst.LOOP_PERIOD_60S, TimeUnit.MILLISECONDS)
+ .map((aLong -> aLong + 1))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(aLong -> SweeperOrderModel.getInstance().runCarHeartbeat());
+ }
+
+ public void stopHeartbeatLoop() {
+ if (mHeartbeatDisposable != null) {
+ CallerLogger.INSTANCE.i(M_BUS + TAG, "stopHeartbeatLoop()");
+ mHeartbeatDisposable.dispose();
+ mHeartbeatDisposable = null;
+ }
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/presenter/SweeperPresenter.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/presenter/SweeperPresenter.java
new file mode 100644
index 0000000000..02a7075a08
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/presenter/SweeperPresenter.java
@@ -0,0 +1,288 @@
+package com.mogo.och.sweeper.presenter;
+
+import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS;
+
+import android.location.Location;
+import android.os.Looper;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.LifecycleOwner;
+
+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.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.UiThreadHandler;
+import com.mogo.och.sweeper.bean.SweeperStationBean;
+import com.mogo.och.sweeper.callback.ICarOperationStatusCallback;
+import com.mogo.och.sweeper.callback.ISweeperControllerStatusCallback;
+import com.mogo.och.sweeper.callback.IRefreshSweeperStationsCallback;
+import com.mogo.och.sweeper.callback.ISlidePannelHideCallback;
+import com.mogo.och.sweeper.fragment.SweeperFragment;
+import com.mogo.och.sweeper.model.SweeperOrderModel;
+import com.mogo.och.sweeper.util.SweeperTrajectoryManager;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import mogo.telematics.pad.MessagePad;
+import mogo_msg.MogoReportMsg;
+import system_master.SystemStatusInfo;
+
+/**
+ * 网约车小巴
+ *
+ * @author tongchenfei
+ */
+public class SweeperPresenter extends Presenter
+ implements ICarOperationStatusCallback, IRefreshSweeperStationsCallback, ISlidePannelHideCallback
+ , IMoGoAutopilotStatusListener, ISweeperControllerStatusCallback {
+
+ private static final String TAG = "BusPresenter";
+
+ private int currentAutopilotStatus = -1;
+ private List mStationList = new ArrayList<>();
+ private int mCurrentStation = 0;
+ private boolean isRestartAutopilot = false;
+
+ public SweeperPresenter(SweeperFragment view) {
+ super(view);
+ //2021.11.1 鹰眼架构整合,由IMoGoAutopilotStatusListener逐步替代IMogoAdasOCHCallback接口
+ CallerAutoPilotStatusListenerManager.INSTANCE.addListener(TAG, this);
+ SweeperOrderModel.getInstance().init();
+ }
+
+ @Override
+ public void onCreate(@NonNull LifecycleOwner owner) {
+ super.onCreate(owner);
+ SweeperOrderModel.getInstance().queryOperationStatus();
+ SweeperOrderModel.getInstance().querySweeperRoutes();
+ initModelListener();
+ }
+
+ @Override
+ public void onDestroy(@NonNull LifecycleOwner owner) {
+ super.onDestroy(owner);
+ SweeperOrderModel.getInstance().release();
+ releaseListener();
+ }
+
+ public void initModelListener() {
+ SweeperOrderModel.getInstance().setCarOperationStatusCallback(this);
+ SweeperOrderModel.getInstance().setRefreshBusStationsCallback(this);
+ SweeperOrderModel.getInstance().setSlidePannelHideCallback(this);
+ SweeperOrderModel.getInstance().setControllerStatusCallback(this);
+ }
+
+ public void releaseListener() {
+ SweeperOrderModel.getInstance().setCarOperationStatusCallback(null);
+ SweeperOrderModel.getInstance().setRefreshBusStationsCallback(null);
+ SweeperOrderModel.getInstance().setSlidePannelHideCallback(null);
+ SweeperOrderModel.getInstance().setControllerStatusCallback(null);
+ }
+
+ public void querySweepersRoutes() {
+ SweeperOrderModel.getInstance().querySweeperRoutes();
+ }
+
+ public void debugResetStationStatus() {
+ SweeperOrderModel.getInstance().debugResetStationStatus();
+ }
+
+ public void autoDriveToNextStation(boolean isRestart) {
+ currentAutopilotStatus = -1;
+ SweeperOrderModel.getInstance().autoDriveToNextStation(isRestart);
+ isRestartAutopilot = false;
+ }
+
+ public void restartAutopilot() {
+// if (SweeperOrderModel.getInstance().isGoingToNextStation()){
+ currentAutopilotStatus = -1;
+ SweeperOrderModel.getInstance().restartAutopilot();
+ isRestartAutopilot = true;
+// }
+ }
+
+ public void onChangeOperationStatus() {
+ SweeperOrderModel.getInstance().onChangeOperationStatus();
+ }
+
+ @Override
+ public void changeOperationStatus(boolean changeStatus) {
+ if (mView != null) {
+ runOnUIThread(() -> mView.changeOperationStatus(changeStatus));
+ }
+ }
+
+ @Override
+ public void refreshBusStations(String lineName,List stationList
+ , int currentStation, int nextStation, boolean isArrived) {
+ mStationList.clear();
+ mStationList.addAll(stationList);
+ mCurrentStation = currentStation;
+// functionDemoModeChange();
+ CallerLogger.INSTANCE.d(M_BUS + "BusOrderModel =", " mCurrentStation =" + mCurrentStation);
+ if (mView != null) {
+ runOnUIThread(() -> mView.refreshSweeperStations(lineName,
+ stationList, currentStation, nextStation, isArrived));
+ }
+ }
+
+ private void functionDemoModeChange() {
+// CallerLogger.INSTANCE.d(M_BUS + "BusOrderModel ="," functionDemoModeChange ="+mCurrentStation);
+ if (FunctionBuildConfig.isDemoMode
+ && ((mCurrentStation > 0 && mCurrentStation < mStationList.size() - 1)
+ || ((mCurrentStation == 0 || mCurrentStation == mStationList.size() - 1)
+ && SweeperOrderModel.getInstance().isGoingToNextStation()))) {
+ runOnUIThread(() -> mView.onAutopilotStatusChanged(
+ IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING));
+ }
+ }
+
+ @Override
+ public void hideSlidePanel() {
+ if (mView != null) {
+ runOnUIThread(() -> mView.hideSlidePanel());
+ }
+ }
+
+ @Override
+ public void onAutopilotArriveAtStation(MessagePad.ArrivalNotification arrivalNotification) {
+ SweeperOrderModel.getInstance().onArriveAt(arrivalNotification);
+ }
+
+ @Override
+ public void onAutopilotSNRequest() {
+
+ }
+
+ @Override
+ public void onAutopilotStatusResponse(@NotNull AutopilotStatusInfo autopilotStatusInfo) {
+ if (autopilotStatusInfo == null) return;
+ int state = autopilotStatusInfo.getState();
+// CallerLogger.INSTANCE.d(M_BUS + TAG, "onStateChange: " + state + "currentAutopilotStatus = " + currentAutopilotStatus);
+ switch (state) {
+ case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE:
+ if (currentAutopilotStatus != IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE) {
+ if (currentAutopilotStatus == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) {//2-->1语音提示
+// AIAssist.getInstance( getContext() ).speakTTSVoice( "已进入人工驾驶模式" );
+ }
+ currentAutopilotStatus = IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE;
+ // 设置UI【自动驾驶】按钮是否展示
+ runOnUIThread(() -> mView.onAutopilotEnableChange(true));
+ if (SweeperOrderModel.getInstance().isGoingToNextStation()) {
+ runOnUIThread(() -> mView.hideSlidePanel());
+ }
+ if (FunctionBuildConfig.isDemoMode
+ && (
+ (mCurrentStation > 0 && mCurrentStation < mStationList.size() - 1)
+ || (
+ (mCurrentStation == 0 || mCurrentStation == mStationList.size() - 1)
+ && SweeperOrderModel.getInstance().isGoingToNextStation()
+ )
+ )
+ ) {
+ CallerLogger.INSTANCE.d(M_BUS + "BusOrderModel=", "有美化功能");
+ return;
+ }
+ // 改变UI自动驾驶状态
+ runOnUIThread(() -> mView.onAutopilotStatusChanged(currentAutopilotStatus));
+ }
+ break;
+ case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING:
+ if (currentAutopilotStatus != IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) {
+ currentAutopilotStatus = IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING;
+ // 改变UI自动驾驶状态
+ runOnUIThread(() -> mView.onAutopilotStatusChanged(currentAutopilotStatus));
+ SweeperOrderModel.getInstance().triggerStartServiceEvent(
+ isRestartAutopilot, true);
+ }
+ break;
+ case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE:
+ if (currentAutopilotStatus != IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE) {
+ if (currentAutopilotStatus == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) {//2-->0语音提示
+// AIAssist.getInstance( getContext() ).speakTTSVoice( "自动驾驶已停止,请人工接管" );
+ }
+ currentAutopilotStatus = IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE;
+ if (FunctionBuildConfig.isDemoMode
+ && (
+ (mCurrentStation > 0 && mCurrentStation < mStationList.size() - 1)
+ || (
+ (mCurrentStation == 0 || mCurrentStation == mStationList.size() - 1)
+ && SweeperOrderModel.getInstance().isGoingToNextStation()
+ )
+ )
+ ) {
+ CallerLogger.INSTANCE.d(M_BUS + "BusOrderModel=", "有美化功能");
+ return;
+ }
+ runOnUIThread(() -> {
+ mView.onAutopilotStatusChanged(currentAutopilotStatus);
+ });
+ }
+ break;
+ default:
+ runOnUIThread(() -> mView.onAutopilotEnableChange(false));
+ break;
+ }
+ }
+
+ @Override
+ public void onVRModeChanged(boolean isVRMode) {
+ runOnUIThread(() -> mView.onVRModeChanged(isVRMode));
+ }
+
+ @Override
+ public void onCarLocationChanged(Location location) {
+ if (null != location) {
+ runOnUIThread(() -> mView.updateSpeedView(location.getSpeed()));
+ }
+ }
+
+ @Override
+ public void startOpenAutopilot() {
+ //非美化模式下启动动画
+ runOnUIThread(() -> mView.startAutopilotAnimation());
+ }
+
+ private void runOnUIThread(Runnable executor) {
+ if (executor == null) {
+ return;
+ }
+ if (Looper.myLooper() != Looper.getMainLooper()) {
+ UiThreadHandler.post(executor);
+ } else {
+ executor.run();
+ }
+ }
+
+ /**
+ * 测试使用
+ *
+ * @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) {
+
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/receiver/TestSweeperBroadcastReceiver.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/receiver/TestSweeperBroadcastReceiver.java
new file mode 100644
index 0000000000..b2ef6bcadd
--- /dev/null
+++ b/OCH/mogo-och-sweeper/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/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/ui/SweeperOperatePanelView.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/ui/SweeperOperatePanelView.java
new file mode 100644
index 0000000000..c58f59b384
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/ui/SweeperOperatePanelView.java
@@ -0,0 +1,1063 @@
+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.content.Context;
+import android.content.DialogInterface;
+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.widget.CheckedTextView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+
+import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotVehicleStateListener;
+import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotManager;
+import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotVehicleStateListenerManager;
+import com.mogo.eagle.core.utilcode.util.ThreadUtils;
+import com.mogo.eagle.core.utilcode.util.ToastUtils;
+import com.mogo.module.common.view.OnPreventFastClickListener;
+import com.mogo.och.sweeper.R;
+import com.mogo.och.sweeper.util.SweeperFutianCmdUtil;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import chassis.Chassis;
+import chassis.SpecialVehicleTaskCmdOuterClass;
+import chassis.VehicleStateOuterClass;
+
+/**
+ * 清扫车操作面板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;
+
+ CheckedTextView mBtnCleanWorkOpenClose;//开关
+ CheckedTextView mBtnCleanModePureSweep;//纯扫
+ CheckedTextView mBtnCleanModePureWash;//纯洗
+ CheckedTextView mBtnCleanModeSweepWash;//洗扫
+ CheckedTextView mBtnCleanModePureAbsorption;//纯吸
+ CheckedTextView mBtnCleanDirectionLeftSide;//左侧
+ CheckedTextView mBtnCleanDirectionRightSide;//右侧
+ CheckedTextView mBtnCleanDirectionBothSide;//两侧
+ CheckedTextView mBtnCleanIntensityStandard;//普通
+ CheckedTextView mBtnCleanIntensityStrong;//强力
+ LinearLayout mLoadingContainer;//loading container
+ TextView mLoadingHintTop;//loading 提示-上面
+ TextView mLoadingHintBottom;//loading 提示-下面
+
+ // 作业模式相关操作按钮的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);
+ }
+ };
+
+ 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);
+ 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);
+ mLoadingHintTop = findViewById(R.id.loading_hint_top);
+ mLoadingHintBottom = findViewById(R.id.loading_hint_bottom);
+ 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(VehicleStateOuterClass.SweeperFuTianCleanSystemState cleanSystemState) {
+ boolean success = false;
+ if (cleanSystemState == null) {
+ return success;
+ }
+ if (isCloseAction) {
+ success = !cleanSystemState.getSecuMotWorkSts();
+ } else {
+ success = cleanSystemState.getSecuMotWorkSts();
+ }
+ return success;
+ }
+
+ @Override
+ public void onCmdSuccess() {
+ runOnUIThread(() -> {
+ if (isCloseAction) {
+ mBtnCleanWorkOpenClose.setText("Open");
+ mBtnCleanWorkOpenClose.setChecked(false);
+ toggleCleanModeBtnsStatus(false);
+ toggleCleanDirectionBtnsStatus(false);
+ toggleCleanIntensityBtnsStatus(false);
+ } else {
+ mBtnCleanWorkOpenClose.setText("Close");
+ mBtnCleanWorkOpenClose.setChecked(true);
+ toggleCleanModeBtnsStatus(true);
+ }
+ hideLoadingMask();
+ showCmdExecuteSuccessToast();
+ });
+ }
+
+ @Override
+ public void onCmdFailed() {
+ }
+
+ @Override
+ public void onCmdTimeout() {
+ //按钮样式恢复原样
+ runOnUIThread(() -> {
+ if (isCloseAction) {
+ mBtnCleanWorkOpenClose.setText("Close");
+ mBtnCleanWorkOpenClose.setChecked(true);
+ } else {
+ mBtnCleanWorkOpenClose.setText("Open");
+ mBtnCleanWorkOpenClose.setChecked(false);
+ }
+ hideLoadingMask();
+ showCmdExecuteTimeoutToast();
+ });
+ }
+ };
+ if (isCloseAction) {
+ //关闭操作,点击时需要弹框提示确认后,关闭
+ showConfirmCleanWorkCloseDialog(() -> {
+ 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(VehicleStateOuterClass.SweeperFuTianCleanSystemState 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 = 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;
+ } else if (isPureSweepClick) {
+ //success = clean_mode_pure_sweep;
+ //纯扫 这个模式实际在福田清扫车上没有这个按钮,只是发送指令给特种车端,默认此命令肯定是正确的
+ success = true;
+ } else if (isPureWashClick) {
+ success = clean_mode_pure_wash;
+ } else if (isWashSweepClick) {
+ success = clean_mode_wash_sweep;
+ } else if (isPureAbsorptionClick) {
+ success = clean_mode_pure_draw;
+ }
+ return success;
+ }
+
+ @Override
+ public void onCmdSuccess() {
+ runOnUIThread(() -> {
+ ((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() {
+ runOnUIThread(() -> {
+ ((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(VehicleStateOuterClass.SweeperFuTianCleanSystemState 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() {
+ runOnUIThread(() -> {
+ ((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() {
+ runOnUIThread(() -> {
+ ((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) {
+ 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(VehicleStateOuterClass.SweeperFuTianCleanSystemState 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() {
+ runOnUIThread(() -> {
+ ((CheckedTextView) currentClickView).setChecked(true);
+ if (isStandardBtnClick) {
+ setCleanIntensityStandard();
+ } else {
+ setCleanIntensityStrong();
+ }
+ hideLoadingMask();
+ showCmdExecuteSuccessToast();
+ });
+ }
+
+ @Override
+ public void onCmdFailed() {
+ }
+
+ @Override
+ public void onCmdTimeout() {
+ runOnUIThread(() -> {
+ ((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) {
+ showLoadingMask("执行中,请稍后。。。", timeout);
+ }
+
+ /**
+ * 发送命令后等待时,展示loading
+ *
+ * @param hint
+ * @param timeout
+ */
+ private void showLoadingMask(String hint, int timeout) {
+ runOnUIThread(() -> {
+ mLoadingContainer.setVisibility(View.VISIBLE);
+ mLoadingHintTop.setText(hint);
+ mLoadingHintBottom.setText(
+ String.format(
+ getContext().getApplicationContext().getString(R.string.sweeper_operate_panel_cmd_execute_timeout),
+ timeout
+ ));
+ mLoadingHintBottom.setVisibility(timeout < 0 ? View.INVISIBLE : View.VISIBLE);
+ });
+ }
+
+ /**
+ * 隐藏loading
+ */
+ private void hideLoadingMask() {
+ runOnUIThread(() -> {
+ mSweeperOperateCmdHandler.removeMessages(MSG_CMD_EXECUTE_COUNT_DOWN);
+ mLoadingContainer.setVisibility(View.GONE);
+ });
+ }
+
+ /**
+ * 更新loading中倒计时
+ *
+ * @param timeout
+ */
+ private void updateLoadingCountDown(int timeout) {
+ runOnUIThread(() -> {
+ mLoadingHintBottom.setText(
+ String.format(
+ getContext().getApplicationContext().getString(R.string.sweeper_operate_panel_cmd_execute_timeout),
+ timeout
+ ));
+ });
+ }
+
+ /**
+ * 命令执行成功toast
+ */
+ private void showCmdExecuteSuccessToast() {
+ ToastUtils.showLong("设备已响应,操作成功");
+ }
+
+ /**
+ * 命令执行超时toast
+ */
+ private void showCmdExecuteTimeoutToast() {
+ ToastUtils.showLong("超时未响应,操作失败");
+ }
+
+ /**
+ * 根据底盘数据恢复操作面板中相关按钮状态 成功toast
+ */
+ private void showRecoverPanelButtonStateSuccessToast() {
+ ToastUtils.showLong("恢复操作面板状态成功");
+ }
+
+ /**
+ * 关闭清扫作业时,确认操作的弹框
+ *
+ * @param runnable
+ */
+ private void showConfirmCleanWorkCloseDialog(Runnable runnable) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setMessage("是否关闭清扫作业?");
+ builder.setCancelable(true);
+ builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ runnable.run();
+ dialog.dismiss();
+ }
+ });
+ builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ });
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
+ private void runOnUIThread(Runnable runnable) {
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ runnable.run();
+ }
+ });
+ }
+
+ private void setClickListener(View view, OnClickListener listener) {
+ view.setOnClickListener(new OnPreventFastClickListener() {
+ @Override
+ public void onClickImpl(View v) {
+ listener.onClick(v);
+ }
+ });
+ }
+
+ // 当前时间戳
+ private long mCurrentTimeMillis;
+ // 底盘数据回调时间间隔
+ private static final long VEHICLE_STATE_INTERVAL_MILLIS = 500L;
+
+ /**
+ * 底盘数据透传listener
+ */
+ private final IMoGoAutopilotVehicleStateListener mIMoGoAutopilotVehicleStateListener = new IMoGoAutopilotVehicleStateListener() {
+ @Override
+ public void onAutopilotDataException(long timestamp) {
+ }
+
+ @Override
+ public void onAutopilotLightSwitchData(@Nullable Chassis.LightSwitch lightSwitch) {
+ }
+
+ @Override
+ public void onAutopilotBrakeLightData(boolean brakeLight) {
+ }
+
+ @Override
+ public void onAutopilotSteeringData(float steering) {
+ }
+
+ @Override
+ public void onAutopilotGearData(@NonNull Chassis.GearPosition gear) {
+ }
+
+ @Override
+ public void onAutopilotAcc(float carAcc) {
+ }
+
+ @Override
+ public void onAutopilotThrottle(float throttle) {
+ }
+
+ @Override
+ public void onAutopilotBrake(float brake) {
+ }
+
+ @Override
+ public void onSweeperFutianCleanSystemState(@NonNull VehicleStateOuterClass.SweeperFuTianCleanSystemState cleanSystemState) {
+ long current = System.currentTimeMillis();
+ if (current - mCurrentTimeMillis <= VEHICLE_STATE_INTERVAL_MILLIS) {
+ return;
+ }
+ mCurrentTimeMillis = current;
+
+ Log.d(TAG, "onSweeperFutianCleanSystemState");
+ // 第一次进入时同步底盘状态,只拿第一次的数据
+ if (mSyncingVehicleState) {
+ onSyncVehicleStateCallBack(cleanSystemState);
+ return;
+ }
+ // 有命令正在执行
+ if (mCurrentCmdRequestCallback != null) {
+ Log.d(TAG, "getSecuWorkLeftSts = " + cleanSystemState.getSecuWorkLeftSts());
+ if (mCurrentCmdRequestCallback.onCheckIfCmdSuccess(cleanSystemState)) {
+ mCurrentCmdRequestCallback.onCmdSuccess();
+ mCurrentCmdRequestCallback = null;
+ }
+ }
+ }
+ };
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ CallerAutopilotVehicleStateListenerManager.INSTANCE.addListener(TAG, mIMoGoAutopilotVehicleStateListener);
+ // 最终调试时需要打开
+ syncVehicleStateAndRecoverOperatePanelStates();
+ // Mock VehicleState 数据回调
+ // UiThreadHandler.postDelayed(() -> {
+ // onSyncVehicleStateCallBack(SweeperFutianCmdUtil.buildSweeperFuTionCleanSystemStateMockData());
+ // }, 3000L);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ CallerAutopilotVehicleStateListenerManager.INSTANCE.removeListener(TAG);
+ }
+
+ /**
+ * 等待同步底盘数据,并根据底盘数据恢复操作面板中按钮的状态
+ */
+ private synchronized void syncVehicleStateAndRecoverOperatePanelStates() {
+ // show sync loading
+ showLoadingMask("状态同步中,请稍后", -1);
+ mSyncingVehicleState = true;
+ }
+
+ private synchronized void onSyncVehicleStateCallBack(VehicleStateOuterClass.SweeperFuTianCleanSystemState cleanSystemState) {
+ if (cleanSystemState == null) return;
+ mSyncingVehicleState = false;
+ // 清扫作业开启状态(以电机状态为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 = checkIfCleanModePureSweep(cleanSystemState);
+
+ // 作业强度状态
+ boolean clean_intensity_standard = cleanSystemState.getSecuWorkStandSts();
+ boolean clean_intensity_strong = cleanSystemState.getSecuWorkStrongSts();
+
+ runOnUIThread(() -> {
+ if (clean_open_requirement) {
+ // 打开状态
+ mBtnCleanWorkOpenClose.setText("Close");
+ mBtnCleanWorkOpenClose.setChecked(true);
+ } else {
+ // 关闭状态
+ mBtnCleanWorkOpenClose.setText("Open");
+ 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();
+ showRecoverPanelButtonStateSuccessToast();
+ });
+ }
+
+ /**
+ * 通过底盘数据判断是纯扫模式
+ *
+ * @param cleanSystemState
+ * @return
+ */
+ private boolean checkIfCleanModePureSweep(VehicleStateOuterClass.SweeperFuTianCleanSystemState 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;
+ }
+
+ /**
+ * 发送清扫车相关作业命令
+ *
+ * @param fuTianCleanCmd
+ * @param cmdRequestCallback
+ * @param timeout
+ */
+ private void sendSweeperCmd(
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd fuTianCleanCmd,
+ CmdRequestCallback cmdRequestCallback,
+ int timeout) {
+ // 设置当前请求的回调
+ mCurrentCmdRequestCallback = cmdRequestCallback;
+ // onSendCmd
+ mCurrentCmdRequestCallback.onSendCmd();
+ // 发送命令
+ CallerAutoPilotManager.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
+// mockSendCmdSuccess();
+ }
+
+ 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 boolean mSyncingVehicleState;//第一次进入页面时,同步底盘状态的标志位
+ 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) {
+ mCurrentCmdRequestCallback.onCmdSuccess();
+ mCurrentCmdRequestCallback = null;
+ }
+ removeMessages(MSG_CMD_EXECUTE_COUNT_DOWN);
+ }
+ }
+ }
+
+ interface CmdRequestCallback {
+ void onSendCmd();
+
+ void onCountDownTick(int senonds);
+
+ boolean onCheckIfCmdSuccess(VehicleStateOuterClass.SweeperFuTianCleanSystemState cleanSystemState);
+
+ void onCmdSuccess();
+
+ void onCmdFailed();
+
+ void onCmdTimeout();
+ }
+
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/ui/SweeperSwitchLineActivity.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/ui/SweeperSwitchLineActivity.java
new file mode 100644
index 0000000000..dedd34cb21
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/ui/SweeperSwitchLineActivity.java
@@ -0,0 +1,300 @@
+package com.mogo.och.sweeper.ui;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.mogo.commons.mvp.MvpActivity;
+import com.mogo.eagle.core.utilcode.util.ToastUtils;
+import com.mogo.och.sweeper.R;
+import com.mogo.och.sweeper.bean.SweeperQueryLinesResponse;
+import com.mogo.och.sweeper.presenter.SweeperLinePresenter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author: wangmingjun
+ * @date: 2022/2/8
+ */
+public class SweeperSwitchLineActivity extends MvpActivity
+ implements View.OnClickListener, SweeperSwitchLineView {
+
+ private ImageView mClose;
+ private ConstraintLayout mNoDatasView;
+ private RecyclerView mLinesListView;
+ private TextView mLineCommitBtn;
+ private SwitchLineAdapter mAdapter;
+ private List mData = new ArrayList<>();
+ private int mSelectLineId = -1;
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.activity_sweeper_switch_line;
+ }
+
+ @NonNull
+ @Override
+ protected SweeperLinePresenter createPresenter() {
+ return new SweeperLinePresenter(this);
+ }
+
+ @Override
+ protected void initViews() {
+ initWH();
+ initView();
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ initDatas();
+ }
+
+ /**
+ * 初始化view
+ */
+ private void initView() {
+ mClose = findViewById(R.id.switch_line_close);
+ mClose.setOnClickListener(this);
+ mNoDatasView = findViewById(R.id.no_order_data_view);
+
+ mLineCommitBtn = findViewById(R.id.switch_line_btn_commit);
+ mLineCommitBtn.setOnClickListener(this);
+
+ mLinesListView = findViewById(R.id.switch_line_rv);
+ mLinesListView.setLayoutManager(new LinearLayoutManager(this));
+ mAdapter = new SwitchLineAdapter(getApplicationContext(),mData);
+ mLinesListView.setAdapter(mAdapter);
+ //设置item 点击事件
+ mAdapter.setOnLineItemClickListener(new LineItemClickListener() {
+ @Override
+ public void onItemClick(int position) {
+ if (mData.size() > position && !TextUtils.isEmpty(mData.get(position).startSiteName )
+ && !TextUtils.isEmpty(mData.get(position).endSiteName)){
+ mSelectLineId = mData.get(position).lineId;
+ }else {
+ mSelectLineId = -1;
+ }
+ }
+ });
+ }
+
+ /**
+ * 设置布局宽高
+ */
+ private void initWH() {
+
+ Window window = getWindow();
+
+ WindowManager.LayoutParams params = window.getAttributes();
+ WindowManager windowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
+ Point point = new Point();
+ windowManager.getDefaultDisplay().getSize(point);//用于获取屏幕高度
+
+ params.width = (int)(point.x * 0.375);
+ params.height = ViewGroup.LayoutParams.MATCH_PARENT;
+ window.setAttributes(params);
+ window.setGravity(Gravity.LEFT|Gravity.BOTTOM);
+ }
+
+ /**
+ * 初始化数据
+ */
+ private void initDatas() {
+ mPresenter.queryBusLines();
+ }
+
+ /**
+ * 查询返回绑定路线集合
+ * @param data
+ */
+ @Override
+ public void onBusLinesChange(SweeperQueryLinesResponse data){
+ if (null == data){
+ showNoData(true);
+ return;
+ }
+ if (data.data != null && data.data.size() > 0){
+ showNoData(false);
+ mData.clear();
+ mData.addAll(data.data);
+ mAdapter.notifyDataSetChanged();
+ changeCommitBtnBg();
+ }else {
+ showNoData(true);
+ }
+ }
+
+ /**
+ * 根据路线选中情况设置提交按钮样式
+ */
+ private void changeCommitBtnBg() {
+ for (int i=0; i -1){
+ mPresenter.commitSwitchLineId(mSelectLineId);
+ }else {
+ finish();
+ }
+ return;
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ }
+
+ /**
+ * 路线列表adapter
+ */
+ static class SwitchLineAdapter extends RecyclerView.Adapter{
+
+ private Context mContext;
+ private List mData;
+ // RecyclerView设置点击事件
+ private LineItemClickListener mItemClickListener ;
+ private int clickPos = -1;
+
+ public SwitchLineAdapter(Context context, List data){
+ mContext = context;
+ mData = data;
+ }
+
+ @NonNull
+ @Override
+ public SwitchLineViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(mContext).inflate(R.layout.sweeper_switch_line_list_item
+ ,parent,false);
+ SwitchLineViewHolder viewHolder = new SwitchLineViewHolder(view);
+ return viewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull SwitchLineViewHolder holder, @SuppressLint("RecyclerView") int position) {
+ SweeperQueryLinesResponse.Result line = mData.get(position);
+ holder.lineName.setText(mContext.getString(R.string.sweeper_switch_line_name)+" "+line.name);
+ holder.lineStartName.setText(mContext.getString(R.string.sweeper_line_start)+" "+line.startSiteName);
+ holder.lineEndName.setText(mContext.getString(R.string.sweeper_line_end)+" "+line.endSiteName);
+
+ //设置item点击事件
+ holder.itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mItemClickListener != null){
+ mItemClickListener.onItemClick(position);
+ clickPos = position;
+ notifyDataSetChanged();
+ }
+ }
+ });
+ //选中绑定
+ if (clickPos > -1){
+ if (clickPos == position){
+ holder.selectIv.setImageResource(R.drawable.sweeper_selected_btn);
+ }else {
+ holder.selectIv.setImageResource(R.drawable.sweeper_unselect_btn);
+ }
+ }else {
+ if (line.choose == 1){//1:绑定 2:未绑定 默认绑定
+ if (mItemClickListener != null) {
+ mItemClickListener.onItemClick(position);
+ }
+ holder.selectIv.setImageResource(R.drawable.sweeper_selected_btn);
+ }else {
+ holder.selectIv.setImageResource(R.drawable.sweeper_unselect_btn);
+ }
+ }
+
+ }
+
+ @Override
+ public int getItemCount() {
+ return mData.size();
+ }
+ public void setOnLineItemClickListener(LineItemClickListener itemClickListener){
+ this.mItemClickListener = itemClickListener ;
+
+ }
+ }
+
+ static class SwitchLineViewHolder extends RecyclerView.ViewHolder{
+
+ private ImageView selectIv;
+ private TextView lineName; //线路名称
+ private TextView lineStartName; //起点
+ private TextView lineEndName; //终点
+
+ public SwitchLineViewHolder(@NonNull View itemView) {
+ super(itemView);
+ selectIv = itemView.findViewById(R.id.switch_line_item_select_iv);
+ lineName = itemView.findViewById(R.id.switch_line_name);
+ lineStartName = itemView.findViewById(R.id.switch_line_start_station);
+ lineEndName = itemView.findViewById(R.id.switch_line_end_station);
+ }
+ }
+
+ public interface LineItemClickListener {
+ void onItemClick(int position) ;
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/ui/SweeperSwitchLineView.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/ui/SweeperSwitchLineView.java
new file mode 100644
index 0000000000..3cfdb9fdb9
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/ui/SweeperSwitchLineView.java
@@ -0,0 +1,15 @@
+package com.mogo.och.sweeper.ui;
+
+import com.mogo.commons.mvp.IView;
+import com.mogo.och.sweeper.bean.SweeperQueryLinesResponse;
+
+/**
+ * @author: wangmingjun
+ * @date: 2022/2/10
+ */
+public interface SweeperSwitchLineView extends IView {
+
+ void onBusLinesChange(SweeperQueryLinesResponse data);
+ void onChangeLineIdSuccess();
+}
+
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/ui/SweeperTrafficLightView.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/ui/SweeperTrafficLightView.java
new file mode 100644
index 0000000000..5f99d4836e
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/ui/SweeperTrafficLightView.java
@@ -0,0 +1,167 @@
+package com.mogo.och.sweeper.ui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.ImageView;
+
+import com.mogo.eagle.core.function.api.hmi.view.IViewTrafficLight;
+import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
+import com.mogo.och.sweeper.R;
+import com.mogo.och.common.module.wigets.OCHGradientTextView;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Bus司机端:红绿灯view
+ *
+ * Created on 2022/3/29
+ */
+public class SweeperTrafficLightView extends IViewTrafficLight {
+
+ private ImageView mLightIconIV;
+ private OCHGradientTextView mLightTimeTV;
+ private int mCurrentLightId;
+
+ public SweeperTrafficLightView(@Nullable Context context) {
+ this(context, null, 0);
+ }
+
+ public SweeperTrafficLightView(@Nullable Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SweeperTrafficLightView(@Nullable Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context);
+ }
+
+ private void init(Context context) {
+ LayoutInflater.from(context).inflate(R.layout.sweeper_traffic_light_view, this, true);
+ mLightIconIV = findViewById(R.id.sweeper_traffic_light_iv);
+ mLightTimeTV = findViewById(R.id.sweeper_traffic_light_time_tv);
+ }
+
+ /**
+ * 展示红绿灯预警
+ *
+ * @param checkLightId 0-都是默认,1-红,2-黄,3-绿
+ * @param lightSource 1:云端下发;2:自车感知
+ */
+ @Override
+ public void showWarningTrafficLight(int checkLightId,int lightSource) {
+ super.showWarningTrafficLight(checkLightId,lightSource);
+ mCurrentLightId = checkLightId;
+ updateTrafficLightIcon(checkLightId);
+ }
+
+ /**
+ * 关闭红绿灯预警展示,并重制灯态
+ */
+ @Override
+ public void disableWarningTrafficLight() {
+ super.disableWarningTrafficLight();
+ UiThreadHandler.post(() -> {
+ mCurrentLightId = 0;
+ SweeperTrafficLightView.this.setVisibility(GONE);
+ });
+ }
+
+ /**
+ * @param redNum 红灯倒计时
+ * @param yellowNum 黄灯倒计时
+ * @param greenNum 绿灯倒计时
+ */
+ @Override
+ public void changeCountdownTrafficLightNum(int redNum, int yellowNum, int greenNum) {
+ super.changeCountdownTrafficLightNum(redNum, yellowNum, greenNum);
+ switch (mCurrentLightId) {
+ case 1:
+ changeCountdownRed(redNum);
+ break;
+ case 2:
+ changeCountdownYellow(yellowNum);
+ break;
+ case 3:
+ changeCountdownGreen(greenNum);
+ break;
+ default:
+ UiThreadHandler.post(() -> {
+ mLightTimeTV.setText("");
+ });
+ break;
+ }
+ }
+
+ @Override
+ public void changeCountdownRed(int redNum) {
+ super.changeCountdownRed(redNum);
+ UiThreadHandler.post(() -> {
+ if (redNum > 0) {
+ mLightTimeTV.setVertrial(true);
+ mLightTimeTV.setmColorList(new int[]{getResources().getColor(R.color.sweeper_traffic_light_red_color_up),
+ getResources().getColor(R.color.sweeper_traffic_light_red_color_down)});
+ mLightTimeTV.setText(String.valueOf(redNum));
+ } else {
+ mLightTimeTV.setText("");
+ }
+ });
+ }
+
+ @Override
+ public void changeCountdownGreen(int greenNum) {
+ super.changeCountdownGreen(greenNum);
+ UiThreadHandler.post(() -> {
+ if (greenNum > 0) {
+ mLightTimeTV.setVertrial(true);
+ mLightTimeTV.setmColorList(new int[]{getResources().getColor(R.color.sweeper_traffic_light_green_color_up),
+ getResources().getColor(R.color.sweeper_traffic_light_green_color_down)});
+ mLightTimeTV.setText(String.valueOf(greenNum));
+ } else {
+ mLightTimeTV.setText("");
+ }
+ });
+ }
+
+ @Override
+ public void changeCountdownYellow(int yellowNum) {
+ super.changeCountdownYellow(yellowNum);
+ UiThreadHandler.post(() -> {
+ if (yellowNum > 0) {
+ mLightTimeTV.setVertrial(true);
+ mLightTimeTV.setmColorList(new int[]{getResources().getColor(R.color.sweeper_traffic_light_yellow_color_up),
+ getResources().getColor(R.color.sweeper_traffic_light_yellow_color_down)});
+ mLightTimeTV.setText(String.valueOf(yellowNum));
+ } else {
+ mLightTimeTV.setText("");
+ }
+ });
+ }
+
+ /**
+ * 更新红绿灯icon
+ *
+ * @param lightId 0-都是默认,1-红,2-黄,3-绿
+ */
+ private void updateTrafficLightIcon(int lightId) {
+ UiThreadHandler.post(() -> {
+ switch (lightId) {
+ case 1:
+ mLightIconIV.setBackgroundResource(R.drawable.sweeper_light_red_nor);
+ SweeperTrafficLightView.this.setVisibility(VISIBLE);
+ break;
+ case 2:
+ mLightIconIV.setBackgroundResource(R.drawable.sweeper_lightyellow_nor);
+ SweeperTrafficLightView.this.setVisibility(VISIBLE);
+ break;
+ case 3:
+ mLightIconIV.setBackgroundResource(R.drawable.sweeper_light_green_nor);
+ SweeperTrafficLightView.this.setVisibility(VISIBLE);
+ break;
+ default:
+ SweeperTrafficLightView.this.setVisibility(GONE);
+ break;
+ }
+ });
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/util/BDRouteDataTestUtils.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/util/BDRouteDataTestUtils.java
new file mode 100644
index 0000000000..85634178f1
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/util/BDRouteDataTestUtils.java
@@ -0,0 +1,45 @@
+package com.mogo.och.sweeper.util;
+
+import com.mogo.och.sweeper.model.SweeperOrderModel;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import mogo.telematics.pad.MessagePad;
+
+/**
+ * @author: wangmingjun
+ * @date: 2022/4/13
+ */
+public class BDRouteDataTestUtils {
+
+ static String jsonStr ="{\n" +
+ " \"models\": [\n" +
+ " {\n" +
+ " \"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19927760268911,\"lon\":116.73512607061035,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19927736555187,\"lon\":116.73498243020299,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19927135941599,\"lon\":116.73482951462647,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199260672670036,\"lon\":116.73468429259535,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199251260349946,\"lon\":116.73453933465,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19924691997577,\"lon\":116.7343756435551,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199247953493625,\"lon\":116.73421240809087,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19924986849947,\"lon\":116.73400425509712,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199249431152175,\"lon\":116.73378579041055,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199248921305724,\"lon\":116.73357811807278,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19925012387371,\"lon\":116.73337650020184,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199252270195075,\"lon\":116.73318223781153,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.1992521615169,\"lon\":116.73298632625203,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19925202633083,\"lon\":116.73279582043983,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199261230205735,\"lon\":116.73263403473568,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199327991681926,\"lon\":116.73251962434813,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19944850496711,\"lon\":116.73249661840195,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199582026896415,\"lon\":116.73251038561487,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199743326352014,\"lon\":116.73253087453938,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199908347167394,\"lon\":116.73255070500186,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.200065950595445,\"lon\":116.7325720694418,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20022747460407,\"lon\":116.73259461416663,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.200384057310536,\"lon\":116.73261575018056,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20053849777916,\"lon\":116.73263451936387,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.200696919444624,\"lon\":116.7326540541723,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.2008524952796,\"lon\":116.7326743511824,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20101429705625,\"lon\":116.73269393580199,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20118279997041,\"lon\":116.73271564378308,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.201342388452076,\"lon\":116.73273653366076,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.201476063822355,\"lon\":116.73275292393079,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20163479199852,\"lon\":116.73277440686762,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20181243476041,\"lon\":116.7328052766508,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.201991767093304,\"lon\":116.7328453845644,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20215573733484,\"lon\":116.73287624009339,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202313648759784,\"lon\":116.73289887933315,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202434745374454,\"lon\":116.7329182210956,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20253164952098,\"lon\":116.73297539811277,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20258043275509,\"lon\":116.73312335324984,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20258233576585,\"lon\":116.73331077089557,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20257107560234,\"lon\":116.73351244039137,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202561578580514,\"lon\":116.73370176209845,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20256256788661,\"lon\":116.73391325024126,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20255633158834,\"lon\":116.73413195000244,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202543311179575,\"lon\":116.73436614303907,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20253067346457,\"lon\":116.73458032609663,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20251776111356,\"lon\":116.73477082198242,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202503997557805,\"lon\":116.73498624001282,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20249129260376,\"lon\":116.73518976336872,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20247877796589,\"lon\":116.73537786253135,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20246651610268,\"lon\":116.73559239130266,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20245754388014,\"lon\":116.73574239922202,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20244749208,\"lon\":116.73589674090469,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20243806550113,\"lon\":116.73607057284322,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20243550556816,\"lon\":116.73628106525871,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20243654127756,\"lon\":116.7364949950665,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20243738221016,\"lon\":116.7367061649993,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20243672476754,\"lon\":116.73691115930336,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20243590788176,\"lon\":116.73710722104272,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202436434375336,\"lon\":116.73730688607075,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20243749821501,\"lon\":116.73750140347998,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20243625962803,\"lon\":116.73771330926793,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202434515480725,\"lon\":116.73791895606205,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.2024326561388,\"lon\":116.73815206945737,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20243092086137,\"lon\":116.73838655528765,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202430876006126,\"lon\":116.73861890759498,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20242914053177,\"lon\":116.73882029918758,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20242843336561,\"lon\":116.73904465495175,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20242661219026,\"lon\":116.73922453252953,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202426462811076,\"lon\":116.7393708046956,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20242687134937,\"lon\":116.73954685547025,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20242694967377,\"lon\":116.73975021183773,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202424630601236,\"lon\":116.73999740812975,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202422502184625,\"lon\":116.74028266774337,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202419634158936,\"lon\":116.7405942561498,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20241975959762,\"lon\":116.7409069557092,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20241920524113,\"lon\":116.74120156191647,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20241765540262,\"lon\":116.74149288504978,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20241569149764,\"lon\":116.7418080096762,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202414529497084,\"lon\":116.74210262897205,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20241419532155,\"lon\":116.74241767661879,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202413879360954,\"lon\":116.7427571218185,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20241287045245,\"lon\":116.7431284691325,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20241214965105,\"lon\":116.74343354359334,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20241141271715,\"lon\":116.7437220210538,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.2024080520075,\"lon\":116.74399113498052,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202391714280026,\"lon\":116.74427625698272,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20238163805639,\"lon\":116.74452083315958,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202379293010274,\"lon\":116.74475703837204,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202379007817086,\"lon\":116.7449961645494,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20237814181231,\"lon\":116.7452036063558,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202375477619896,\"lon\":116.74539567654291,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.2023632396621,\"lon\":116.74555457589031,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20229396554444,\"lon\":116.7456716047369,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20217800547467,\"lon\":116.74574081942625,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202047498095304,\"lon\":116.74573659255675,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20188573786706,\"lon\":116.74571018281719,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.201738240263026,\"lon\":116.74568463148606,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20157507049073,\"lon\":116.74565525041498,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20137985142042,\"lon\":116.745619970576,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.201187335613575,\"lon\":116.74558631350607,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20098251429043,\"lon\":116.74555055587679,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.2007748533628,\"lon\":116.74551426934663,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20057082986032,\"lon\":116.74547749663195,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20036944224329,\"lon\":116.74544156175533,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20016365229035,\"lon\":116.74540577510051,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.1999958572445,\"lon\":116.74537505807076,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19984100521566,\"lon\":116.7453433678602,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.1996863960282,\"lon\":116.74529675648621,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19953919567943,\"lon\":116.74525916493474,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19940587189373,\"lon\":116.74523402869453,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19929047792381,\"lon\":116.74518617038383,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19922141745155,\"lon\":116.74506912884067,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19920798885308,\"lon\":116.744896716334,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19920912644279,\"lon\":116.74467216715483,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199209186509314,\"lon\":116.74448257515108,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19920910709997,\"lon\":116.74430613406223,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.1992100786082,\"lon\":116.74410888316238,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19921081961254,\"lon\":116.74391968819582,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19921040855518,\"lon\":116.7437082083402,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19921085053439,\"lon\":116.74346931155634,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19921197237373,\"lon\":116.74325149697013,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19921248248983,\"lon\":116.74301103786591,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.1992139724646,\"lon\":116.74277237066539,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199215818352386,\"lon\":116.74253219408898,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199216175018876,\"lon\":116.74228853120842,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199215970354246,\"lon\":116.74204663206451,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199216627492966,\"lon\":116.74183871233049,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19921789170398,\"lon\":116.74165788334192,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19922000138535,\"lon\":116.74144512197054,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199221559127494,\"lon\":116.741249370491,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19922287231889,\"lon\":116.7410525810756,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19922229019589,\"lon\":116.74085266662037,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.1992216995901,\"lon\":116.74061957723823,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19922263073874,\"lon\":116.74041638149129,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19922478093337,\"lon\":116.7402123910757,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199227066091595,\"lon\":116.74003419421553,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199228634241756,\"lon\":116.73985841944678,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19922951636012,\"lon\":116.7397079274105,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199252095329484,\"lon\":116.73956265582487,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199346162997905,\"lon\":116.73944690416265,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199470799628024,\"lon\":116.73941941053417,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19962513314346,\"lon\":116.7394280706812,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199780626058924,\"lon\":116.73944255215424,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199961525343376,\"lon\":116.73945856750177,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20016196947193,\"lon\":116.73947572081121,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.200384479551936,\"lon\":116.7394949225795,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.200595083817475,\"lon\":116.73951027963179,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.200792203321086,\"lon\":116.73952526850614,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.200985930701684,\"lon\":116.73954125209579,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20115978977055,\"lon\":116.73955610094161,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.201321019536124,\"lon\":116.7395695239138,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20147117943043,\"lon\":116.7395823299481,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20163699848565,\"lon\":116.73959633422596,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20178484338371,\"lon\":116.7396085776486,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.201962185646316,\"lon\":116.73962351991214,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.2021018923927,\"lon\":116.7396354059821,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.2022137620686,\"lon\":116.73964348380458,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20232600820075,\"lon\":116.73961190446633,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20241090270993,\"lon\":116.73951649703137,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20245777783807,\"lon\":116.73937664238166,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20246906634823,\"lon\":116.73920146119093,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202470916682884,\"lon\":116.73898763065634,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20247034830421,\"lon\":116.73878158418357,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20246978204673,\"lon\":116.73857680142473,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20247082638905,\"lon\":116.73834517890637,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202471943178196,\"lon\":116.7381047689514,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20247131648035,\"lon\":116.73787761484981,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202470799473765,\"lon\":116.73766230702478,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20247013054322,\"lon\":116.73743619407796,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20246999515433,\"lon\":116.73724916823292,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20247199652478,\"lon\":116.73704888970806,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202473960263525,\"lon\":116.73684083235807,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202474504753205,\"lon\":116.73665462440796,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20247501354581,\"lon\":116.73650710371837,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20246541231906,\"lon\":116.73635807696789,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.202426768984274,\"lon\":116.73622283382787,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20236638788854,\"lon\":116.73610589402243,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20227106919894,\"lon\":116.73600895001849,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.2021428343084,\"lon\":116.73596816020945,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20197815580698,\"lon\":116.73594623645097,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20181789535303,\"lon\":116.73593148707488,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.201667906886954,\"lon\":116.73591743008926,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.201505897730755,\"lon\":116.7359002912543,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20135083580946,\"lon\":116.73588579696379,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20118617904595,\"lon\":116.73586970398149,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20102374028594,\"lon\":116.73585314703226,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20085554043743,\"lon\":116.73583763953049,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20069451888229,\"lon\":116.73582073901778,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.200530837344964,\"lon\":116.73580314359012,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.2003608457064,\"lon\":116.73578183888779,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20021770046798,\"lon\":116.73575292592922,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.20003454701824,\"lon\":116.7357174959358,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19986125116602,\"lon\":116.73569499961796,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19969408518737,\"lon\":116.73567725223492,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19955533048882,\"lon\":116.73566375985422,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19943174810538,\"lon\":116.73564927714162,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19933167546824,\"lon\":116.735595995086,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.199280357603875,\"lon\":116.73546293260645,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19927848361656,\"lon\":116.73531579486274,\"speed\":0.0},{\"altitude\":0.0,\"angle\":0.0,\"duration\":0,\"lat\":40.19928127892504,\"lon\":116.73505848474375,\"speed\": 0.0\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+ public static void converToRouteData(){
+ List list = new ArrayList<>();
+
+ try {
+ JSONObject jsonObject = new JSONObject(jsonStr);
+ JSONArray jsonElements = jsonObject.getJSONArray("models");
+ for (int i = 0; i < jsonElements.length(); i++) {
+ JSONObject s = jsonElements.getJSONObject(i);
+ MessagePad.Location.Builder builder = MessagePad.Location.newBuilder();
+ builder.setLatitude(s.getDouble("lat"));
+ builder.setLongitude(s.getDouble("lon"));
+ list.add(builder.build());
+ }
+ SweeperOrderModel.getInstance().debugUpdateOrderRoute(list);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/util/SweeperAnalyticsManager.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/util/SweeperAnalyticsManager.java
new file mode 100644
index 0000000000..76f43e4388
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/util/SweeperAnalyticsManager.java
@@ -0,0 +1,81 @@
+package com.mogo.och.sweeper.util;
+
+import android.text.TextUtils;
+
+import com.mogo.cloud.passport.MoGoAiCloudClientConfig;
+import com.mogo.commons.debug.DebugConfig;
+import com.mogo.eagle.core.data.app.AppConfigInfo;
+import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener;
+import com.mogo.eagle.core.function.call.analytics.AnalyticsManager;
+import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager;
+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内未开启,上报失败埋点
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_RESULT
+ , CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState() ==
+ IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING);
+ AnalyticsManager.INSTANCE.track(mStartAutopilotKey, mStartAutopilotParams);
+ };
+
+ /**
+ * 触发'开启自动驾驶'埋点流程
+ * 开启自动驾驶,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 (startAutopilotRunnable != null &&
+ UiThreadHandler.getsUiHandler().hasCallbacks(startAutopilotRunnable)) {
+ UiThreadHandler.removeCallbacks(startAutopilotRunnable);
+ }
+ mStartAutopilotParams.put(SweeperConst.EVENT_PARAM_START_RESULT, true);
+ AnalyticsManager.INSTANCE.track(mStartAutopilotKey, mStartAutopilotParams);
+ } else {
+ UiThreadHandler.postDelayed(startAutopilotRunnable, SweeperConst.LOOP_PERIOD_15S);
+ }
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/util/SweeperFutianCmdUtil.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/util/SweeperFutianCmdUtil.java
new file mode 100644
index 0000000000..969b0dbc34
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/util/SweeperFutianCmdUtil.java
@@ -0,0 +1,148 @@
+package com.mogo.och.sweeper.util;
+
+import chassis.SpecialVehicleTaskCmdOuterClass;
+import chassis.VehicleStateOuterClass;
+
+/**
+ * 清扫车-福田,构建业务命令数据的工具类
+ */
+public class SweeperFutianCmdUtil {
+ private static final int CLEAN_WORK_OPEN = 1; //清扫作业-开启
+ private 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;//作业模式-纯吸
+ private 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;//清扫方向-右侧
+ private 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();
+ }
+
+ /**
+ * 构建底盘Mock数据
+ *
+ * @return
+ */
+ public static VehicleStateOuterClass.SweeperFuTianCleanSystemState buildSweeperFuTionCleanSystemStateMockData() {
+ VehicleStateOuterClass.SweeperFuTianCleanSystemState.Builder builder = VehicleStateOuterClass.SweeperFuTianCleanSystemState.newBuilder();
+ builder.setSecuMotWorkSts(true);
+ builder.setSecuModWashSts(true);
+ builder.setSecuWorkOnBothsidesSts(true);
+ builder.setSecuWorkStrongSts(true);
+ return builder.build();
+ }
+
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/util/SweeperTrajectoryManager.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/util/SweeperTrajectoryManager.java
new file mode 100644
index 0000000000..8f054bf16a
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/util/SweeperTrajectoryManager.java
@@ -0,0 +1,204 @@
+package com.mogo.och.sweeper.util;
+
+import androidx.annotation.Nullable;
+
+import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters;
+import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotManager;
+import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
+import com.mogo.eagle.core.utilcode.util.GsonUtils;
+import com.mogo.och.sweeper.bean.SweeperRoutesResult;
+import com.mogo.och.sweeper.constant.SweeperConst;
+import com.mogo.och.sweeper.model.SweeperOrderModel;
+
+import java.util.concurrent.TimeUnit;
+
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+import mogo_msg.MogoReportMsg;
+
+import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS;
+
+/**
+ * Bus轨迹管理:给MEC下发用于轨迹下载的信息
+ * Created on 2022/6/23
+ */
+public class 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() {
+ SweeperRoutesResult routesResult = SweeperOrderModel.getInstance().getBusRoutesResult();
+ if (SweeperOrderModel.getInstance().isWorking() && routesResult != null
+ && SweeperOrderModel.getInstance().getCurrentStationIndex() == 0
+ && !SweeperOrderModel.getInstance().isGoingToNextStation()) {
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "syncTrajectoryInfo() start.");
+ startTrajReqLoop();
+ } else {
+ // 无路线信息or当前未在始发站
+ CallerLogger.INSTANCE.d(M_BUS + 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_BUS + TAG, "onAutopilotGuardian() 轨迹开始下载");
+ // ToastUtils.showShort("轨迹开始下载");
+ stopTrajReqLoop();
+ } else if ("ISYS_INIT_TRAJECTORY_SUCCESS".equals(guardianInfo.getCode())) {
+ // 2. 轨迹管理_轨迹下载成功(本地已有对应轨迹也触发)
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "onAutopilotGuardian() 轨迹下载成功");
+ // ToastUtils.showShort("轨迹下载成功");
+ stopTrajReqLoop();
+ } else if ("ISYS_INIT_TRAJECTORY_FAILURE".equals(guardianInfo.getCode())) {
+ // 3. 轨迹管理_轨迹下载失败,本地无对应轨迹
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "onAutopilotGuardian() " +
+ "轨迹下载失败,本地无对应轨迹");
+ // ToastUtils.showShort("轨迹下载失败,本地无对应轨迹");
+ } else if ("ISYS_INIT_TRAJECTORY_WARNING".equals(guardianInfo.getCode())) {
+ // 4. 轨迹管理_轨迹下载失败,本地有对应轨迹,认为成功
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "onAutopilotGuardian() " +
+ "轨迹下载失败,本地有对应轨迹,认为成功");
+ // ToastUtils.showShort("轨迹下载失败,本地有对应轨迹,认为成功");
+ } else if ("ISYS_INIT_TRAJECTORY_TIMEOUT".equals(guardianInfo.getCode())) {
+ // 5. 轨迹管理_轨迹下载超时
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "onAutopilotGuardian() 轨迹下载超时");
+ // ToastUtils.showShort("轨迹下载超时");
+ }
+ }
+
+ private void setupAutoPilotLine() {
+ SweeperRoutesResult routesResult = SweeperOrderModel.getInstance().getBusRoutesResult();
+ if (routesResult == null) {
+ CallerLogger.INSTANCE.e(M_BUS + TAG,
+ "setupAutoPilotLine(): routesResult is null.");
+ return;
+ } else {
+ if (mAutoPilotLine == null) {
+ mAutoPilotLine = new AutopilotControlParameters.AutoPilotLine(routesResult.getLineId(),
+ routesResult.csvFileUrl, routesResult.csvFileMd5,
+ routesResult.txtFileUrl, routesResult.txtFileMd5,
+ routesResult.contrailSaveTime, routesResult.carModel,
+ routesResult.csvFileUrlDPQP, routesResult.csvFileMd5DPQP,
+ routesResult.txtFileUrlDPQP, routesResult.txtFileMd5DPQP,
+ routesResult.contrailSaveTimeDPQP);
+ } else {
+ mAutoPilotLine.setLineId(routesResult.getLineId());
+ mAutoPilotLine.setTrajUrl(routesResult.csvFileUrl);
+ mAutoPilotLine.setTrajMd5(routesResult.csvFileMd5);
+ mAutoPilotLine.setStopUrl(routesResult.txtFileUrl);
+ mAutoPilotLine.setStopMd5(routesResult.txtFileMd5);
+ mAutoPilotLine.setTimestamp(routesResult.contrailSaveTime);
+ mAutoPilotLine.setVehicleModel(routesResult.carModel);
+ mAutoPilotLine.setTrajUrl_dpqp(routesResult.csvFileUrlDPQP);
+ mAutoPilotLine.setTrajMd5_dpqp(routesResult.csvFileMd5DPQP);
+ mAutoPilotLine.setStopUrl_dpqp(routesResult.txtFileUrlDPQP);
+ mAutoPilotLine.setStopMd5_dpqp(routesResult.txtFileMd5DPQP);
+ mAutoPilotLine.setTimestamp_dpqp(routesResult.contrailSaveTimeDPQP);
+ }
+ }
+ }
+
+ private void clearAutoPilotLine() {
+ if (mAutoPilotLine == null) return;
+ mAutoPilotLine.setLineId(-1);
+ mAutoPilotLine.setTrajUrl("");
+ mAutoPilotLine.setTrajMd5("");
+ mAutoPilotLine.setStopUrl("");
+ mAutoPilotLine.setStopMd5("");
+ mAutoPilotLine.setTimestamp(0);
+ mAutoPilotLine.setVehicleModel("");
+ mAutoPilotLine.setTrajUrl_dpqp("");
+ mAutoPilotLine.setTrajMd5_dpqp("");
+ mAutoPilotLine.setStopUrl_dpqp("");
+ mAutoPilotLine.setStopMd5_dpqp("");
+ mAutoPilotLine.setTimestamp_dpqp(0);
+ }
+
+ private void startTrajReqLoop() {
+ if (mSendReqDisposable != null && !mSendReqDisposable.isDisposed()) {
+ return;
+ }
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "startTrajReqLoop()");
+ setupAutoPilotLine();
+ 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_BUS + TAG, "loop sendTrajectoryReq: " + aLong);
+ sendTrajectoryReq();
+ });
+ }
+
+ public void stopTrajReqLoop() {
+ if (mSendReqDisposable != null) {
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "stopTrajReqLoop()");
+ mSendReqDisposable.dispose();
+ mSendReqDisposable = null;
+ clearAutoPilotLine();
+ }
+ }
+
+ private void sendTrajectoryReq() {
+ if (mAutoPilotLine == null) {
+ CallerLogger.INSTANCE.e(M_BUS + 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");
+
+ CallerAutoPilotManager.INSTANCE.sendTrajectoryDownloadReq(mAutoPilotLine);
+ CallerLogger.INSTANCE.d(M_BUS + TAG, "sendTrajectoryReq(): "
+ + GsonUtils.toJson(mAutoPilotLine));
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/view/BusArcView.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/view/BusArcView.java
new file mode 100644
index 0000000000..d559214b15
--- /dev/null
+++ b/OCH/mogo-och-sweeper/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/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/view/NoTouchConstraintLayout.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/view/NoTouchConstraintLayout.java
new file mode 100644
index 0000000000..6922b9596f
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/view/NoTouchConstraintLayout.java
@@ -0,0 +1,37 @@
+package com.mogo.och.sweeper.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.mogo.commons.debug.DebugConfig;
+
+/**
+ * 强制拦截所有touch时间的约束布局
+ *
+ * @author tongchenfei
+ */
+public class NoTouchConstraintLayout extends ConstraintLayout {
+ 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(DebugConfig.isDebug()){
+ return super.onInterceptTouchEvent(ev);
+ }else {
+ return true;
+ }
+ }
+}
diff --git a/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/view/SlidePanelView.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/view/SlidePanelView.java
new file mode 100644
index 0000000000..f7171bce89
--- /dev/null
+++ b/OCH/mogo-och-sweeper/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/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/view/VerticalDashLineView.java b/OCH/mogo-och-sweeper/src/main/java/com/mogo/och/sweeper/view/VerticalDashLineView.java
new file mode 100644
index 0000000000..875722ea11
--- /dev/null
+++ b/OCH/mogo-och-sweeper/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/mogo-och-sweeper/src/main/res/color/sweeper_autopilot_text_color_selector.xml b/OCH/mogo-och-sweeper/src/main/res/color/sweeper_autopilot_text_color_selector.xml
new file mode 100644
index 0000000000..afd0b1f78c
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/color/sweeper_autopilot_text_color_selector.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/end_maker_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/end_maker_icon.png
new file mode 100755
index 0000000000..8acf113151
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/end_maker_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_ai_normal.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_ai_normal.png
new file mode 100755
index 0000000000..e98738b192
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_ai_normal.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_ai_select.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_ai_select.png
new file mode 100755
index 0000000000..d3e0107c02
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_ai_select.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_bad_case_normal.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_bad_case_normal.png
new file mode 100755
index 0000000000..c0a978fc2b
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_bad_case_normal.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_bad_case_select.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_bad_case_select.png
new file mode 100755
index 0000000000..ebacf3a11a
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_bad_case_select.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_station_start_end.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_station_start_end.png
new file mode 100644
index 0000000000..04580a8f0d
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/icon_station_start_end.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/press_start_status.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/press_start_status.png
new file mode 100755
index 0000000000..af32c20cb5
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/press_start_status.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/start_failure.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/start_failure.png
new file mode 100755
index 0000000000..5737f93ad8
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/start_failure.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/start_maker_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/start_maker_icon.png
new file mode 100644
index 0000000000..9eca61e199
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/start_maker_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/start_success.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/start_success.png
new file mode 100755
index 0000000000..84246fd323
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/start_success.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_base_icon_not_in_autopilot.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_base_icon_not_in_autopilot.png
new file mode 100644
index 0000000000..927296d690
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_base_icon_not_in_autopilot.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_base_slide_block.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_base_slide_block.png
new file mode 100644
index 0000000000..ed7b293b90
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_base_slide_block.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_disable_autopilot_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_disable_autopilot_icon.png
new file mode 100644
index 0000000000..170f254cd1
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_disable_autopilot_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_icon_arrived_station.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_icon_arrived_station.png
new file mode 100644
index 0000000000..8a065b66dd
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_icon_arrived_station.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_icon_arriving_station.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_icon_arriving_station.png
new file mode 100644
index 0000000000..4ed57a0e30
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_icon_arriving_station.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_light_green_nor.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_light_green_nor.png
new file mode 100644
index 0000000000..bc9fed952d
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_light_green_nor.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_light_red_nor.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_light_red_nor.png
new file mode 100644
index 0000000000..8732508ded
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_light_red_nor.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_lightyellow_nor.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_lightyellow_nor.png
new file mode 100644
index 0000000000..bae01408fd
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_lightyellow_nor.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_line_panel_bg.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_line_panel_bg.png
new file mode 100755
index 0000000000..3166d20e37
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_line_panel_bg.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_line_panel_bg_1.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_line_panel_bg_1.png
new file mode 100755
index 0000000000..09a9c252da
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_line_panel_bg_1.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_loading_autopilot_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_loading_autopilot_icon.png
new file mode 100644
index 0000000000..f21a1081f1
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_loading_autopilot_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_och_dot_line.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_och_dot_line.png
new file mode 100644
index 0000000000..a720a532ea
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_och_dot_line.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_right_autopilot_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_right_autopilot_icon.png
new file mode 100644
index 0000000000..cc2b18083d
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_right_autopilot_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_selected_btn.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_selected_btn.png
new file mode 100644
index 0000000000..3f05565483
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_selected_btn.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_setting_btn_bg.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_setting_btn_bg.png
new file mode 100644
index 0000000000..ba41bf3a53
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_setting_btn_bg.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_switch_line_close.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_switch_line_close.png
new file mode 100644
index 0000000000..370b61de38
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_switch_line_close.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_switch_map_long.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_switch_map_long.png
new file mode 100755
index 0000000000..cf3e5a3778
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_switch_map_long.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_switch_map_medium.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_switch_map_medium.png
new file mode 100755
index 0000000000..bdc2725468
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_switch_map_medium.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_unselect_btn.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_unselect_btn.png
new file mode 100644
index 0000000000..0114bb4f2b
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_unselect_btn.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_wrong_autopilot_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_wrong_autopilot_icon.png
new file mode 100644
index 0000000000..0c8988acb3
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1440/sweeper_wrong_autopilot_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/end_maker_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/end_maker_icon.png
new file mode 100755
index 0000000000..8acf113151
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/end_maker_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_ai_normal.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_ai_normal.png
new file mode 100755
index 0000000000..e98738b192
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_ai_normal.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_ai_select.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_ai_select.png
new file mode 100755
index 0000000000..d3e0107c02
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_ai_select.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_bad_case_normal.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_bad_case_normal.png
new file mode 100755
index 0000000000..c0a978fc2b
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_bad_case_normal.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_bad_case_select.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_bad_case_select.png
new file mode 100755
index 0000000000..ebacf3a11a
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_bad_case_select.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_station_start_end.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_station_start_end.png
new file mode 100644
index 0000000000..04580a8f0d
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/icon_station_start_end.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/press_start_status.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/press_start_status.png
new file mode 100755
index 0000000000..af32c20cb5
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/press_start_status.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/start_failure.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/start_failure.png
new file mode 100755
index 0000000000..5737f93ad8
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/start_failure.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/start_maker_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/start_maker_icon.png
new file mode 100644
index 0000000000..9eca61e199
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/start_maker_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/start_success.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/start_success.png
new file mode 100755
index 0000000000..84246fd323
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/start_success.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_base_icon_not_in_autopilot.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_base_icon_not_in_autopilot.png
new file mode 100644
index 0000000000..927296d690
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_base_icon_not_in_autopilot.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_base_slide_block.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_base_slide_block.png
new file mode 100644
index 0000000000..ed7b293b90
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_base_slide_block.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_disable_autopilot_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_disable_autopilot_icon.png
new file mode 100644
index 0000000000..170f254cd1
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_disable_autopilot_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_icon_arrived_station.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_icon_arrived_station.png
new file mode 100644
index 0000000000..8a065b66dd
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_icon_arrived_station.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_icon_arriving_station.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_icon_arriving_station.png
new file mode 100644
index 0000000000..4ed57a0e30
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_icon_arriving_station.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_light_green_nor.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_light_green_nor.png
new file mode 100644
index 0000000000..bc9fed952d
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_light_green_nor.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_light_red_nor.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_light_red_nor.png
new file mode 100644
index 0000000000..8732508ded
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_light_red_nor.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_lightyellow_nor.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_lightyellow_nor.png
new file mode 100644
index 0000000000..bae01408fd
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_lightyellow_nor.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_line_panel_bg.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_line_panel_bg.png
new file mode 100755
index 0000000000..3166d20e37
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_line_panel_bg.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_line_panel_bg_1.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_line_panel_bg_1.png
new file mode 100755
index 0000000000..09a9c252da
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_line_panel_bg_1.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_loading_autopilot_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_loading_autopilot_icon.png
new file mode 100644
index 0000000000..f21a1081f1
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_loading_autopilot_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_och_dot_line.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_och_dot_line.png
new file mode 100644
index 0000000000..a720a532ea
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_och_dot_line.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_right_autopilot_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_right_autopilot_icon.png
new file mode 100644
index 0000000000..cc2b18083d
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_right_autopilot_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_selected_btn.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_selected_btn.png
new file mode 100644
index 0000000000..3f05565483
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_selected_btn.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_setting_btn_bg.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_setting_btn_bg.png
new file mode 100644
index 0000000000..ba41bf3a53
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_setting_btn_bg.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_switch_line_close.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_switch_line_close.png
new file mode 100644
index 0000000000..370b61de38
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_switch_line_close.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_switch_map_long.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_switch_map_long.png
new file mode 100755
index 0000000000..cf3e5a3778
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_switch_map_long.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_switch_map_medium.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_switch_map_medium.png
new file mode 100755
index 0000000000..bdc2725468
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_switch_map_medium.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_unselect_btn.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_unselect_btn.png
new file mode 100644
index 0000000000..0114bb4f2b
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_unselect_btn.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_wrong_autopilot_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_wrong_autopilot_icon.png
new file mode 100644
index 0000000000..0c8988acb3
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi-2560x1600/sweeper_wrong_autopilot_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/end_maker_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/end_maker_icon.png
new file mode 100755
index 0000000000..8acf113151
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/end_maker_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_ai_normal.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_ai_normal.png
new file mode 100755
index 0000000000..e98738b192
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_ai_normal.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_ai_select.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_ai_select.png
new file mode 100755
index 0000000000..d3e0107c02
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_ai_select.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_bad_case_normal.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_bad_case_normal.png
new file mode 100755
index 0000000000..c0a978fc2b
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_bad_case_normal.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_bad_case_select.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_bad_case_select.png
new file mode 100755
index 0000000000..ebacf3a11a
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_bad_case_select.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_station_start_end.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_station_start_end.png
new file mode 100644
index 0000000000..04580a8f0d
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/icon_station_start_end.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/img_sweeper_status_bg.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/img_sweeper_status_bg.png
new file mode 100644
index 0000000000..27cb9285d3
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/img_sweeper_status_bg.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/no_order_data.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/no_order_data.png
new file mode 100644
index 0000000000..0e61996d3f
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/no_order_data.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/press_start_status.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/press_start_status.png
new file mode 100755
index 0000000000..af32c20cb5
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/press_start_status.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/start_failure.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/start_failure.png
new file mode 100755
index 0000000000..5737f93ad8
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/start_failure.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/start_maker_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/start_maker_icon.png
new file mode 100644
index 0000000000..9eca61e199
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/start_maker_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/start_success.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/start_success.png
new file mode 100755
index 0000000000..84246fd323
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/start_success.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_icon_in_autopilot.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_icon_in_autopilot.png
new file mode 100644
index 0000000000..75c26c3d71
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_icon_in_autopilot.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_icon_not_in_autopilot.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_icon_not_in_autopilot.png
new file mode 100644
index 0000000000..927296d690
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_icon_not_in_autopilot.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_notice_box_bg.9.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_notice_box_bg.9.png
new file mode 100644
index 0000000000..8b4b579b56
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_notice_box_bg.9.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_slide_block.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_slide_block.png
new file mode 100644
index 0000000000..ed7b293b90
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_base_slide_block.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_disable_autopilot_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_disable_autopilot_icon.png
new file mode 100644
index 0000000000..170f254cd1
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_disable_autopilot_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_dot_line.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_dot_line.png
new file mode 100644
index 0000000000..186001352c
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_dot_line.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_ic_autopilot.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_ic_autopilot.png
new file mode 100644
index 0000000000..be978145dc
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_ic_autopilot.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_arrived_station.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_arrived_station.png
new file mode 100644
index 0000000000..8a065b66dd
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_arrived_station.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_arriving_station.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_arriving_station.png
new file mode 100644
index 0000000000..4ed57a0e30
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_arriving_station.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_not_arrive_station.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_not_arrive_station.png
new file mode 100644
index 0000000000..e0bb24c526
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_icon_not_arrive_station.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_light_green_nor.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_light_green_nor.png
new file mode 100644
index 0000000000..bc9fed952d
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_light_green_nor.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_light_red_nor.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_light_red_nor.png
new file mode 100644
index 0000000000..8732508ded
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_light_red_nor.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_lightyellow_nor.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_lightyellow_nor.png
new file mode 100644
index 0000000000..bae01408fd
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_lightyellow_nor.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_line_panel_bg.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_line_panel_bg.png
new file mode 100755
index 0000000000..3166d20e37
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_line_panel_bg.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_line_panel_bg_1.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_line_panel_bg_1.png
new file mode 100755
index 0000000000..09a9c252da
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_line_panel_bg_1.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_loading_autopilot_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_loading_autopilot_icon.png
new file mode 100644
index 0000000000..f21a1081f1
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_loading_autopilot_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_och_dot_line.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_och_dot_line.png
new file mode 100644
index 0000000000..a720a532ea
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_och_dot_line.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_right_autopilot_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_right_autopilot_icon.png
new file mode 100644
index 0000000000..cc2b18083d
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_right_autopilot_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_selected_btn.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_selected_btn.png
new file mode 100644
index 0000000000..3f05565483
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_selected_btn.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_setting_btn_bg.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_setting_btn_bg.png
new file mode 100644
index 0000000000..ba41bf3a53
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_setting_btn_bg.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_line_close.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_line_close.png
new file mode 100644
index 0000000000..370b61de38
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_line_close.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_long.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_long.png
new file mode 100755
index 0000000000..cf3e5a3778
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_long.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_medium.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_medium.png
new file mode 100644
index 0000000000..bdc2725468
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_switch_map_medium.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_unselect_btn.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_unselect_btn.png
new file mode 100644
index 0000000000..0114bb4f2b
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_unselect_btn.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_wrong_autopilot_icon.png b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_wrong_autopilot_icon.png
new file mode 100644
index 0000000000..0c8988acb3
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable-xhdpi/sweeper_wrong_autopilot_icon.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/ai_collect_selector.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/ai_collect_selector.xml
new file mode 100755
index 0000000000..a1211f3c47
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/ai_collect_selector.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bad_case_selector.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/bad_case_selector.xml
new file mode 100755
index 0000000000..bc47ce95d7
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/bad_case_selector.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel.xml
new file mode 100644
index 0000000000..c9f7378baa
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_close.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_close.xml
new file mode 100644
index 0000000000..8455e0cafb
--- /dev/null
+++ b/OCH/mogo-och-sweeper/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/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_default.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_default.xml
new file mode 100644
index 0000000000..84464f5307
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_default.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_disabled.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_disabled.xml
new file mode 100644
index 0000000000..a5cb095bc8
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_disabled.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_open.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_open.xml
new file mode 100644
index 0000000000..ec0eeb317b
--- /dev/null
+++ b/OCH/mogo-och-sweeper/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/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_pressed.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_pressed.xml
new file mode 100644
index 0000000000..8d7970361a
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_operate_panel_btn_pressed.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_traffic_light_background.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_traffic_light_background.xml
new file mode 100644
index 0000000000..a74b1ff75f
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/bg_sweeper_traffic_light_background.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/img_sweeper_status_bg.9.png b/OCH/mogo-och-sweeper/src/main/res/drawable/img_sweeper_status_bg.9.png
new file mode 100644
index 0000000000..0af2b9db73
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable/img_sweeper_status_bg.9.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_autopilot_status_bg.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_autopilot_status_bg.xml
new file mode 100644
index 0000000000..ad57da1c3a
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_autopilot_status_bg.xml
@@ -0,0 +1,17 @@
+
+
+ -
+
+
+ -
+
+ -
+
+ -
+
+ -
+
+ -
+
+
+
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_autopilot_status_bg_check.png b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_autopilot_status_bg_check.png
new file mode 100644
index 0000000000..28857974b5
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_autopilot_status_bg_check.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_autopilot_status_bg_nor.png b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_autopilot_status_bg_nor.png
new file mode 100644
index 0000000000..f7d4f92c4b
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_autopilot_status_bg_nor.png differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_base_autopilot_status_icon_selector.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_base_autopilot_status_icon_selector.xml
new file mode 100644
index 0000000000..6b646eac98
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_base_autopilot_status_icon_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_checkbox_selector.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_checkbox_selector.xml
new file mode 100644
index 0000000000..191827e786
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_checkbox_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_line_dividing_line1_selector.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_line_dividing_line1_selector.xml
new file mode 100644
index 0000000000..b00fbd8bd6
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_line_dividing_line1_selector.xml
@@ -0,0 +1,8 @@
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_line_dividing_line2_selector.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_line_dividing_line2_selector.xml
new file mode 100644
index 0000000000..ee555aae15
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_line_dividing_line2_selector.xml
@@ -0,0 +1,8 @@
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operate_panel_btn1_bg_selector.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operate_panel_btn1_bg_selector.xml
new file mode 100644
index 0000000000..ba7719ba91
--- /dev/null
+++ b/OCH/mogo-och-sweeper/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/mogo-och-sweeper/src/main/res/drawable/sweeper_operate_panel_btn2_bg_selector.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operate_panel_btn2_bg_selector.xml
new file mode 100755
index 0000000000..c51538216c
--- /dev/null
+++ b/OCH/mogo-och-sweeper/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/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_bg.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_bg.xml
new file mode 100644
index 0000000000..753d85e3ec
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_bg.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_bg_selector.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_bg_selector.xml
new file mode 100755
index 0000000000..996c623455
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_bg_selector.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_select_bg.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_select_bg.xml
new file mode 100644
index 0000000000..835c1fbaff
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_operation_status_select_bg.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_panel_anchor_bkg.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_panel_anchor_bkg.xml
new file mode 100644
index 0000000000..38fc28d893
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_panel_anchor_bkg.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_panel_bkg.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_panel_bkg.xml
new file mode 100644
index 0000000000..d7937835a0
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_panel_bkg.xml
@@ -0,0 +1,19 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_setting_tip_red_cir_bg.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_setting_tip_red_cir_bg.xml
new file mode 100644
index 0000000000..0f456d52c7
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_setting_tip_red_cir_bg.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_station_green_dash_line.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_station_green_dash_line.xml
new file mode 100644
index 0000000000..d1fbaeb3b9
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_station_green_dash_line.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_station_v_green_dash.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_station_v_green_dash.xml
new file mode 100644
index 0000000000..f43c213363
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_station_v_green_dash.xml
@@ -0,0 +1,11 @@
+
+
+ -
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_line_btn.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_line_btn.xml
new file mode 100644
index 0000000000..be0bd24850
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_line_btn.xml
@@ -0,0 +1,11 @@
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_line_btn_commit.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_line_btn_commit.xml
new file mode 100644
index 0000000000..324b9ece10
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_line_btn_commit.xml
@@ -0,0 +1,16 @@
+
+
+ -
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_line_btn_un_commit.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_line_btn_un_commit.xml
new file mode 100644
index 0000000000..d0ea7fa041
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_line_btn_un_commit.xml
@@ -0,0 +1,16 @@
+
+
+ -
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_map_bg.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_map_bg.xml
new file mode 100644
index 0000000000..943ebcac05
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_switch_map_bg.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_yi_biao_pan_bg_nor.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_yi_biao_pan_bg_nor.xml
new file mode 100644
index 0000000000..4bde0e73c1
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_yi_biao_pan_bg_nor.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_yi_biao_pan_bg_speeding.xml b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_yi_biao_pan_bg_speeding.xml
new file mode 100644
index 0000000000..dea7a88bb6
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/drawable/sweeper_yi_biao_pan_bg_speeding.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/layout/activity_sweeper_switch_line.xml b/OCH/mogo-och-sweeper/src/main/res/layout/activity_sweeper_switch_line.xml
new file mode 100644
index 0000000000..83f6208652
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/layout/activity_sweeper_switch_line.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/layout/fragment_och_sweeper.xml b/OCH/mogo-och-sweeper/src/main/res/layout/fragment_och_sweeper.xml
new file mode 100644
index 0000000000..31e2ba482f
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/layout/fragment_och_sweeper.xml
@@ -0,0 +1,176 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/layout/item_och_sweeper_station.xml b/OCH/mogo-och-sweeper/src/main/res/layout/item_och_sweeper_station.xml
new file mode 100644
index 0000000000..ddcc6f38d7
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/layout/item_och_sweeper_station.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_base_fragment.xml b/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_base_fragment.xml
new file mode 100644
index 0000000000..3329a05a39
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_base_fragment.xml
@@ -0,0 +1,254 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_no_data_common_view.xml b/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_no_data_common_view.xml
new file mode 100644
index 0000000000..823a1bf7e2
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_no_data_common_view.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_operate_panel_view.xml b/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_operate_panel_view.xml
new file mode 100644
index 0000000000..790a01dffa
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_operate_panel_view.xml
@@ -0,0 +1,310 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_switch_line_list_item.xml b/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_switch_line_list_item.xml
new file mode 100644
index 0000000000..0474a2543d
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_switch_line_list_item.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_test_bar_view.xml b/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_test_bar_view.xml
new file mode 100644
index 0000000000..4322fdf328
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_test_bar_view.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_traffic_light_view.xml b/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_traffic_light_view.xml
new file mode 100644
index 0000000000..947eb46197
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/layout/sweeper_traffic_light_view.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/raw/end_marker.nt3d b/OCH/mogo-och-sweeper/src/main/res/raw/end_marker.nt3d
new file mode 100644
index 0000000000..be6057c547
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/raw/end_marker.nt3d differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/raw/star_marker.nt3d b/OCH/mogo-och-sweeper/src/main/res/raw/star_marker.nt3d
new file mode 100644
index 0000000000..c6e546fc31
Binary files /dev/null and b/OCH/mogo-och-sweeper/src/main/res/raw/star_marker.nt3d differ
diff --git a/OCH/mogo-och-sweeper/src/main/res/raw/sweeper_away_passengers.json b/OCH/mogo-och-sweeper/src/main/res/raw/sweeper_away_passengers.json
new file mode 100644
index 0000000000..e76436f2dc
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/raw/sweeper_away_passengers.json
@@ -0,0 +1,184 @@
+{
+ "code": 0,
+ "msg": "",
+ "detailMsg": "",
+ "result": {
+ "info": [
+ {
+ "_id": "cee57b3ae07c4486b0357319368487d7",
+ "orderNo": "XB20210422000002",
+ "orderType": 10,
+ "userName": "董QAD",
+ "userPhone": "15631204018",
+ "startStationId": 1,
+ "startStation": "万集东门站",
+ "startStationCoordinate": [
+ 116.7354579447,
+ 40.1974932972
+ ],
+ "endStationId": 2,
+ "endStation": "顺密路口站",
+ "endStationCoordinate": [
+ 116.721520973,
+ 40.1940181096
+ ],
+ "orderDispatchType": 7,
+ "carNum": "京NB010",
+ "sn": "F803EB2046PZD00149",
+ "orderStartTime": "2021-04-22 16:31:58",
+ "orderEndTime": "2021-04-26 10:38:13",
+ "arrivedStartStationTime": null,
+ "arrivedEndStationTime": null,
+ "cityCode": "010",
+ "areaCode": "1001",
+ "createTime": "2021-04-22 16:31:58",
+ "updateTime": "2021-04-26 10:38:13",
+ "personNum": 1,
+ "travelDistance": 1.2,
+ "vehicleColour": null,
+ "lastBrandName": null,
+ "headImgUrl": null
+ },
+ {
+ "_id": "ce69b1bcfb9840c6a4563bc6ef947caf",
+ "orderNo": "XB20210426000000",
+ "orderType": 10,
+ "userName": "董QAD",
+ "userPhone": "15631204018",
+ "startStationId": 1,
+ "startStation": "万集东门站",
+ "startStationCoordinate": [
+ 116.7354579447,
+ 40.1974932972
+ ],
+ "endStationId": 2,
+ "endStation": "顺密路口站",
+ "endStationCoordinate": [
+ 116.721520973,
+ 40.1940181096
+ ],
+ "orderDispatchType": 7,
+ "carNum": "京NB010",
+ "sn": "F803EB2046PZD00149",
+ "orderStartTime": "2021-04-26 10:38:48",
+ "orderEndTime": "2021-04-26 10:46:16",
+ "arrivedStartStationTime": null,
+ "arrivedEndStationTime": null,
+ "cityCode": "010",
+ "areaCode": "1001",
+ "createTime": "2021-04-26 10:38:48",
+ "updateTime": "2021-04-26 10:46:16",
+ "personNum": 1,
+ "travelDistance": 1.2,
+ "vehicleColour": null,
+ "lastBrandName": null,
+ "headImgUrl": null
+ },
+ {
+ "_id": "cae07b56f41c4e0fa60ab3543ffc258e",
+ "orderNo": "XB20210426000001",
+ "orderType": 10,
+ "userName": "董QAD",
+ "userPhone": "15631204018",
+ "startStationId": 1,
+ "startStation": "万集东门站",
+ "startStationCoordinate": [
+ 116.7354579447,
+ 40.1974932972
+ ],
+ "endStationId": 2,
+ "endStation": "顺密路口站",
+ "endStationCoordinate": [
+ 116.721520973,
+ 40.1940181096
+ ],
+ "orderDispatchType": 7,
+ "carNum": "京NB010",
+ "sn": "F803EB2046PZD00149",
+ "orderStartTime": "2021-04-26 10:47:05",
+ "orderEndTime": "2021-04-26 10:48:07",
+ "arrivedStartStationTime": null,
+ "arrivedEndStationTime": null,
+ "cityCode": "010",
+ "areaCode": "1001",
+ "createTime": "2021-04-26 10:47:05",
+ "updateTime": "2021-04-26 10:48:07",
+ "personNum": 1,
+ "travelDistance": 1.2,
+ "vehicleColour": null,
+ "lastBrandName": null,
+ "headImgUrl": null
+ },
+ {
+ "_id": "62bc84afbc434d01b644c74ee406e772",
+ "orderNo": "XB20210426000002",
+ "orderType": 10,
+ "userName": "董QAD",
+ "userPhone": "15631204018",
+ "startStationId": 1,
+ "startStation": "万集东门站",
+ "startStationCoordinate": [
+ 116.7354579447,
+ 40.1974932972
+ ],
+ "endStationId": 2,
+ "endStation": "顺密路口站",
+ "endStationCoordinate": [
+ 116.721520973,
+ 40.1940181096
+ ],
+ "orderDispatchType": 7,
+ "carNum": "京NB010",
+ "sn": "F803EB2046PZD00149",
+ "orderStartTime": "2021-04-26 10:48:22",
+ "orderEndTime": "2021-04-26 10:50:32",
+ "arrivedStartStationTime": null,
+ "arrivedEndStationTime": null,
+ "cityCode": "010",
+ "areaCode": "1001",
+ "createTime": "2021-04-26 10:48:22",
+ "updateTime": "2021-04-26 10:50:32",
+ "personNum": 1,
+ "travelDistance": 1.2,
+ "vehicleColour": null,
+ "lastBrandName": null,
+ "headImgUrl": null
+ },
+ {
+ "_id": "fa3214c7a6ec411bb3d6edbc98907423",
+ "orderNo": "XB20210426000009",
+ "orderType": 10,
+ "userName": "董QAD",
+ "userPhone": "15631204018",
+ "startStationId": 1,
+ "startStation": "万集东门站",
+ "startStationCoordinate": [
+ 116.7354579447,
+ 40.1974932972
+ ],
+ "endStationId": 2,
+ "endStation": "顺密路口站",
+ "endStationCoordinate": [
+ 116.721520973,
+ 40.1940181096
+ ],
+ "orderDispatchType": 7,
+ "carNum": "京NB010",
+ "sn": "F803EB2046PZD00149",
+ "orderStartTime": "2021-04-26 19:26:05",
+ "orderEndTime": "2021-04-27 14:35:50",
+ "arrivedStartStationTime": null,
+ "arrivedEndStationTime": null,
+ "cityCode": "010",
+ "areaCode": "1001",
+ "createTime": "2021-04-26 19:26:05",
+ "updateTime": "2021-04-27 14:35:50",
+ "personNum": 1,
+ "travelDistance": 1.2,
+ "vehicleColour": null,
+ "lastBrandName": null,
+ "headImgUrl": null
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/raw/sweeper_order_1.json b/OCH/mogo-och-sweeper/src/main/res/raw/sweeper_order_1.json
new file mode 100644
index 0000000000..050b67447d
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/raw/sweeper_order_1.json
@@ -0,0 +1,28 @@
+{
+ "_id": "62bc84afbc434d01b644c74ee406e772",
+ "areaCode": "1001",
+ "carNum": "京NB010",
+ "cityCode": "010",
+ "createTime": "Apr 26, 2021 10:48:22 AM",
+ "endStation": "顺密路口站",
+ "endStationCoordinate": [
+ 116.721520973,
+ 40.1940181096
+ ],
+ "endStationId": 2,
+ "orderDispatchType": 1,
+ "orderNo": "XB20210426000002",
+ "orderStartTime": "Apr 26, 2021 10:48:22 AM",
+ "orderType": 10,
+ "sn": "F803EB2046PZD00149",
+ "startStation": "万集东门站",
+ "startStationCoordinate": [
+ 116.7354579447,
+ 40.1974932972
+ ],
+ "startStationId": 1,
+ "travelDistance": 1.2,
+ "updateTime": "Apr 26, 2021 10:48:23 AM",
+ "userName": "董QAD",
+ "userPhone": "15631204018"
+}
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/raw/sweeper_station_list1.json b/OCH/mogo-och-sweeper/src/main/res/raw/sweeper_station_list1.json
new file mode 100644
index 0000000000..c74daa1174
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/raw/sweeper_station_list1.json
@@ -0,0 +1,69 @@
+{
+ "code": 0,
+ "msg": "",
+ "detailMsg": "",
+ "result": {
+ "site": [
+ {
+ "lineId": 1.0,
+ "siteId": 1.0,
+ "siteName": "万集东门站",
+ "cityCode": "010",
+ "areaCode": "1001",
+ "areaName": "顺义区",
+ "currentLocation": [
+ 116.7354579447,
+ 40.1974932972
+ ],
+ "lon": 116.7354579447,
+ "lat": 40.1974932972,
+ "siteDesc": "万集东门站",
+ "siteState": 1.0,
+ "isCurrentSite": 1.0,
+ "siteColor": 1.0,
+ "peoples": "0",
+ "ifStop": 1.0
+ },
+ {
+ "lineId": 1.0,
+ "siteId": 2.0,
+ "siteName": "市政府前街18号",
+ "cityCode": "010",
+ "areaCode": "1001",
+ "areaName": "顺义区",
+ "currentLocation": [
+ 116.729134342,
+ 40.1953113732
+ ],
+ "lon": 116.729134342,
+ "lat": 40.1953113732,
+ "siteDesc": "市政府前街18号",
+ "siteState": 1.0,
+ "isCurrentSite": 3.0,
+ "siteColor": 2.0,
+ "peoples": "0",
+ "ifStop": 0.0
+ },
+ {
+ "lineId": 1.0,
+ "siteId": 3.0,
+ "siteName": "顺密路口站",
+ "cityCode": "010",
+ "areaCode": "1001",
+ "areaName": "顺义区",
+ "currentLocation": [
+ 116.721520973,
+ 40.1940181096
+ ],
+ "lon": 116.721520973,
+ "lat": 40.1940181096,
+ "siteDesc": "顺密路口站",
+ "siteState": 1.0,
+ "isCurrentSite": 0.0,
+ "siteColor": 0.0,
+ "peoples": "0",
+ "ifStop": 1.0
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/raw/sweeper_station_list2.json b/OCH/mogo-och-sweeper/src/main/res/raw/sweeper_station_list2.json
new file mode 100644
index 0000000000..48d6782cc3
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/raw/sweeper_station_list2.json
@@ -0,0 +1,109 @@
+{
+ "code": 0,
+ "msg": "",
+ "detailMsg": "",
+ "result": {
+ "site": [
+ {
+ "lineId": 1.0,
+ "siteId": 1.0,
+ "siteName": "万集东门站",
+ "cityCode": "010",
+ "areaCode": "1001",
+ "areaName": "顺义区",
+ "currentLocation": [
+ 116.7354579447,
+ 40.1974932972
+ ],
+ "lon": 116.7354579447,
+ "lat": 40.1974932972,
+ "siteDesc": "万集东门站",
+ "siteState": 1.0,
+ "isCurrentSite": 0.0,
+ "siteColor": 0.0,
+ "peoples": "0",
+ "ifStop": 1.0
+ },
+ {
+ "lineId": 1.0,
+ "siteId": 1.0,
+ "siteName": "万集东门站",
+ "cityCode": "010",
+ "areaCode": "1001",
+ "areaName": "顺义区",
+ "currentLocation": [
+ 116.7374429112,
+ 40.2023987087
+ ],
+ "lon": 116.7374429112,
+ "lat": 40.2023987087,
+ "siteDesc": "万集东门站",
+ "siteState": 1.0,
+ "isCurrentSite": 0.0,
+ "siteColor": 0.0,
+ "peoples": "0",
+ "ifStop": 1.0
+ },
+ {
+ "lineId": 1.0,
+ "siteId": 2.0,
+ "siteName": "顺密路口站",
+ "cityCode": "010",
+ "areaCode": "1001",
+ "areaName": "顺义区",
+ "currentLocation": [
+ 116.721520973,
+ 40.1940181096
+ ],
+ "lon": 116.721520973,
+ "lat": 40.1940181096,
+ "siteDesc": "顺密路口站",
+ "siteState": 1.0,
+ "isCurrentSite": 1.0,
+ "siteColor": 1.0,
+ "peoples": "0",
+ "ifStop": 1.0
+ },
+ {
+ "lineId": 1.0,
+ "siteId": 2.0,
+ "siteName": "顺密路口站",
+ "cityCode": "010",
+ "areaCode": "1001",
+ "areaName": "顺义区",
+ "currentLocation": [
+ 116.723146,
+ 40.179637
+ ],
+ "lon": 116.723146,
+ "lat": 40.179637,
+ "siteDesc": "顺密路口站",
+ "siteState": 1.0,
+ "isCurrentSite": 1.0,
+ "siteColor": 1.0,
+ "peoples": "0",
+ "ifStop": 1.0
+ },
+ {
+ "lineId": 2.0,
+ "siteId": 2.0,
+ "siteName": "顺密路口站",
+ "cityCode": "010",
+ "areaCode": "1001",
+ "areaName": "顺义区",
+ "currentLocation": [
+ 116.738835502,
+ 40.2023958306
+ ],
+ "lon": 116.738835502,
+ "lat": 40.2023958306,
+ "siteDesc": "顺密路口站",
+ "siteState": 1.0,
+ "isCurrentSite": 1.0,
+ "siteColor": 1.0,
+ "peoples": "0",
+ "ifStop": 1.0
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/values-xhdpi-2560x1440/dimens.xml b/OCH/mogo-och-sweeper/src/main/res/values-xhdpi-2560x1440/dimens.xml
new file mode 100644
index 0000000000..40a71f82e2
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/values-xhdpi-2560x1440/dimens.xml
@@ -0,0 +1,140 @@
+
+
+
+ 300px
+ 348px
+ 211px
+ 276px
+
+
+ 220px
+ 98px
+ 159px
+
+ 32px
+ 20px
+ 40px
+ 42px
+
+ 15px
+
+ 20px
+ 36px
+ 28px
+ 36px
+
+ 3px
+ 3px
+ 17px
+ 17px
+
+
+ 300px
+ 270px
+ 30px
+ 24px
+ 24px
+ 1px
+ 30px
+ 23px
+ 30px
+ 146px
+ 20px
+ 23px
+ 30px
+ 23px
+ 26px
+ 34px
+ 20px
+ 80px
+ 3px
+ 34px
+ 20px
+ 28px
+ 27px
+
+
+ 28px
+ 20px
+ 20px
+ 64px
+ 16px
+
+ 40px
+ 40px
+ 46px
+ 24px
+
+ 530px
+ 492px
+
+ 20px
+ 20px
+ 70px
+ 130px
+ 93px
+ 150px
+ 70px
+
+ 24px
+ 616px
+ 180px
+
+ 112px
+ 112px
+
+ 92px
+
+ 30px
+ 616px
+ 754px
+
+
+ 40px
+ 13px
+ 12px
+ 350px
+
+ 460px
+ 30px
+
+ 110px
+ 40px
+ 320px
+ 20px
+ 40px
+ 320px
+ 320px
+ 70px
+ 616px
+ 130px
+ 30px
+ 279px
+ 112px
+ 22px
+ 36px
+ 50px
+ 60px
+
+
+ 46px
+ 700px
+ 120px
+ 560px
+ 116px
+
+ 20px
+
+ 225px
+ 154px
+ 60px
+ 40px
+ 23px
+ 210px
+ 120px
+ 15px
+ 17px
+ 154px
+ 130px
+ 60px
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/values-xhdpi-2560x1600/dimens.xml b/OCH/mogo-och-sweeper/src/main/res/values-xhdpi-2560x1600/dimens.xml
new file mode 100644
index 0000000000..85035d4a73
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/values-xhdpi-2560x1600/dimens.xml
@@ -0,0 +1,138 @@
+
+
+
+ 300px
+ 348px
+ 211px
+ 276px
+
+
+ 220px
+ 98px
+ 159px
+
+ 32px
+ 20px
+ 40px
+ 42px
+
+ 15px
+
+ 20px
+ 36px
+ 28px
+ 36px
+
+ 3px
+ 3px
+ 17px
+ 17px
+
+
+ 300px
+ 270px
+ 30px
+ 24px
+ 24px
+ 1px
+ 30px
+ 23px
+ 30px
+ 146px
+ 20px
+ 23px
+ 30px
+ 23px
+ 26px
+ 34px
+ 20px
+ 80px
+ 3px
+ 34px
+ 20px
+ 28px
+ 27px
+
+
+ 25.6px
+ 20px
+ 20px
+ 64px
+ 16px
+
+ 40px
+ 40px
+ 46px
+ 24px
+
+ 530px
+ 492px
+
+ 20px
+ 20px
+ 70px
+ 130px
+ 93px
+ 150px
+ 70px
+
+ 24px
+ 616px
+ 180px
+
+ 112px
+ 112px
+
+ 92px
+
+ 30px
+ 616px
+ 754px
+
+
+ 40px
+ 13px
+ 12px
+ 350px
+
+ 460px
+ 30px
+
+ 110px
+ 40px
+ 320px
+ 20px
+ 40px
+ 320px
+ 460px
+ 70px
+ 460px
+ 130px
+ 30px
+ 276px
+ 112px
+ 22px
+ 36px
+ 50px
+ 60px
+
+ 46px
+ 700px
+ 120px
+ 560px
+ 116px
+ 50px
+
+ 225px
+ 154px
+ 60px
+ 40px
+ 23px
+ 210px
+ 120px
+ 15px
+ 17px
+ 154px
+ 130px
+ 60px
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/values/attrs.xml b/OCH/mogo-och-sweeper/src/main/res/values/attrs.xml
new file mode 100644
index 0000000000..396db92f74
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/values/attrs.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/values/colors.xml b/OCH/mogo-och-sweeper/src/main/res/values/colors.xml
new file mode 100644
index 0000000000..855ffb1a50
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/values/colors.xml
@@ -0,0 +1,56 @@
+
+
+ #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
+
+ #2966EC
+ #F0151D41
+
+ #19FFFFFF
+ #FFFFFF
+
+ #FFFFA28B
+ #FFDA1100
+ #FF60FFD3
+ #FF006D43
+ #FFFFE198
+ #FFFF9B00
+
+ #7DE261
+ #f00
+ #BF30334C
+ #ffffff
+ #1FA7FF
+ #80ffffff
+ #BF30334C
+
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/values/dimens.xml b/OCH/mogo-och-sweeper/src/main/res/values/dimens.xml
new file mode 100644
index 0000000000..8cbd5c847a
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/values/dimens.xml
@@ -0,0 +1,157 @@
+
+
+
+ 300px
+ 348px
+ 211px
+ 276px
+
+
+ 220px
+ 98px
+ 159px
+
+ 32px
+ 20px
+ 26px
+ 20px
+
+ 15px
+
+ 20px
+ 36px
+ 28px
+ 36px
+
+ 3px
+ 3px
+ 17px
+ 17px
+
+
+ 300px
+ 270px
+ 30px
+ 24px
+ 24px
+ 1px
+ 30px
+ 23px
+ 30px
+ 146px
+ 20px
+ 23px
+ 30px
+ 23px
+ 26px
+ 20px
+ 20px
+ 80px
+ 3px
+ 27px
+ 20px
+ 28px
+ 27px
+
+ 16px
+ 16px
+ 16px
+ 16px
+ 16px
+
+ 40px
+ 40px
+ 46px
+ 24px
+
+ 345px
+ 492px
+
+ 15px
+ 15px
+ 40px
+ 50px
+ 50px
+ 70px
+ 40px
+
+ 24px
+ 300px
+ 100px
+
+ 100px
+ 100px
+
+ 35px
+
+ 15px
+ 300px
+ 270px
+
+ 30px
+ 13px
+ 12px
+ 288px
+
+ 460px
+ 30px
+
+ 80px
+ 28px
+ 200px
+ 10px
+ 40px
+ 200px
+ 300px
+ 60px
+ 300px
+ 110px
+ 20px
+
+ #FFFFFF
+ #4DFFFFFF
+ #FFFFFF
+ #323C6F
+ 10px
+ 20px
+ 200px
+ 52px
+ 65px
+ 20px
+ 50px
+ 20px
+ 38px
+ 33px
+ 368px
+ 76px
+ 38px
+ 190px
+ 76px
+ 16px
+ 24px
+ 35px
+ 822px
+
+ 30px
+ 450px
+ 72px
+ 280px
+ 58px
+ 20px
+
+ 225px
+ 154px
+ 60px
+ 40px
+ 23px
+ 210px
+ 120px
+ 15px
+ 17px
+ 154px
+ 130px
+ 60px
+
+ 16px
+ 36px
+
\ No newline at end of file
diff --git a/OCH/mogo-och-sweeper/src/main/res/values/strings.xml b/OCH/mogo-och-sweeper/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..95a71366f9
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/values/strings.xml
@@ -0,0 +1,29 @@
+
+ 近距视角
+ 远距视角
+ 启动中…
+ 启动成功
+ 启动失败
+ 自动驾驶
+ 路线列表
+ 路线:
+ 起点:
+ 终点:
+ 确认
+ 切换路线
+ 自动驾驶中,不可切换路线
+ 当前行程未完成,不可切换路线
+ 当前车辆无路线\n请联系运营人员绑定
+ 起点:
+ 终点:
+ 更换路线成功
+ 更换路线失败
+
+ 起点:
+ 终点:
+ 当前站点:
+ 下一站:
+ 自动驾驶状态为0不可用
+
+ 预计等待%d秒
+
diff --git a/OCH/mogo-och-sweeper/src/main/res/values/style.xml b/OCH/mogo-och-sweeper/src/main/res/values/style.xml
new file mode 100644
index 0000000000..36d7ef0d93
--- /dev/null
+++ b/OCH/mogo-och-sweeper/src/main/res/values/style.xml
@@ -0,0 +1,23 @@
+
+
+
+
diff --git a/OCH/mogo-och-sweeper/src/test/java/com/mogo/och/sweeper/ExampleUnitTest.kt b/OCH/mogo-och-sweeper/src/test/java/com/mogo/och/sweeper/ExampleUnitTest.kt
new file mode 100644
index 0000000000..1afdb5acad
--- /dev/null
+++ b/OCH/mogo-och-sweeper/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/bugly/BuglySymtabLog.txt b/app/bugly/BuglySymtabLog.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/app/bugly/BuglyUploadLog.txt b/app/bugly/BuglyUploadLog.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/app/build.gradle b/app/build.gradle
index 3a14cfac1c..508935760b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -227,6 +227,7 @@ android {
apply from: "./productFlavors/fPadLenovoOchTaxi.gradle"
apply from: "./productFlavors/fPadLenovoOchBusPassenger.gradle"
apply from: "./productFlavors/fPadLenovoOchTaxiPassenger.gradle"
+ apply from: "./productFlavors/fPadLenovoOchSweeper.gradle"
packagingOptions {
exclude 'META-INF/io.netty.versions.properties'
diff --git a/app/functions/och.gradle b/app/functions/och.gradle
index fa05f78b8f..6a3e9f0776 100644
--- a/app/functions/och.gradle
+++ b/app/functions/och.gradle
@@ -8,6 +8,15 @@ project.dependencies {
exclude group: 'com.mogo.eagle.core.function' //by group
}
+ // sweeper清扫车
+ fPadLenovoOchSweeperImplementation(rootProject.ext.dependencies.mogoochsweeper) {
+ exclude group: 'com.mogo.commons' //by group
+ exclude group: 'com.mogo.module' //by group
+ exclude group: 'com.mogo.map' //by group
+ exclude group: 'com.mogo.eagle.core' //by group
+ exclude group: 'com.mogo.eagle.core.function' //by group
+ }
+
// Bus司机端
fPadLenovoOchBusImplementation(rootProject.ext.dependencies.mogoochbus) {
exclude group: 'com.mogo.commons' //by group
@@ -50,6 +59,14 @@ project.dependencies {
exclude group: 'com.mogo.eagle.core' //by group
exclude group: 'com.mogo.eagle.core.function' //by group
}
+ // sweeper 清扫车
+ fPadLenovoOchSweeperImplementation (project(':OCH:mogo-och-sweeper')) {
+ exclude group: 'com.mogo.commons' //by group
+ exclude group: 'com.mogo.module' //by group
+ exclude group: 'com.mogo.map' //by group
+ exclude group: 'com.mogo.eagle.core' //by group
+ exclude group: 'com.mogo.eagle.core.function' //by group
+ }
// Bus司机端
fPadLenovoOchBusImplementation (project(':OCH:mogo-och-bus')) {
diff --git a/app/productFlavors/fPadLenovoOchSweeper.gradle b/app/productFlavors/fPadLenovoOchSweeper.gradle
new file mode 100644
index 0000000000..97db194a24
--- /dev/null
+++ b/app/productFlavors/fPadLenovoOchSweeper.gradle
@@ -0,0 +1,38 @@
+project.android.productFlavors {
+ // 衡阳-联想Pad-网约车-小巴车
+ fPadLenovoOchSweeper {
+ externalNativeBuild {
+ ndk {
+ // 设置支持的SO库架构
+ abiFilters "arm64-v8a"
+ }
+ }
+ minSdkVersion rootProject.ext.android.minSdkVersionPadLenovo
+ targetSdkVersion rootProject.ext.android.targetSdkVersionPadLenovo
+ versionCode rootProject.versionCode as int
+ versionName rootProject.versionName
+ // 应用包名
+ applicationId rootProject.ext.android.fLauncherApplicationId
+ dimension "product"
+
+ // 车机类型,主要用于区分自研车机还是别人家的车机,自研车机类型为0
+ buildConfigField 'int', 'CAR_MACHINE_TYPE', '2'
+ //高德地图鉴权信息
+ manifestPlaceholders = [AMAP_API_VALUE: rootProject.ext.android.fLauncherAmapApiValue, CHANNEL_VALUE: "fPadLenovoOchSweeper",ACTIVITY_ROOT:true]
+
+ // 是否基于地图
+ buildConfigField 'boolean', 'IS_MAP_BASED', 'true'
+
+ // 是否需要实时上报坐标
+ buildConfigField 'boolean', 'IS_NEED_UPLOAD_COORDINATES_IN_TIME', 'true'
+ // GPS数据提供源: 0-Android系统,1-工控机,2-OBU
+ buildConfigField 'int', 'GPS_PROVIDER', "1"
+
+ // 构建的应用身份类型,出租车0|小巴A-司机|乘客
+ buildConfigField 'int', 'APP_IDENTITY_MODE', "0xA0"
+ // 连接的工控机IP地址
+ buildConfigField 'String', 'ADAS_CONNECT_IP', "\"192.168.8.102\""
+ // 构建的是否是演示(美化)模式
+ buildConfigField 'boolean', 'IS_DEMO_MODE', 'false'
+ }
+}
\ No newline at end of file
diff --git a/app/regroup.gradle b/app/regroup.gradle
index 6b249c3b08..56c7128a4f 100644
--- a/app/regroup.gradle
+++ b/app/regroup.gradle
@@ -1,7 +1,7 @@
// 将 install 和 assemble 任务按功能分组
afterEvaluate {
- def launcher = [ "fPadLenovo", "fPadLenovoOchTaxi", "fPadLenovoOchBus", "fPadLenovoOchBusPassenger", "fPadLenovoOchTaxiPassenger"]
+ def launcher = [ "fPadLenovo","fPadLenovoOchSweeper", "fPadLenovoOchTaxi", "fPadLenovoOchBus", "fPadLenovoOchBusPassenger", "fPadLenovoOchTaxiPassenger"]
it.getTasks().iterator().forEachRemaining {
def task = it
diff --git a/app/src/main/java/com/mogo/launcher/stageone/ConfigStartUp.kt b/app/src/main/java/com/mogo/launcher/stageone/ConfigStartUp.kt
index 0f178d13cf..a654875d4a 100644
--- a/app/src/main/java/com/mogo/launcher/stageone/ConfigStartUp.kt
+++ b/app/src/main/java/com/mogo/launcher/stageone/ConfigStartUp.kt
@@ -68,7 +68,10 @@ class ConfigStartUp : AndroidStartup() {
// 配置BuglyAppID:MoGoEagleEye
CrashReportConstants.buglyAppID = "ac71228f85"
- if (DebugConfig.getProductFlavor() == "fPadLenovoOchTaxi" || DebugConfig.getProductFlavor() == "fPadLenovoOchBus" || DebugConfig.getProductFlavor() == "fPadLenovoOchTaxiPassenger" || DebugConfig.getProductFlavor() == "fPadLenovoOchBusPassenger") {
+ if (DebugConfig.getProductFlavor() == "fPadLenovoOchTaxi" || DebugConfig.getProductFlavor() == "fPadLenovoOchBus"
+ || DebugConfig.getProductFlavor() == "fPadLenovoOchTaxiPassenger"
+ || DebugConfig.getProductFlavor() == "fPadLenovoOchBusPassenger"
+ || DebugConfig.getProductFlavor() == "fPadLenovoOchSweeper") {
//控制HMI展示元素 将不用手动调用setXXXXXViewVisibility
HmiBuildConfig.isShowSpeedView = false
HmiBuildConfig.isShowAutopilotStatusView = false
@@ -80,7 +83,8 @@ class ConfigStartUp : AndroidStartup() {
if (DebugConfig.getProductFlavor() == "fPadLenovoOchTaxi" || DebugConfig.getProductFlavor() == "fPadLenovoOchTaxiPassenger") {
HdMapBuildConfig.currentCarVrIconRes = R.raw.chuzuche
- } else if (DebugConfig.getProductFlavor() == "fPadLenovoOchBus" || DebugConfig.getProductFlavor() == "fPadLenovoOchBusPassenger") {
+ } else if (DebugConfig.getProductFlavor() == "fPadLenovoOchBus" || DebugConfig.getProductFlavor() == "fPadLenovoOchBusPassenger"
+ || DebugConfig.getProductFlavor() == "fPadLenovoOchSweeper") {
HdMapBuildConfig.currentCarVrIconRes = R.raw.xiaobache
HmiBuildConfig.isShowBrakeLightView = false
HmiBuildConfig.isShowTurnLightView = false
diff --git a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/App.java b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/App.java
index f1943a9a49..e89e78ab58 100644
--- a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/App.java
+++ b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/App.java
@@ -5,9 +5,11 @@ import android.app.Application;
import com.zhidao.adas.client.utils.CrashHandler;
public class App extends Application {
+ public static App INSTANCE;
@Override
public void onCreate() {
super.onCreate();
+ INSTANCE = this;
CrashHandler.getInstance().init(this);
}
}
diff --git a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/adapter/SpecialVehicleAdapter.java b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/adapter/SpecialVehicleAdapter.java
new file mode 100644
index 0000000000..a7eedf2245
--- /dev/null
+++ b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/adapter/SpecialVehicleAdapter.java
@@ -0,0 +1,60 @@
+package com.zhidao.adas.client.adapter;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.zhidao.adas.client.R;
+import com.zhidao.adas.client.base.BaseAdapter;
+import com.zhidao.adas.client.base.BaseViewHolder;
+import com.zhidao.adas.client.bean.SpecialVehicleBean;
+
+import java.util.List;
+
+/**
+ * @author song kenan
+ * @des 线路
+ * @date 2021/8/13
+ */
+public class SpecialVehicleAdapter extends BaseAdapter {
+
+
+ public SpecialVehicleAdapter(List data) {
+ super(data);
+ }
+
+ @Override
+ public void setData(List mDatas) {
+ super.setData(mDatas);
+ }
+
+ @Override
+ protected void onBindDataToItem(ViewHolder viewHolder, SpecialVehicleBean data, int position) {
+ viewHolder.title.setText(data.name);
+ }
+
+ @Override
+ protected View getItemViewResource(ViewGroup viewGroup) {
+ return LayoutInflater.from(mContext).inflate(R.layout.item_info, viewGroup, false);
+ }
+
+ @Override
+ protected ViewHolder getViewHolder(View view) {
+ return new ViewHolder(view, this);
+ }
+
+ class ViewHolder extends BaseViewHolder {
+ TextView title;
+
+ public ViewHolder(View itemView, SpecialVehicleAdapter adapter) {
+ super(itemView, adapter);
+// ViewGroup.LayoutParams layoutParams = itemView.getLayoutParams();
+// if (layoutParams != null) {
+// layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+//
+// }
+ title = itemView.findViewById(R.id.tv_info_title);
+ }
+ }
+}
diff --git a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/bean/SpecialVehicleBean.java b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/bean/SpecialVehicleBean.java
new file mode 100644
index 0000000000..63db092b72
--- /dev/null
+++ b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/bean/SpecialVehicleBean.java
@@ -0,0 +1,230 @@
+package com.zhidao.adas.client.bean;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+
+import com.google.protobuf.TextFormat;
+import com.zhidao.adas.client.ui.special.SpecialVehicleFloatWindowManager;
+import com.zhidao.adas.client.utils.PreferencesUtils;
+import com.zhidao.support.adas.high.AdasManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import chassis.SpecialVehicleTaskCmdOuterClass;
+
+public class SpecialVehicleBean {
+ private interface TAG {
+ String FTQSC = "ftqsc";//福田清扫车
+ String KWXB = "kwxb";//开沃小巴
+ }
+
+ public interface SEND_TYPE {
+ int ONE = 0;//单次发送
+ int MORE = 1;//多次发送
+ int ALL = 2;//两种方式都支持
+ }
+
+ public final String name;
+ public final String simpleName;//简单名字 两个字
+ public final List options;
+ private final String tag;//用于存储
+ public int sendType = SEND_TYPE.ONE;//发送类型
+ private SpecialVehicleFloatWindowManager manager;
+
+ public static final int SCREEN_MARGIN = 20;
+
+ private final String FLOAT_WINDOW_LOCATION_MIN_X;
+ private final String FLOAT_WINDOW_LOCATION_MIN_Y;
+ private final String FLOAT_WINDOW_LOCATION_MAX_X;
+ private final String FLOAT_WINDOW_LOCATION_MAX_Y;
+
+ private SpecialVehicleBean(@NonNull String name, @NonNull String simpleName, String tag, List options) {
+ this.name = name;
+ this.simpleName = simpleName;
+ this.tag = tag;
+ this.options = options;
+ FLOAT_WINDOW_LOCATION_MIN_X = tag + "_float_window_location_min_x";
+ FLOAT_WINDOW_LOCATION_MIN_Y = tag + "_float_window_location_min_y";
+ FLOAT_WINDOW_LOCATION_MAX_X = tag + "_float_window_location_max_X";
+ FLOAT_WINDOW_LOCATION_MAX_Y = tag + "_float_window_location_max_y";
+
+ }
+
+ public void showFloat(Context context) {
+ if (manager == null)
+ manager = new SpecialVehicleFloatWindowManager(context, this);
+ manager.show();
+ }
+
+ public void dismissFloat() {
+ if (manager != null) {
+ manager.onBack();
+ manager = null;
+ }
+ }
+
+ /************************悬浮窗位置******************/
+
+
+ public void setFloatWindowLocationMinX(Context context, int x) {
+ PreferencesUtils.putInt(context, FLOAT_WINDOW_LOCATION_MIN_X, x);
+ }
+
+ public int getFloatWindowLocationMinX(Context context) {
+ return PreferencesUtils.getInt(context, FLOAT_WINDOW_LOCATION_MIN_X, SCREEN_MARGIN);
+ }
+
+ public void setFloatWindowLocationMinY(Context context, int y) {
+ PreferencesUtils.putInt(context, FLOAT_WINDOW_LOCATION_MIN_Y, y);
+ }
+
+ public int getFloatWindowLocationMinY(Context context) {
+ return PreferencesUtils.getInt(context, FLOAT_WINDOW_LOCATION_MIN_Y, SCREEN_MARGIN);
+ }
+
+
+ /************************悬浮窗位置******************/
+
+ public void setFloatWindowLocationMaxX(Context context, int x) {
+ PreferencesUtils.putInt(context, FLOAT_WINDOW_LOCATION_MAX_X, x);
+ }
+
+ public int getFloatWindowLocationMaxX(Context context) {
+ return PreferencesUtils.getInt(context, FLOAT_WINDOW_LOCATION_MAX_X, SCREEN_MARGIN);
+ }
+
+ public void setFloatWindowLocationMaxY(Context context, int y) {
+ PreferencesUtils.putInt(context, FLOAT_WINDOW_LOCATION_MAX_Y, y);
+ }
+
+ public int getFloatWindowLocationMaxY(Context context) {
+ return PreferencesUtils.getInt(context, FLOAT_WINDOW_LOCATION_MAX_Y, SCREEN_MARGIN);
+ }
+
+ /**
+ * 命令下发
+ *
+ * @param index -1一次性发送所有命令 其他 单个命令发送
+ * @return
+ */
+ public String sendCmd(int index) {
+ String str = "";
+ if (TextUtils.equals(this.tag, TAG.FTQSC)) { //福田清扫车
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.newBuilder();
+ if (index < 0) {
+ for (index = 0; index < options.size(); index++) {
+ SpecialVehicleOption option = options.get(index);
+ if (option.moreCheckPos != -1) {
+ option.checkPos = option.moreCheckPos;
+ option.moreCheckPos = -1;
+ }
+ setFuTianCleanValue(builder, index, option.checkPos);
+ }
+ } else {
+ int checkPos = options.get(index).checkPos;
+ setFuTianCleanValue(builder, index, checkPos);
+ }
+
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd fuTianCleanCmd = builder.build();
+ SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd fuTianTaskCmd = SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd.newBuilder()
+ .setRoboSweeperFutianCleanCmd(fuTianCleanCmd).build();
+ AdasManager.getInstance().sendRoboSweeperFuTianTaskCmd(fuTianTaskCmd);
+ str = TextFormat.printer().escapingNonAscii(false).printToString(fuTianTaskCmd).replaceAll("\n", "");
+ } else if (TextUtils.equals(this.tag, TAG.KWXB)) { //开沃小巴
+ SpecialVehicleTaskCmdOuterClass.RoboVanSkywellTaskCmd vanSkywellTaskCmd = SpecialVehicleTaskCmdOuterClass.RoboVanSkywellTaskCmd.newBuilder()
+ .build();
+ AdasManager.getInstance().sendRoboVanSkywellTaskCmd(vanSkywellTaskCmd);
+ }
+ return str;
+ }
+
+ private void setFuTianCleanValue(SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianCleanCmd.Builder builder, int index, int checkPos) {
+ switch (index) {
+ case 0:
+ builder.setCleanOpenRequirement(checkPos);
+ break;
+ case 1:
+ builder.setCleanModeRequirement(checkPos);
+ break;
+ case 2:
+ builder.setCleanDirectionRequirement(checkPos);
+ break;
+ case 3:
+ builder.setCleanIntensityRequirement(checkPos);
+ break;
+ case 4:
+ builder.setDuskCloseRequirement(checkPos);
+ break;
+ case 5:
+ builder.setSuctionNozzlefleOpenRequirement(checkPos);
+ break;
+ case 6:
+ builder.setSprayGunOpenRequirement(checkPos);
+ break;
+ case 7:
+ builder.setSweepdiskSpeedRequirement(checkPos);
+ break;
+ }
+ }
+
+
+ public static List init() {
+ List list = new ArrayList<>();
+ List optionsF = new ArrayList<>();
+ int tag = 0;
+ String[] value = new String[3];
+ value[0] = "0-No Req";
+ value[1] = "1-Start";
+ value[2] = "2-Stop";
+ optionsF.add(new SpecialVehicleOption("清扫作业", tag++, value, 0));
+ value = new String[6];
+ value[0] = "0-No Req";
+ value[1] = "1-Sweeping";
+ value[2] = "2-Wash Sweeper";
+ value[3] = "3-Pure Wash";
+ value[4] = "4-Pure Draw";
+ value[5] = "5-Close Clean";
+ optionsF.add(new SpecialVehicleOption("清扫模式", tag++, value, 0));
+ value = new String[5];
+ value[0] = "0-No Req";
+ value[1] = "1-Both";
+ value[2] = "2-Left";
+ value[3] = "3-Right";
+ value[4] = "4-Close Side";
+ optionsF.add(new SpecialVehicleOption("清扫方向", tag++, value, 0));
+ value = new String[3];
+ value[0] = "0-No Req";
+ value[1] = "1-Stand";
+ value[2] = "2-Strong";
+ optionsF.add(new SpecialVehicleOption("作业强度", tag++, value, 0));
+ value = new String[3];
+ value[0] = "0-No Req";
+ value[1] = "1-Close";
+ value[2] = "2-Open";
+ optionsF.add(new SpecialVehicleOption("降尘", tag++, value, 0));
+ value = new String[3];
+ value[0] = "0-No Req";
+ value[1] = "1-Open";
+ value[2] = "2-Close";
+ optionsF.add(new SpecialVehicleOption("吸嘴挡板", tag++, value, 0));
+ value = new String[3];
+ value[0] = "0-No Req";
+ value[1] = "1-Open";
+ value[2] = "2-Close";
+ optionsF.add(new SpecialVehicleOption("喷雾枪", tag++, value, 0));
+ value = new String[3];
+ value[0] = "0-No Req";
+ value[1] = "1-Decelerate";
+ value[2] = "2-Accelerate";
+ optionsF.add(new SpecialVehicleOption("扫盘加速", tag, value, 0));
+ SpecialVehicleBean beanF = new SpecialVehicleBean("福田清扫车", "福清", TAG.FTQSC, optionsF);
+ SpecialVehicleBean beanK = new SpecialVehicleBean("开沃小巴", "开巴", TAG.KWXB, null);
+ list.add(beanF);
+ list.add(beanK);
+ return list;
+ }
+
+}
diff --git a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/bean/SpecialVehicleOption.java b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/bean/SpecialVehicleOption.java
new file mode 100644
index 0000000000..26f2ec883a
--- /dev/null
+++ b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/bean/SpecialVehicleOption.java
@@ -0,0 +1,16 @@
+package com.zhidao.adas.client.bean;
+
+public class SpecialVehicleOption {
+ public final String name;
+ public final int tag;
+ public final String[] value;
+ public int checkPos = 0;//选中的下标
+ public int moreCheckPos = -1;//发送模式下多条模式时选中的下标
+
+ public SpecialVehicleOption(String name, int tag, String[] value, int checkPos) {
+ this.name = name;
+ this.tag = tag;
+ this.value = value;
+ this.checkPos = checkPos;
+ }
+}
diff --git a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/MainActivity.java b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/MainActivity.java
index eb77663d3c..ab90d01575 100644
--- a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/MainActivity.java
+++ b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/MainActivity.java
@@ -70,6 +70,7 @@ import com.zhidao.adas.client.bean.PlanningObjects;
import com.zhidao.adas.client.bean.PredictionObstacleTrajectory;
import com.zhidao.adas.client.bean.RecordDataConfig;
import com.zhidao.adas.client.bean.RecordPanel;
+import com.zhidao.adas.client.bean.SpecialVehicleBean;
import com.zhidao.adas.client.bean.StatusInfo;
import com.zhidao.adas.client.bean.TrackedObjects;
import com.zhidao.adas.client.bean.Trajectory;
@@ -77,6 +78,7 @@ import com.zhidao.adas.client.bean.VehicleState;
import com.zhidao.adas.client.bean.Warn;
import com.zhidao.adas.client.log.ConnectStatusSave;
import com.zhidao.adas.client.log.LogSave;
+import com.zhidao.adas.client.ui.special.SpecialVehicleDialog;
import com.zhidao.adas.client.utils.Constants;
import com.zhidao.adas.client.utils.PreferencesUtils;
import com.zhidao.support.adas.high.AdasManager;
@@ -159,11 +161,13 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
private String recordFileName;
private int connectStatus;
private AutoPilotModeDialog autoPilotModeDialog;
+ private SpecialVehicleDialog specialVehicleDialog;
private ListPopupWindow listPopupWindow;
private FloatWindow floatWindow;
private View include_title;
private boolean isAutopilotAbility = true;
private String autopilotAbilityReason;
+ private List specialVehicleBeanList;//特种车辆
// @Override
// protected void onStart() {
// super.onStart();
@@ -253,6 +257,14 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
wakeLock.release();
if (wifiLock != null)
wifiLock.release();
+ if (autoPilotModeDialog != null && autoPilotModeDialog.isShowing()) {
+ autoPilotModeDialog.dismiss();
+ autoPilotModeDialog = null;
+ }
+ if (specialVehicleDialog != null && specialVehicleDialog.isShowing()) {
+ specialVehicleDialog.dismiss();
+ specialVehicleDialog = null;
+ }
}
private void canDrawOverlays() {
@@ -633,6 +645,7 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
titleBtnData.add(Constants.TITLE.SEND_SET_AUTOPILOT_MODE_REQ);
titleBtnData.add(Constants.TITLE.SEND_GLOBAL_PATH_REQ);
+ titleBtnData.add(Constants.TITLE.SEND_SPECIAL_VEHICLE_TASK_CMD);
titleBtnData.add(Constants.TITLE.SEND_STATUS_QUERY_REQ);
titleBtnData.add(Constants.TITLE.SEND_BASIC_INFO_RESP);
titleBtnData.add(Constants.TITLE.SEND_RECORD_DATA_CONFIG_RESP);
@@ -1109,6 +1122,7 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
} else if (connectStatus == IPC_CONNECTION_STATUS.DISCONNECTED) {
getHandler().sendEmptyMessage(WHAT_IPC_IP);
}
+
// LogSave.getInstance().saveLog("连接状态", status);
// CupidLogUtils.i(TAG, "connectStatus=" + status);
}
@@ -1210,6 +1224,17 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
//自动驾驶路径查询
AdasManager.getInstance().sendGlobalPathReq();
break;
+ case Constants.TITLE.SEND_SPECIAL_VEHICLE_TASK_CMD:
+ if (specialVehicleBeanList == null) {
+ specialVehicleBeanList = SpecialVehicleBean.init();
+ }
+ if (specialVehicleDialog == null) {
+ specialVehicleDialog = new SpecialVehicleDialog(this, specialVehicleBeanList);
+ }
+ if (!specialVehicleDialog.isShowing()) {
+ specialVehicleDialog.show();
+ }
+ break;
case Constants.TITLE.SEND_STATUS_QUERY_REQ:
AdasManager.getInstance().sendStatusQueryReq();
break;
@@ -1358,6 +1383,12 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
switch (msg.what) {
case WHAT_IPC_IP:
showIPCIP();
+ if (specialVehicleBeanList != null && !specialVehicleBeanList.isEmpty()) {
+ for (SpecialVehicleBean bean : specialVehicleBeanList) {
+ bean.dismissFloat();
+ }
+ specialVehicleBeanList = null;
+ }
break;
case WHAT_DRIVER_IP:
ipcIp.setVisibility(View.VISIBLE);
diff --git a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/special/SpecialVehicleDialog.java b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/special/SpecialVehicleDialog.java
new file mode 100644
index 0000000000..0903180db1
--- /dev/null
+++ b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/special/SpecialVehicleDialog.java
@@ -0,0 +1,116 @@
+package com.zhidao.adas.client.ui.special;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.SimpleItemAnimator;
+
+import com.zhidao.adas.client.App;
+import com.zhidao.adas.client.R;
+import com.zhidao.adas.client.adapter.SpecialVehicleAdapter;
+import com.zhidao.adas.client.base.BaseAdapter;
+import com.zhidao.adas.client.bean.SpecialVehicleBean;
+import com.zhidao.adas.client.ui.AutopilotConfigActivity;
+
+import java.util.List;
+
+
+/**
+ * 特种车辆
+ */
+public class SpecialVehicleDialog extends Dialog {
+ private RecyclerView recyclerView;
+ private List list;
+
+
+ public SpecialVehicleDialog(@NonNull Context context, List list) {
+ super(context, R.style.CustomDialog);
+ this.list = list;
+ }
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.dialog_autopilot_mode);
+ //初始化界面控件
+ initView();
+ //初始化界面控件的事件
+ initListener();
+ initBtnRecyclerView();
+ setOnDismissListener(new OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ }
+ });
+
+ }
+
+ @Override
+ public void show() {
+ super.show();
+ }
+
+
+ private void initBtnRecyclerView() {
+ //初始info-recycle
+ LinearLayoutManager nodLinearLayoutManage = new LinearLayoutManager(getContext());
+ nodLinearLayoutManage.setOrientation(LinearLayoutManager.VERTICAL);
+ recyclerView.setLayoutManager(nodLinearLayoutManage);
+ //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能
+ recyclerView.setHasFixedSize(true);
+ //解决局部刷新闪屏问题
+ SimpleItemAnimator animatorInfo = (SimpleItemAnimator) recyclerView.getItemAnimator();
+ if (animatorInfo != null)
+ animatorInfo.setSupportsChangeAnimations(false);
+ //创建并设置Adapter
+ SpecialVehicleAdapter adapter = new SpecialVehicleAdapter(list);
+ recyclerView.setAdapter(adapter);
+ adapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() {
+ @Override
+ public void onItemClick(int position, SpecialVehicleBean data) {
+ if (data.options == null) {
+ Toast.makeText(getContext(), "“" + data.name + "”暂未支持", Toast.LENGTH_SHORT).show();
+ } else {
+ data.showFloat(App.INSTANCE);
+ SpecialVehicleDialog.this.dismiss();
+ }
+
+ }
+ });
+ }
+
+ /**
+ * 初始化界面的确定和取消监听器
+ */
+ private void initListener() {
+ findViewById(R.id.settings).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ getContext().startActivity(new Intent(getContext(), AutopilotConfigActivity.class));
+ }
+ });
+ }
+
+
+ /**
+ * 初始化界面控件
+ */
+ private void initView() {
+ recyclerView = findViewById(R.id.recyclerView);
+ findViewById(R.id.settings).setVisibility(View.GONE);
+ TextView textView = findViewById(R.id.title);
+ textView.setText("特种车辆");
+ }
+
+
+}
\ No newline at end of file
diff --git a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/special/SpecialVehicleFloatWindow.java b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/special/SpecialVehicleFloatWindow.java
new file mode 100644
index 0000000000..c60756c777
--- /dev/null
+++ b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/special/SpecialVehicleFloatWindow.java
@@ -0,0 +1,477 @@
+package com.zhidao.adas.client.ui.special;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Handler;
+import android.os.Message;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.HorizontalScrollView;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.widget.AppCompatButton;
+
+import com.zhidao.adas.client.R;
+import com.zhidao.adas.client.bean.SpecialVehicleBean;
+import com.zhidao.adas.client.bean.SpecialVehicleOption;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+
+
+/**
+ * 2017/1/10.
+ * Description:全局悬浮窗口
+ */
+
+public class SpecialVehicleFloatWindow extends LinearLayout {
+
+ /*********************悬浮窗相关***********************/
+
+ private int sW;
+ private int sH;
+ private boolean isMaximize = true;//是否是最大化
+ private WindowManager wm;
+ //此wmParams变量为获取的全局变量,用以保存悬浮窗口的属性
+ private WindowManager.LayoutParams wmParams;
+ private int btnMaximizeW;
+ private int btnMaximizeH;
+
+ /*********************CAN数据配置相关***********************/
+ private final static int WHAT_UPDATE_DATA = 1;
+ private BaseHandler mBaseHandler;
+ private LinearLayout layout_btn;
+ private HorizontalScrollView btn_list;
+ private AppCompatButton btn_send;
+ private RadioGroup rg_send_type;
+ private TextView text;
+ private TextView title;
+ private TextView btn_maximize;
+ private View can_parent;
+
+ private OnFloatWindowListener listener;
+ private final SpecialVehicleBean specialVehicleBean;
+
+ public interface OnFloatWindowListener {
+ void onBack();
+
+ void onMinimality();
+
+ void onMaximize();
+ }
+
+ public boolean isMaximize() {
+ return isMaximize;
+ }
+
+ public void setOnFloatWindowListener(OnFloatWindowListener listener) {
+ this.listener = listener;
+ }
+
+ public void setWmParams(WindowManager.LayoutParams wmParams) {
+ this.wmParams = wmParams;
+ }
+
+ public SpecialVehicleFloatWindow(@NonNull Context context, @NonNull SpecialVehicleBean specialVehicleBean) {
+ super(context, null, 0);
+ this.specialVehicleBean = specialVehicleBean;
+ wm = (WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
+ //加载布局
+ LayoutInflater.from(context).inflate(R.layout.dialog_special_vehicle_config, this, true);
+ initParameter();
+ initCanView();
+ }
+
+ private void initParameter() {
+ DisplayMetrics metrics2 = getResources().getDisplayMetrics();
+ sW = metrics2.widthPixels;
+ sH = metrics2.heightPixels;
+ }
+
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ if (isMaximize) {
+ minimality();
+ return true;
+ }
+ }
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
+ private float mInViewX;
+ private float mInViewY;
+ private float mDownInScreenX;
+ private float mDownInScreenY;
+ private float mInScreenX;
+ private float mInScreenY;
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ // 获取相对View的坐标,即以此View左上角为原点
+ mInViewX = event.getX();
+ mInViewY = event.getY();
+ // 获取相对屏幕的坐标,即以屏幕左上角为原点
+ mDownInScreenX = event.getRawX();
+ mDownInScreenY = event.getRawY() - getSysBarHeight(getContext());
+ mInScreenX = event.getRawX();
+ mInScreenY = event.getRawY() - getSysBarHeight(getContext());
+
+ if (!isMaximize) {
+ btn_maximize.setPressed(true);
+ btnMaximizeW = btn_maximize.getWidth();
+ btnMaximizeH = btn_maximize.getHeight();
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ // 更新浮动窗口位置参数
+ mInScreenX = event.getRawX();
+ mInScreenY = event.getRawY() - getSysBarHeight(getContext());
+ wmParams.x = (int) (mInScreenX - mInViewX);
+ wmParams.y = (int) (mInScreenY - mInViewY);
+ updateViewLayout();
+ break;
+
+ case MotionEvent.ACTION_UP:
+ // 如果手指离开屏幕时,xDownInScreen和xInScreen相等,且yDownInScreen和yInScreen相等,则视为触发了单击事件。
+// if (mDownInScreenX == mInScreenX && mDownInScreenY == mInScreenY) {
+ float temX = Math.abs(mDownInScreenX - mInScreenX);
+ float temY = Math.abs(mDownInScreenY - mInScreenY);
+ if (temX + temY < 10) {
+ maximize();
+ } else {
+ if (isMaximize) {
+ specialVehicleBean.setFloatWindowLocationMaxX(getContext(), wmParams.x);
+ specialVehicleBean.setFloatWindowLocationMaxY(getContext(), wmParams.y);
+ } else {
+ btn_maximize.setPressed(false);
+ // 抬起手指时让floatView屏幕左右边缘 距离20个像素
+// wmParams.x = wmParams.x <= (sW / 2) ? AmiConstants.SCREEN_MARGIN : sW - btnMaximizeW - AmiConstants.SCREEN_MARGIN;
+ int tem = wmParams.x;
+ if (tem < SpecialVehicleBean.SCREEN_MARGIN)
+ tem = SpecialVehicleBean.SCREEN_MARGIN;
+ else if (sW - (tem + btnMaximizeW) < SpecialVehicleBean.SCREEN_MARGIN) {
+ tem = sW - btnMaximizeW - SpecialVehicleBean.SCREEN_MARGIN;
+ }
+ wmParams.x = tem;
+ tem = wmParams.y;
+ if (tem < SpecialVehicleBean.SCREEN_MARGIN)
+ tem = SpecialVehicleBean.SCREEN_MARGIN;
+ else if (sH - (tem + btnMaximizeH) < SpecialVehicleBean.SCREEN_MARGIN) {
+ tem = sH - btnMaximizeH - SpecialVehicleBean.SCREEN_MARGIN;
+ }
+ wmParams.y = tem;
+ updateViewLayout();
+ specialVehicleBean.setFloatWindowLocationMinX(getContext(), wmParams.x);
+ specialVehicleBean.setFloatWindowLocationMinY(getContext(), wmParams.y);
+ }
+ }
+
+ break;
+ }
+ return true;
+ }
+
+ public void updateViewLayout() {
+ wm.updateViewLayout(this, wmParams);
+ }
+
+ // 获取系统状态栏高度
+ private int sbar = -1;
+
+ public int getSysBarHeight(Context contex) {
+ if (sbar == -1) {
+ Class> c;
+ Object obj;
+ Field field;
+ int x;
+ try {
+ c = Class.forName("com.android.internal.R$dimen");
+ obj = c.newInstance();
+ field = c.getField("status_bar_height");
+ x = Integer.parseInt(field.get(obj).toString());
+ sbar = contex.getResources().getDimensionPixelSize(x);
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ }
+ return sbar;
+ }
+
+ /*****************************业务逻辑*******************************************/
+
+
+ private void initCanView() {
+ initHandler();
+ can_parent = findViewById(R.id.can_parent);
+ btn_list = findViewById(R.id.btn_list);
+ btn_send = findViewById(R.id.btn_send);
+ rg_send_type = findViewById(R.id.rg_send_type);
+ text = findViewById(R.id.text);
+ title = findViewById(R.id.title);
+ title.setText(specialVehicleBean.name);
+ btn_maximize = findViewById(R.id.btn_maximize);
+ btn_maximize.setText(specialVehicleBean.simpleName);
+ initListener();
+ initBtnRecyclerView();
+ initSendTypeView();
+ }
+
+ private void initSendTypeView() {
+ int resId;
+ switch (specialVehicleBean.sendType) {
+ default:
+ case SpecialVehicleBean.SEND_TYPE.ONE:
+ resId = R.id.btn_one;
+ break;
+ case SpecialVehicleBean.SEND_TYPE.MORE:
+ resId = R.id.btn_more;
+ break;
+ case SpecialVehicleBean.SEND_TYPE.ALL:
+ resId = R.id.btn_all;
+ break;
+ }
+ rg_send_type.check(resId);
+ btn_send.setVisibility(specialVehicleBean.sendType == SpecialVehicleBean.SEND_TYPE.ONE ? View.GONE : View.VISIBLE);
+ rg_send_type.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(RadioGroup group, int checkedId) {
+ View checkView = group.findViewById(checkedId);
+ if (!checkView.isPressed()) {
+ return;
+ }
+ int type = SpecialVehicleBean.SEND_TYPE.ONE;
+ if (checkedId == R.id.btn_more) {
+ type = SpecialVehicleBean.SEND_TYPE.MORE;
+ } else {
+ if (specialVehicleBean.sendType == SpecialVehicleBean.SEND_TYPE.MORE) {
+ for (int i = 0; i < layout_btn.getChildCount(); i++) {
+ LinearLayout view = (LinearLayout) layout_btn.getChildAt(i);
+ RadioGroup radioGroup = view.findViewById(R.id.item_group);
+ SpecialVehicleOption option = specialVehicleBean.options.get(i);
+ if (option.moreCheckPos != -1) {
+ option.moreCheckPos = -1;
+ radioGroup.check(option.checkPos);
+ }
+ }
+ }
+ if (checkedId == R.id.btn_one) {
+ type = SpecialVehicleBean.SEND_TYPE.ONE;
+ } else if (checkedId == R.id.btn_all) {
+ type = SpecialVehicleBean.SEND_TYPE.ALL;
+ }
+ }
+ specialVehicleBean.sendType = type;
+ btn_send.setVisibility(type == SpecialVehicleBean.SEND_TYPE.ONE ? View.GONE : View.VISIBLE);
+ }
+ });
+ btn_send.setOnClickListener(onClickListener);
+ }
+
+
+ private void initListener() {
+ findViewById(R.id.btn_back).setOnClickListener(onClickListener);
+ findViewById(R.id.btn_minimality).setOnClickListener(onClickListener);
+ }
+
+ public void minimality() {
+ isMaximize = false;
+ btn_maximize.setVisibility(VISIBLE);
+ can_parent.setVisibility(GONE);
+ if (listener != null) {
+ listener.onMinimality();
+ }
+
+ }
+
+ public void maximize() {
+ isMaximize = true;
+ if (listener != null) {
+ listener.onMaximize();
+ }
+ btn_maximize.setVisibility(GONE);
+ can_parent.setVisibility(VISIBLE);
+
+ }
+
+ private final OnClickListener onClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+ if (id == R.id.btn_back) {
+ if (listener != null) {
+ listener.onBack();
+ }
+ } else if (id == R.id.btn_minimality) {
+ minimality();
+ } else if (id == R.id.btn_send) {
+ String cmd = specialVehicleBean.sendCmd(-1);
+ updateText(0, cmd);
+ }
+ }
+ };
+
+
+ private void initBtnRecyclerView() {
+
+ layout_btn = new LinearLayout(getContext());
+ btn_list.addView(layout_btn);
+ layout_btn.setOrientation(LinearLayout.HORIZONTAL);
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) layout_btn.getLayoutParams();
+ lp.gravity = Gravity.CENTER_VERTICAL;
+ for (int i = 0; i < specialVehicleBean.options.size(); i++) {
+ SpecialVehicleOption bean = specialVehicleBean.options.get(i);
+ View view = LayoutInflater.from(getContext()).inflate(R.layout.item_special_vehicle, layout_btn, false);
+ TextView name = view.findViewById(R.id.name);
+ RadioGroup radioGroup = view.findViewById(R.id.item_group);
+
+ name.setText(bean.name);
+ String[] value = bean.value;
+ for (int j = 0; j < value.length; j++) {
+ RadioButton button = LayoutInflater.from(getContext()).inflate(R.layout.item_special_vehicle_option_radio_btn, radioGroup, false)
+ .findViewById(R.id.r_btn);
+ button.setText(value[j]);
+ button.setId(j);
+ if (i == 1 || i == 2 || i == 3 || i == 4) {
+ ViewGroup.LayoutParams layoutParams = button.getLayoutParams();
+ layoutParams.width = 202;
+ }
+ radioGroup.addView(button);
+ }
+ radioGroup.setTag(bean.tag);
+ radioGroup.setOnCheckedChangeListener(onCheckedChangeListener);
+ radioGroup.check(bean.checkPos);
+ layout_btn.addView(view);
+ }
+ }
+
+ private final RadioGroup.OnCheckedChangeListener onCheckedChangeListener = new RadioGroup.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(RadioGroup group, int checkedId) {
+ View checkView = group.findViewById(checkedId);
+ if (checkView == null || !checkView.isPressed()) {
+ return;
+ }
+ int tag = (int) group.getTag();
+ SpecialVehicleOption bean = specialVehicleBean.options.get(tag);
+ if (specialVehicleBean.sendType != SpecialVehicleBean.SEND_TYPE.MORE) {
+ bean.checkPos = checkedId;
+ String cmd = specialVehicleBean.sendCmd(tag);
+ updateText(0, cmd);
+ } else {
+ bean.moreCheckPos = checkedId;
+ }
+ }
+ };
+
+
+ /**
+ * 更新文本
+ *
+ * @param tag 0--发送 1--接收
+ * @param data 数据
+ */
+ private void updateText(int tag, String data) {
+ Message msg = Message.obtain();
+ msg.what = WHAT_UPDATE_DATA;
+ msg.obj = data;
+ msg.arg1 = tag;
+ getHandler().sendMessage(msg);
+ }
+
+
+ /**
+ * 初始化一个Handler,如果需要使用Handler,先调用此方法,
+ * 然后可以使用postRunnable(Runnable runnable),
+ * sendMessage在handleMessage(Message msg)中接收msg
+ */
+ public void initHandler() {
+ mBaseHandler = new BaseHandler(this);
+ }
+
+ /**
+ * 返回Handler,在此之前确定已经调用initHandler()
+ *
+ * @return Handler
+ */
+ public Handler getHandler() {
+ return mBaseHandler;
+ }
+
+ /**
+ * 同Handler的postRunnable
+ * 在此之前确定已经调用initHandler()
+ */
+ protected void postRunnable(Runnable runnable) {
+ postRunnableDelayed(runnable, 0);
+ }
+
+ /**
+ * 同Handler的postRunnableDelayed
+ * 在此之前确定已经调用initHandler()
+ */
+ protected void postRunnableDelayed(Runnable runnable, long delayMillis) {
+ if (mBaseHandler == null) initHandler();
+ mBaseHandler.postDelayed(runnable, delayMillis);
+ }
+
+
+ /**
+ * 同Handler 的 handleMessage,
+ * getHandler.sendMessage,发送的Message在此接收
+ * 在此之前确定已经调用initHandler()
+ *
+ * @param msg
+ */
+ protected void handleMessage(Message msg) {
+ switch (msg.what) {
+ case WHAT_UPDATE_DATA:
+ if (msg.arg1 == 0) {
+ text.setTextColor(Color.parseColor("#FFFFFF"));
+ } else {
+ text.setTextColor(Color.parseColor("#FF0000"));
+ }
+ String str = (String) msg.obj;
+ if (str.length() < 100) {
+ text.setTextSize(14);
+ } else {
+ text.setTextSize(10);
+ }
+ text.setText(str);
+ break;
+ }
+
+ }
+
+
+ protected static class BaseHandler extends Handler {
+ private final WeakReference mObjects;
+
+ public BaseHandler(SpecialVehicleFloatWindow mPresenter) {
+ mObjects = new WeakReference(mPresenter);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ SpecialVehicleFloatWindow mPresenter = mObjects.get();
+ if (mPresenter != null)
+ mPresenter.handleMessage(msg);
+ }
+ }
+}
diff --git a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/special/SpecialVehicleFloatWindowManager.java b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/special/SpecialVehicleFloatWindowManager.java
new file mode 100644
index 0000000000..45068dee3d
--- /dev/null
+++ b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/special/SpecialVehicleFloatWindowManager.java
@@ -0,0 +1,94 @@
+package com.zhidao.adas.client.ui.special;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.view.Gravity;
+import android.view.WindowManager;
+
+import com.zhidao.adas.client.bean.SpecialVehicleBean;
+
+
+public class SpecialVehicleFloatWindowManager implements SpecialVehicleFloatWindow.OnFloatWindowListener {
+ private final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+ private SpecialVehicleFloatWindow floatWindow = null;
+ private WindowManager wm = null;
+ private final Context context;
+ private final SpecialVehicleBean specialVehicleBean;
+
+ public SpecialVehicleFloatWindowManager(Context context, SpecialVehicleBean specialVehicleBean) {
+ this.context = context;
+ this.specialVehicleBean = specialVehicleBean;
+ }
+
+ public void show() {
+ if (!createFloatWindow()) {
+ if (floatWindow.isMaximize()) {
+ floatWindow.minimality();
+ } else {
+ floatWindow.maximize();
+ }
+ }
+ }
+
+ private boolean createFloatWindow() {
+ if (floatWindow == null) {
+ wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+ layoutParams.format = PixelFormat.RGBA_8888;
+ layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;//| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ layoutParams.gravity = Gravity.START | Gravity.TOP;
+ layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
+ layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ layoutParams.alpha = 0.9f;
+ floatWindow = new SpecialVehicleFloatWindow(context, specialVehicleBean);
+ floatWindow.setWmParams(layoutParams);
+ floatWindow.setOnFloatWindowListener(this);
+ layoutParams.x = specialVehicleBean.getFloatWindowLocationMaxX(context);
+ layoutParams.y = specialVehicleBean.getFloatWindowLocationMaxY(context);
+ wm.addView(floatWindow, layoutParams);
+ return true;
+ }
+ return false;
+ }
+
+ private void removeFloatWindow() {
+ if (floatWindow != null) {
+ wm.removeView(floatWindow);
+ floatWindow = null;
+ wm = null;
+ }
+ }
+
+ @Override
+ public void onBack() {
+ removeFloatWindow();
+ }
+
+ @Override
+ public void onMinimality() {
+ layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
+ layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ layoutParams.x = specialVehicleBean.getFloatWindowLocationMinX(context);
+ layoutParams.y = specialVehicleBean.getFloatWindowLocationMinY(context);
+ layoutParams.alpha = 1f;
+ if (floatWindow != null) {
+ floatWindow.updateViewLayout();
+ }
+ }
+
+ @Override
+ public void onMaximize() {
+ layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+ layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
+ layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ layoutParams.x = specialVehicleBean.getFloatWindowLocationMaxX(context);
+ layoutParams.y = specialVehicleBean.getFloatWindowLocationMaxY(context);
+ layoutParams.alpha = 0.9f;
+ if (floatWindow != null) {
+ floatWindow.updateViewLayout();
+ }
+ }
+
+
+}
diff --git a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/utils/Constants.java b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/utils/Constants.java
index 520893fde8..df45365bf0 100644
--- a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/utils/Constants.java
+++ b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/utils/Constants.java
@@ -173,6 +173,7 @@ public class Constants {
String SEND_SET_AUTOPILOT_MODE_REQ = "自动驾驶模式";
String SEND_GLOBAL_PATH_REQ = "自动驾驶路径查询";
+ String SEND_SPECIAL_VEHICLE_TASK_CMD = "特种车辆";
String SEND_STATUS_QUERY_REQ = "状态查询";
String SEND_BASIC_INFO_RESP = "下发SN";
String SEND_RECORD_DATA_5 = "数据采集5秒";
diff --git a/app_ipc_monitoring/src/main/res/drawable/bg_radio_button.xml b/app_ipc_monitoring/src/main/res/drawable/bg_radio_button.xml
new file mode 100644
index 0000000000..51b99e6dfb
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/drawable/bg_radio_button.xml
@@ -0,0 +1,23 @@
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app_ipc_monitoring/src/main/res/drawable/bg_special_vehicle_float.xml b/app_ipc_monitoring/src/main/res/drawable/bg_special_vehicle_float.xml
new file mode 100644
index 0000000000..f234ac57f3
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/drawable/bg_special_vehicle_float.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
diff --git a/app_ipc_monitoring/src/main/res/drawable/btn_maximize_text_color.xml b/app_ipc_monitoring/src/main/res/drawable/btn_maximize_text_color.xml
new file mode 100644
index 0000000000..f7b06336e2
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/drawable/btn_maximize_text_color.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/app_ipc_monitoring/src/main/res/drawable/btn_special_vehicle_small_bg.xml b/app_ipc_monitoring/src/main/res/drawable/btn_special_vehicle_small_bg.xml
new file mode 100644
index 0000000000..35ec4217b8
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/drawable/btn_special_vehicle_small_bg.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
diff --git a/app_ipc_monitoring/src/main/res/drawable/ic_special_vehicle_back.xml b/app_ipc_monitoring/src/main/res/drawable/ic_special_vehicle_back.xml
new file mode 100644
index 0000000000..907343605c
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/drawable/ic_special_vehicle_back.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app_ipc_monitoring/src/main/res/drawable/ic_special_vehicle_back_true.xml b/app_ipc_monitoring/src/main/res/drawable/ic_special_vehicle_back_true.xml
new file mode 100644
index 0000000000..6e5e50af88
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/drawable/ic_special_vehicle_back_true.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app_ipc_monitoring/src/main/res/drawable/ic_special_vehicle_minimality.xml b/app_ipc_monitoring/src/main/res/drawable/ic_special_vehicle_minimality.xml
new file mode 100644
index 0000000000..bbe2de802f
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/drawable/ic_special_vehicle_minimality.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app_ipc_monitoring/src/main/res/drawable/ic_special_vehicle_minimality_true.xml b/app_ipc_monitoring/src/main/res/drawable/ic_special_vehicle_minimality_true.xml
new file mode 100644
index 0000000000..5c35a310b5
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/drawable/ic_special_vehicle_minimality_true.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app_ipc_monitoring/src/main/res/drawable/radio_btn_bg.xml b/app_ipc_monitoring/src/main/res/drawable/radio_btn_bg.xml
new file mode 100644
index 0000000000..31c702bcc5
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/drawable/radio_btn_bg.xml
@@ -0,0 +1,20 @@
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app_ipc_monitoring/src/main/res/drawable/selector_special_vehicle_back.xml b/app_ipc_monitoring/src/main/res/drawable/selector_special_vehicle_back.xml
new file mode 100644
index 0000000000..6adf0a241c
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/drawable/selector_special_vehicle_back.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app_ipc_monitoring/src/main/res/drawable/selector_special_vehicle_minimality.xml b/app_ipc_monitoring/src/main/res/drawable/selector_special_vehicle_minimality.xml
new file mode 100644
index 0000000000..f313d33d5a
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/drawable/selector_special_vehicle_minimality.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app_ipc_monitoring/src/main/res/layout/dialog_special_vehicle_config.xml b/app_ipc_monitoring/src/main/res/layout/dialog_special_vehicle_config.xml
new file mode 100644
index 0000000000..cf31149b2c
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/layout/dialog_special_vehicle_config.xml
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app_ipc_monitoring/src/main/res/layout/item_special_vehicle.xml b/app_ipc_monitoring/src/main/res/layout/item_special_vehicle.xml
new file mode 100644
index 0000000000..751bd9cf79
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/layout/item_special_vehicle.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app_ipc_monitoring/src/main/res/layout/item_special_vehicle_option_radio_btn.xml b/app_ipc_monitoring/src/main/res/layout/item_special_vehicle_option_radio_btn.xml
new file mode 100644
index 0000000000..ff589b4b0c
--- /dev/null
+++ b/app_ipc_monitoring/src/main/res/layout/item_special_vehicle_option_radio_btn.xml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/app_ipc_monitoring/src/main/res/values/styles.xml b/app_ipc_monitoring/src/main/res/values/styles.xml
index 71a18efd24..8b2a5ad784 100644
--- a/app_ipc_monitoring/src/main/res/values/styles.xml
+++ b/app_ipc_monitoring/src/main/res/values/styles.xml
@@ -31,4 +31,15 @@
+
+
diff --git a/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/MoGoAutopilotProvider.kt b/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/MoGoAutopilotProvider.kt
index 8647411a2f..5fc8dffe6f 100644
--- a/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/MoGoAutopilotProvider.kt
+++ b/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/MoGoAutopilotProvider.kt
@@ -3,6 +3,7 @@ package com.mogo.eagle.core.function.autopilot
import android.Manifest.permission
import android.content.Context
import androidx.annotation.RequiresPermission
+import chassis.SpecialVehicleTaskCmdOuterClass
import com.alibaba.android.arouter.facade.annotation.Route
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters
@@ -668,4 +669,9 @@ class MoGoAutopilotProvider :
override fun sendStatusQueryReq() {
AdasManager.getInstance().sendStatusQueryReq()
}
+
+ override fun sendSweeperFuTianTaskCmd(fuTianTaskCmd: SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd) {
+ Log.d(TAG, "---- sendSweeperFuTianTaskCmd ----")
+ AdasManager.getInstance().sendRoboSweeperFuTianTaskCmd(fuTianTaskCmd)
+ }
}
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoAdasListenerImpl.kt b/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoAdasListenerImpl.kt
index 0402c87379..f53c1f082b 100644
--- a/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoAdasListenerImpl.kt
+++ b/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoAdasListenerImpl.kt
@@ -166,7 +166,10 @@ class MoGoAdasListenerImpl : OnAdasListener {
CallerAutopilotVehicleStateListenerManager.invokeAutopilotThrottle(vehicleState.throttle)
//刹车
CallerAutopilotVehicleStateListenerManager.invokeAutopilotBrake(vehicleState.brake)
-
+ //清扫车(福田)清扫控制系统状态
+ vehicleState.sweeperFutianCleanSystemState?.also {
+ CallerAutopilotVehicleStateListenerManager.invokeSweeperFutianCleanSystemState(it)
+ }
} else {
CallerAutopilotVehicleStateListenerManager.invokeAutopilotDataException(header.timestamp.toLong())
}
diff --git a/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoAdasMsgConnectStatusListenerImpl.kt b/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoAdasMsgConnectStatusListenerImpl.kt
index 5f6ecf04f1..a9da4f3990 100644
--- a/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoAdasMsgConnectStatusListenerImpl.kt
+++ b/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoAdasMsgConnectStatusListenerImpl.kt
@@ -24,7 +24,7 @@ import com.zhidao.support.adas.high.common.Constants.TERMINAL_ROLE.DRIVER
import com.zhidao.support.adas.high.common.Constants.TERMINAL_ROLE.PASSENGER
import mogo.telematics.pad.MessagePad
import java.util.*
-import java.util.concurrent.atomic.*
+import java.util.concurrent.atomic.AtomicBoolean
/**
* ADAS-SDK与工控机连接状态回调
diff --git a/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoHandAdasMsgManager.java b/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoHandAdasMsgManager.java
index 413c2f3bdf..32530d996d 100644
--- a/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoHandAdasMsgManager.java
+++ b/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoHandAdasMsgManager.java
@@ -4,6 +4,7 @@ import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.mogo.cloud.passport.MoGoAiCloudClientConfig;
@@ -24,6 +25,7 @@ import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr;
import org.jetbrains.annotations.NotNull;
import chassis.Chassis;
+import chassis.VehicleStateOuterClass;
import mogo.telematics.pad.MessagePad;
public class MoGoHandAdasMsgManager implements
@@ -178,4 +180,9 @@ public class MoGoHandAdasMsgManager implements
}
+
+ @Override
+ public void onSweeperFutianCleanSystemState(VehicleStateOuterClass.SweeperFuTianCleanSystemState cleanSystemState) {
+
+ }
}
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/status/flow/can/CanImpl.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/status/flow/can/CanImpl.kt
index cfebc1ad24..c8b1ad4876 100644
--- a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/status/flow/can/CanImpl.kt
+++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/status/flow/can/CanImpl.kt
@@ -4,6 +4,7 @@ import android.content.*
import android.util.Log
import chassis.Chassis.GearPosition
import chassis.Chassis.LightSwitch
+import chassis.VehicleStateOuterClass
import com.mogo.eagle.core.function.api.autopilot.*
import com.mogo.eagle.core.function.call.autopilot.*
import com.mogo.eagle.core.utilcode.kotlin.*
@@ -81,6 +82,11 @@ internal class CanImpl(ctx: Context): IFlow(ctx), IMoGoAutopilotVehic
timeOutCheck()
}
+ override fun onSweeperFutianCleanSystemState(cleanSystemState: VehicleStateOuterClass.SweeperFuTianCleanSystemState) {
+ send(CanStatus(isCanEnabled()))
+ timeOutCheck()
+ }
+
override fun onAutopilotGuardian(guardianInfo: MogoReportMessage?) {
super.onAutopilotGuardian(guardianInfo)
send(CanStatus(isCanEnabled()))
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/DebugSettingView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/DebugSettingView.kt
index 9b8c6d67f0..e9af260e2d 100644
--- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/DebugSettingView.kt
+++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/DebugSettingView.kt
@@ -19,6 +19,7 @@ import androidx.core.content.ContextCompat
import androidx.core.view.*
import androidx.recyclerview.widget.LinearLayoutManager
import chassis.Chassis
+import chassis.VehicleStateOuterClass
import com.mogo.cloud.passport.MoGoAiCloudClient
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
import com.mogo.commons.debug.DebugConfig
@@ -2075,6 +2076,13 @@ class DebugSettingView @JvmOverloads constructor(
}
+ /**
+ * 清扫车(福田)清扫控制系统状态
+ */
+ override fun onSweeperFutianCleanSystemState(cleanSystemState: VehicleStateOuterClass.SweeperFuTianCleanSystemState) {
+
+ }
+
/**
* 吐司提示
*/
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/SteeringWheelView.java b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/SteeringWheelView.java
index 34f476121f..fbf8c38268 100644
--- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/SteeringWheelView.java
+++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/SteeringWheelView.java
@@ -27,6 +27,7 @@ import com.mogo.eagle.core.utilcode.util.ThreadUtils;
import org.jetbrains.annotations.NotNull;
import chassis.Chassis;
+import chassis.VehicleStateOuterClass;
import mogo.telematics.pad.MessagePad;
import mogo_msg.MogoReportMsg;
import system_master.SystemStatusInfo;
@@ -164,6 +165,10 @@ public class SteeringWheelView extends ConstraintLayout {
private final IMoGoAutopilotVehicleStateListener mIMoGoAutopilotVehicleStateListener = new IMoGoAutopilotVehicleStateListener() {
+ @Override
+ public void onSweeperFutianCleanSystemState(@NonNull VehicleStateOuterClass.SweeperFuTianCleanSystemState cleanSystemState) {
+ }
+
/**
* @param brake 刹车
*/
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/TrafficDataView.java b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/TrafficDataView.java
index dd21592b78..afa2fd8782 100644
--- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/TrafficDataView.java
+++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/TrafficDataView.java
@@ -26,6 +26,7 @@ import com.mogo.eagle.core.utilcode.util.ThreadUtils;
import org.jetbrains.annotations.NotNull;
import chassis.Chassis;
+import chassis.VehicleStateOuterClass;
import mogo.telematics.pad.MessagePad;
/**
@@ -122,6 +123,10 @@ public class TrafficDataView extends ConstraintLayout {
}
private final IMoGoAutopilotVehicleStateListener mIMoGoAutopilotVehicleStateListener = new IMoGoAutopilotVehicleStateListener() {
+ @Override
+ public void onSweeperFutianCleanSystemState(@NonNull VehicleStateOuterClass.SweeperFuTianCleanSystemState cleanSystemState) {
+ }
+
/**
* 车辆转向灯
* @param lightSwitch
diff --git a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotProvider.kt b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotProvider.kt
index 083e93fb7e..6f18eb5b73 100644
--- a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotProvider.kt
+++ b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotProvider.kt
@@ -1,5 +1,6 @@
package com.mogo.eagle.core.function.api.autopilot
+import chassis.SpecialVehicleTaskCmdOuterClass
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters
import com.mogo.eagle.core.data.trafficlight.TrafficLightResult
import com.mogo.eagle.core.function.api.base.IMoGoFunctionServerProvider
@@ -232,4 +233,9 @@ interface IMoGoAutopilotProvider : IMoGoFunctionServerProvider {
* 鸣笛 开始:1,结束:2
*/
fun sendOperatorSetHorn(value: Double)
+
+ /**
+ * 福田清扫车业务指令下发
+ */
+ fun sendSweeperFuTianTaskCmd(fuTianTaskCmd: SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd)
}
\ No newline at end of file
diff --git a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotVehicleStateListener.kt b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotVehicleStateListener.kt
index 75bde9e46f..bc80cc6fd9 100644
--- a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotVehicleStateListener.kt
+++ b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotVehicleStateListener.kt
@@ -1,7 +1,7 @@
package com.mogo.eagle.core.function.api.autopilot
import chassis.Chassis
-import mogo.telematics.pad.MessagePad
+import chassis.VehicleStateOuterClass
/**
* 车辆底盘 数据 回调监听
@@ -52,4 +52,9 @@ interface IMoGoAutopilotVehicleStateListener {
* 刹车
*/
fun onAutopilotBrake(brake: Float)
+
+ /**
+ * 清扫车(福田)清扫控制系统状态
+ */
+ fun onSweeperFutianCleanSystemState(cleanSystemState: VehicleStateOuterClass.SweeperFuTianCleanSystemState)
}
\ No newline at end of file
diff --git a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutoPilotManager.kt b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutoPilotManager.kt
index a941d04ea8..585eec1cbf 100644
--- a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutoPilotManager.kt
+++ b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutoPilotManager.kt
@@ -1,6 +1,7 @@
package com.mogo.eagle.core.function.call.autopilot
import android.os.SystemClock
+import chassis.SpecialVehicleTaskCmdOuterClass
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.data.constants.MogoServicePaths
@@ -346,4 +347,11 @@ object CallerAutoPilotManager {
fun sendStatusQueryReq() {
providerApi?.sendStatusQueryReq()
}
+
+ /**
+ * 福田清扫车业务指令下发
+ */
+ fun sendSweeperFuTianTaskCmd(fuTianTaskCmd: SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd) {
+ providerApi?.sendSweeperFuTianTaskCmd(fuTianTaskCmd)
+ }
}
\ No newline at end of file
diff --git a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutopilotVehicleStateListenerManager.kt b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutopilotVehicleStateListenerManager.kt
index df4cd2c638..a704804633 100644
--- a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutopilotVehicleStateListenerManager.kt
+++ b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutopilotVehicleStateListenerManager.kt
@@ -2,6 +2,7 @@ package com.mogo.eagle.core.function.call.autopilot
import androidx.annotation.Nullable
import chassis.Chassis
+import chassis.VehicleStateOuterClass
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotVehicleStateListener
import com.mogo.eagle.core.function.call.base.CallerBase
import mogo.telematics.pad.MessagePad
@@ -132,6 +133,16 @@ object CallerAutopilotVehicleStateListenerManager : CallerBase() {
}
}
+ /**
+ * clean system state 清扫车(福田)清扫控制系统状态
+ */
+ fun invokeSweeperFutianCleanSystemState(cleanSystemState: VehicleStateOuterClass.SweeperFuTianCleanSystemState){
+ M_AUTOPILOT_VEHICLE_LISTENERS.forEach{
+ val listener = it.value
+ listener.onSweeperFutianCleanSystemState(cleanSystemState)
+ }
+ }
+
/**
* 工控机时间回调
diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasChannel.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasChannel.java
index daa4366e6e..ca7c47622a 100644
--- a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasChannel.java
+++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasChannel.java
@@ -52,6 +52,8 @@ import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;
+import chassis.SpecialVehicleTaskCmdOuterClass;
+import common.HeaderOuterClass;
import mogo.telematics.pad.MessagePad;
import okio.ByteString;
@@ -75,6 +77,8 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec
private DispatchHandler defaultDispatchHandler;//默认分发线程分发
private final Map dispatchHandlers = new HashMap<>();//其他分发线程
private Timer checkCompatibilityTimer;//检查版本兼容性定时器 连接成功后5秒内等待工控机发送配置信息
+ private int seqSpecialVehicle = 0;//特种车辆命令发送次数
+
/**
* 与工控机链接状态
*/
@@ -472,6 +476,7 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec
ipcConnectedIp = ipAddress;
ipcConnectedPort = port;
subscribeInterface = new SubscribeInterface(this);
+ seqSpecialVehicle = 0;
updateConnectStatus(Constants.IPC_CONNECTION_STATUS.CONNECTED, "已连接");
//根据连接配置 进行接口订阅或取消订阅配置
if (adasOptions != null) {
@@ -1112,6 +1117,61 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec
return subscribeInterface != null && subscribeInterface.subscribeInterface(role, type, messageType);
}
+ /**
+ * 福田清扫车业务指令下发
+ *
+ * @param fuTianTaskCmd 命令
+ * @return boolean
+ */
+ @Override
+ public boolean sendRoboSweeperFuTianTaskCmd(SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd fuTianTaskCmd) {
+ SpecialVehicleTaskCmdOuterClass.SpecialVehicleTaskCmd.Builder cmdBuild = SpecialVehicleTaskCmdOuterClass.SpecialVehicleTaskCmd
+ .newBuilder()
+ .setRoboSweeperFutianTaskCmd(fuTianTaskCmd);
+ return sendSpecialVehicleTaskCmd(cmdBuild);
+ }
+
+ /**
+ * 开沃小巴业务指令下发
+ *
+ * @param vanSkywellTaskCmd 命令
+ * @return boolean
+ */
+ @Override
+ public boolean sendRoboVanSkywellTaskCmd(SpecialVehicleTaskCmdOuterClass.RoboVanSkywellTaskCmd vanSkywellTaskCmd) {
+ SpecialVehicleTaskCmdOuterClass.SpecialVehicleTaskCmd.Builder cmdBuild = SpecialVehicleTaskCmdOuterClass.SpecialVehicleTaskCmd
+ .newBuilder()
+ .setRoboVanSkywellTaskCmd(vanSkywellTaskCmd);
+ return sendSpecialVehicleTaskCmd(cmdBuild);
+ }
+
+ /**
+ * 特种车辆命令下发
+ *
+ * @param cmdBuild 命令
+ * @return boolean
+ */
+ @Override
+ public boolean sendSpecialVehicleTaskCmd(SpecialVehicleTaskCmdOuterClass.SpecialVehicleTaskCmd.Builder cmdBuild) {
+ long t = System.currentTimeMillis();
+ int sec = (int) (t / 1000);
+ int nsec = (int) (t % 1000 * 1000000);
+ HeaderOuterClass.Time time = HeaderOuterClass.Time
+ .newBuilder()
+ .setSec(sec)
+ .setNsec(nsec)
+ .build();
+ HeaderOuterClass.Header header = HeaderOuterClass.Header.newBuilder()
+ .setSeq(++seqSpecialVehicle)
+ .setStamp(time)
+ .setFrameId("special_vehicle_task_cmd")
+ .setModuleName("EagleEye")
+ .build();
+ cmdBuild.setHeader(header);
+ return sendPBMessage(MessageType.TYPE_SEND_SPECIAL_VEHICLE_TASK_CMD.typeCode, cmdBuild.build().toByteArray());
+ }
+
+
/**
* 向左变道
*
diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasManager.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasManager.java
index 35b0554b2e..e2e109d586 100644
--- a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasManager.java
+++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasManager.java
@@ -14,6 +14,7 @@ import com.zhidao.support.adas.high.common.ReceiveTimeoutManager;
import java.util.HashSet;
import java.util.Set;
+import chassis.SpecialVehicleTaskCmdOuterClass;
import mogo.telematics.pad.MessagePad;
/**
@@ -540,6 +541,40 @@ public class AdasManager implements IAdasNetCommApi {
return mChannel != null && mChannel.subscribeInterface(role, type, messageType);
}
+ /**
+ * 福田清扫车业务指令下发
+ *
+ * @param fuTianTaskCmd 命令
+ * @return boolean
+ */
+ @Override
+ public boolean sendRoboSweeperFuTianTaskCmd(SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd fuTianTaskCmd) {
+ return mChannel != null && mChannel.sendRoboSweeperFuTianTaskCmd(fuTianTaskCmd);
+ }
+
+ /**
+ * 开沃小巴业务指令下发
+ *
+ * @param vanSkywellTaskCmd 命令
+ * @return boolean
+ */
+ @Override
+ public boolean sendRoboVanSkywellTaskCmd(SpecialVehicleTaskCmdOuterClass.RoboVanSkywellTaskCmd vanSkywellTaskCmd) {
+ return mChannel != null && mChannel.sendRoboVanSkywellTaskCmd(vanSkywellTaskCmd);
+ }
+
+ /**
+ * 特种车辆命令下发
+ *
+ * @param cmdBuild 命令
+ * @return boolean
+ */
+ @Override
+ public boolean sendSpecialVehicleTaskCmd(SpecialVehicleTaskCmdOuterClass.SpecialVehicleTaskCmd.Builder cmdBuild) {
+ return mChannel != null && mChannel.sendSpecialVehicleTaskCmd(cmdBuild);
+ }
+
+
@Override
public boolean sendOperatorCmdChangeLaneLeft() {
return mChannel != null && mChannel.sendOperatorCmdChangeLaneLeft();
diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/IAdasNetCommApi.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/IAdasNetCommApi.java
index 6fc73c2beb..7165f68dc1 100644
--- a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/IAdasNetCommApi.java
+++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/IAdasNetCommApi.java
@@ -9,6 +9,7 @@ import com.zhidao.support.adas.high.common.MessageType;
import java.util.Set;
+import chassis.SpecialVehicleTaskCmdOuterClass;
import mogo.telematics.pad.MessagePad;
/**
@@ -275,6 +276,30 @@ public interface IAdasNetCommApi {
*/
boolean subscribeInterface(@Define.TerminalRole int role, @Define.SubscribeType int type, @NonNull MessageType messageType);
+ /**
+ * 福田清扫车业务指令下发
+ *
+ * @param fuTianTaskCmd 命令
+ * @return boolean
+ */
+ boolean sendRoboSweeperFuTianTaskCmd(SpecialVehicleTaskCmdOuterClass.RoboSweeperFuTianTaskCmd fuTianTaskCmd);
+
+ /**
+ * 开沃小巴业务指令下发
+ *
+ * @param vanSkywellTaskCmd 命令
+ * @return boolean
+ */
+ boolean sendRoboVanSkywellTaskCmd(SpecialVehicleTaskCmdOuterClass.RoboVanSkywellTaskCmd vanSkywellTaskCmd);
+
+ /**
+ * 特种车辆命令下发
+ *
+ * @param cmdBuild 命令
+ * @return boolean
+ */
+ boolean sendSpecialVehicleTaskCmd(SpecialVehicleTaskCmdOuterClass.SpecialVehicleTaskCmd.Builder cmdBuild);
+
/**
* 向左变道
diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/common/MessageType.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/common/MessageType.java
index 7fada1ae8e..6527e359a3 100644
--- a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/common/MessageType.java
+++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/common/MessageType.java
@@ -49,6 +49,7 @@ public enum MessageType {
TYPE_SEND_RECORD_DATA_CONFIG_REQ(MessagePad.MessageType.MsgTypeRecordDataConfigReq, "数据采集配置查询"),
TYPE_RECEIVE_RECORD_DATA_CONFIG_RESP(MessagePad.MessageType.MsgTypeRecordDataConfigResp, "数据采集配置"),
TYPE_SEND_SUBSCRIBE_DATA_REQ(MessagePad.MessageType.MsgTypeSubscribeDataReq, "数据订阅、取消订阅请求"),
+ TYPE_SEND_SPECIAL_VEHICLE_TASK_CMD(MessagePad.MessageType.MsgTypeSpecialVehicleTaskCmd, "特种车辆命令"),
//透传 原始pb文件中不存在以下type。由于Java中无法强转所以在mogo-adas-data message_pad.proto中放开注释
TYPE_RECEIVE_PLANNING_DECISION_STATE(MessagePad.MessageType.MsgTypePlanningDecisionState, "Planning决策状态");
diff --git a/settings.gradle b/settings.gradle
index 715ab2164c..f9f1930fd1 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -87,4 +87,4 @@ include ':OCH:mogo-och-taxi'
include ':OCH:mogo-och-taxi-passenger'
include ':OCH:mogo-och-noop'
include(':OCH:mogo-och-common-module')
-
+include ':OCH:mogo-och-sweeper'