diff --git a/OCH/sweeper/sweeper-cloud/.gitignore b/OCH/sweeper/sweeper-cloud/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/build.gradle b/OCH/sweeper/sweeper-cloud/build.gradle new file mode 100644 index 0000000000..30fb36674e --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/build.gradle @@ -0,0 +1,68 @@ +apply plugin: 'com.android.library' +apply plugin: 'com.alibaba.arouter' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion rootProject.ext.android.compileSdkVersion + // buildToolsVersion rootProject.ext.android.buildToolsVersion + defaultConfig { + minSdkVersion rootProject.ext.android.minSdkVersion + targetSdkVersion rootProject.ext.android.targetSdkVersion + versionCode Integer.valueOf(VERSION_CODE) + versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION") + + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + + javaCompileOptions { + annotationProcessorOptions { + arguments = [AROUTER_MODULE_NAME: project.getName(),"room.schemaLocation": "$projectDir/schemas".toString()] + } + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + lintOptions { + abortOnError false + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + debug { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation rootProject.ext.dependencies.kotlinstdlibjdk7 + implementation rootProject.ext.dependencies.androidxappcompat + implementation rootProject.ext.dependencies.arouter + annotationProcessor rootProject.ext.dependencies.aroutercompiler + implementation rootProject.ext.dependencies.androidxconstraintlayout + implementation rootProject.ext.dependencies.amapnavi3dmap + + implementation rootProject.ext.dependencies.rxjava + implementation rootProject.ext.dependencies.rxandroid + implementation rootProject.ext.dependencies.androidxrecyclerview + implementation rootProject.ext.dependencies.androidxcardview + implementation rootProject.ext.dependencies.androidxroomruntime + annotationProcessor rootProject.ext.dependencies.androidxroomcompiler + + implementation project(":OCH:mogo-och-common-module") + compileOnly project(":libraries:mogo-map") + +} + +apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString() \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/gradle.properties b/OCH/sweeper/sweeper-cloud/gradle.properties new file mode 100644 index 0000000000..6153f2df71 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/gradle.properties @@ -0,0 +1,3 @@ +GROUP=com.mogo.och +POM_ARTIFACT_ID=och-sweeper +VERSION_CODE=1 diff --git a/OCH/sweeper/sweeper-cloud/proguard-rules.pro b/OCH/sweeper/sweeper-cloud/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/schemas/com.mogo.och.sweeper.database.MyDataBase/1.json b/OCH/sweeper/sweeper-cloud/schemas/com.mogo.och.sweeper.database.MyDataBase/1.json new file mode 100644 index 0000000000..a9451322a4 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/schemas/com.mogo.och.sweeper.database.MyDataBase/1.json @@ -0,0 +1,86 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "0897ef4b7b6a43fccf8bcf4b2144dafa", + "entities": [ + { + "tableName": "welt_data_table", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `subTaskId` INTEGER NOT NULL, `locLon` REAL NOT NULL, `locLat` REAL NOT NULL, `weltDistance` REAL NOT NULL, `cleanMode` INTEGER NOT NULL, `cleanDirection` INTEGER NOT NULL, `cleanIntensity` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subTaskId", + "columnName": "subTaskId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "locLon", + "columnName": "locLon", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "locLat", + "columnName": "locLat", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "weltDistance", + "columnName": "weltDistance", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "cleanMode", + "columnName": "cleanMode", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "cleanDirection", + "columnName": "cleanDirection", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "cleanIntensity", + "columnName": "cleanIntensity", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_welt_data_table_id", + "unique": true, + "columnNames": [ + "id" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_welt_data_table_id` ON `${TABLE_NAME}` (`id`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '0897ef4b7b6a43fccf8bcf4b2144dafa')" + ] + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/androidTest/java/com/mogo/och/sweeper/ExampleInstrumentedTest.kt b/OCH/sweeper/sweeper-cloud/src/androidTest/java/com/mogo/och/sweeper/ExampleInstrumentedTest.kt new file mode 100644 index 0000000000..ccebc3709a --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/androidTest/java/com/mogo/och/sweeper/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.mogo.och.sweeper + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.mogo.och.sweeper", appContext.packageName) + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/AndroidManifest.xml b/OCH/sweeper/sweeper-cloud/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..c2a6c2cfeb --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/AndroidManifest.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/assets/map_style.data b/OCH/sweeper/sweeper-cloud/src/main/assets/map_style.data new file mode 100644 index 0000000000..b200669659 Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/assets/map_style.data differ diff --git a/OCH/sweeper/sweeper-cloud/src/main/assets/map_style_extra.data b/OCH/sweeper/sweeper-cloud/src/main/assets/map_style_extra.data new file mode 100644 index 0000000000..7aa8fa7b45 Binary files /dev/null and b/OCH/sweeper/sweeper-cloud/src/main/assets/map_style_extra.data differ diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/IMogoOCH.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/IMogoOCH.java new file mode 100644 index 0000000000..0f584c6b1d --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/IMogoOCH.java @@ -0,0 +1,24 @@ +package com.mogo.och.sweeper; + +import androidx.annotation.IdRes; +import androidx.fragment.app.FragmentActivity; + +import com.mogo.eagle.core.function.api.base.IMoGoFunctionProvider; + +public +/** + * @author congtaowang + * @since 2021/1/15 + * + * 网约车抽象接口 + */ +interface IMogoOCH extends IMoGoFunctionProvider { + + /** + * 初始化网约车容器 + * + * @param activity + * @param containerId 容器ID + */ + void createCoverage(FragmentActivity activity, @IdRes int containerId); +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/SweeperProvider.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/SweeperProvider.java new file mode 100644 index 0000000000..4691f4f95b --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/SweeperProvider.java @@ -0,0 +1,87 @@ +package com.mogo.och.sweeper; + + +import android.content.Context; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; + +import com.alibaba.android.arouter.facade.annotation.Route; +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; +import com.mogo.och.sweeper.constant.SweeperConst; +import com.mogo.och.sweeper.fragment.SweeperFragment; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * 清扫车业务实现入口 + * + * @author tongchenfei + */ +@Route(path = SweeperConst.PATH) +public class SweeperProvider implements IMogoOCH { + + private static final String TAG = "SweeperProvider"; + + private SweeperFragment sweeperFragment; + private int containerId; + private FragmentActivity activity; + + @Override + public void init(Context context) { + } + private void showFragment() { + FragmentManager supportFragmentManager = activity.getSupportFragmentManager(); + if (sweeperFragment == null) { + CallerLogger.INSTANCE.d(TAG, "准备add fragment======"); + Fragment fragmentByTag = supportFragmentManager.findFragmentByTag(sweeperFragment.TAG); + if (fragmentByTag instanceof SweeperFragment) { + sweeperFragment = (SweeperFragment) fragmentByTag; + } else { + sweeperFragment = new SweeperFragment(); + } + if(!sweeperFragment.isAdded()) { + supportFragmentManager.beginTransaction().add(containerId, sweeperFragment, sweeperFragment.TAG).commitAllowingStateLoss(); + } + return; + } + CallerLogger.INSTANCE.d(TAG, "准备show fragment"); + supportFragmentManager.beginTransaction().show(sweeperFragment).commitAllowingStateLoss(); + } + private void hideFragment() { + if (sweeperFragment != null) { + CallerLogger.INSTANCE.d(TAG, "准备hide fragment"); + activity.getSupportFragmentManager().beginTransaction().hide(sweeperFragment).commitAllowingStateLoss(); + } + + } + + @Override + public void createCoverage(FragmentActivity activity, int containerId) { + + } + + @NotNull + @Override + public String getFunctionName() { + return null; + } + + @Nullable + @Override + public Fragment createCoverage(@Nullable FragmentActivity fragmentActivity, @Nullable Integer integer) { + this.containerId = integer; + this.activity = fragmentActivity; + showFragment(); + return null; + } + + @Override + public void onDestroy() { + //若不调用finish, 设置中打开关闭UITouch,会造成och fragment 重叠 + if (activity == null) return; + activity.finish(); + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/BaseResponse.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/BaseResponse.java new file mode 100644 index 0000000000..d13c872662 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/BaseResponse.java @@ -0,0 +1,31 @@ +package com.mogo.och.sweeper.bean; + +import com.mogo.eagle.core.data.BaseData; + +public class BaseResponse extends BaseData { + private T data; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SubStartRequest.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SubStartRequest.kt new file mode 100644 index 0000000000..f0793a69a5 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SubStartRequest.kt @@ -0,0 +1,11 @@ +package com.mogo.och.sweeper.bean + +import com.mogo.cloud.passport.MoGoAiCloudClientConfig + +data class SubStartRequest( + var carSn:String=MoGoAiCloudClientConfig.getInstance().sn, + var taskId:Int, + var startTime:Long, + var isFirst:Boolean, + var isEnd:Boolean + ) \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SweeperMainTaskBean.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SweeperMainTaskBean.kt new file mode 100644 index 0000000000..ccb548653a --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SweeperMainTaskBean.kt @@ -0,0 +1,14 @@ +package com.mogo.och.sweeper.bean + +/** + * + * 清扫车任务信息 + * + * @author tongchenfei + */ +data class SweeperMainTaskBean( + var mainTaskId:Int = 0, + var mainTaskName: String? = null, + var subTaskTotal:Int = 0, + var mainTaskStartTime: Long = 0 + ) \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SweeperRoutePlanningUpdateReqBean.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SweeperRoutePlanningUpdateReqBean.java new file mode 100644 index 0000000000..32fcf73e48 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SweeperRoutePlanningUpdateReqBean.java @@ -0,0 +1,32 @@ +package com.mogo.och.sweeper.bean; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by pangfan on 2021/8/19 + * + * 订单状态更新请求数据结构 + */ +public class SweeperRoutePlanningUpdateReqBean implements Serializable { + public String sn; + public int lineId; + public int startSiteId; + public int endSiteId; + public ArrayList points; + + public static class Result implements Serializable{ + public Double latitude; + public Double longitude; + } + + public SweeperRoutePlanningUpdateReqBean(String sn, int lineId, int startSiteId + , int endSiteId, ArrayList points) { + this.sn = sn; + this.lineId = lineId; + this.startSiteId = startSiteId; + this.endSiteId = endSiteId; + this.points = points; + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SweeperSubTaskBean.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SweeperSubTaskBean.kt new file mode 100644 index 0000000000..63ce688454 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SweeperSubTaskBean.kt @@ -0,0 +1,28 @@ +package com.mogo.och.sweeper.bean + +/** + * 子任务信息 + */ +data class SweeperSubTaskBean( + var taskId: Int = 0, + var taskName: String?, + var taskStartTime: Long = 0, + var sort: Int = 1, + var subList: MutableList? +) + +data class SubInfo( + var taskId: Int = 0, + var taskName: String?, + var mileage: Int = 0, + var taskStatus: Int,// 状态1未执行 2执行中 3结束 4跳过 + var taskType: Int,//1自动驾驶 2人工驾驶 + var timeSpent: String, + var startSiteName: String,//起点名称 + var startWgs84Lon: Double,//起点经度 + var startWgs84Lat: Double,//起点纬度 + var endSiteName: String,//终点名称 + var endWgs84Lon: Double,//终点经度 + var endWgs84Lat: Double,//终点纬度 + var sort: Int = 0, +) \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SweeperSubTaskDetailBean.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SweeperSubTaskDetailBean.java new file mode 100644 index 0000000000..c21229a738 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/bean/SweeperSubTaskDetailBean.java @@ -0,0 +1,314 @@ +package com.mogo.och.sweeper.bean; + +public class SweeperSubTaskDetailBean { + private int id; //子任务id + private int lineId; //线路id + private String lineName;//线路名称 + private int sort; + private int status; + private int startSiteId; //子任务起点id + private String startSiteName; //子任务起点名称 + private double startSiteLon; //子任务起点高德经度 + private double startSiteLat; //子任务起点高德纬度 + private double startSiteWgs64Lon;//子任务起点高精经度 + private double startSiteWgs64Lat;//子任务起点高精纬度 + private int endSiteId;//子任务终点id + private String endSiteName;//子任务终点名称 + private double endSiteLon; //子任务终点高德经度 + private double endSiteLat;//子任务终点高德纬度 + private double endSiteWgs64Lon;//子任务终点高精经度 + private double endSiteWgs64Lat;//子任务终点高精纬度 + private String brand; //品牌 + private String carModel; //车辆型号 + private String csvFileUrl = ""; //轨迹文件csv文件url地址 + private String csvFileMd5 = ""; //轨迹文件csv md5 + private String csvFileName = "";//轨迹文件cvs名称 + private String txtFileUrl = ""; //轨迹文件txt url地址 + private String txtFileMd5 = ""; //轨迹文件txt md5 + private String txtFileName; //轨迹文件txt名称 + private long publishTime; + private String contrailFileType; //轨迹文件类型 + private String publishStatus;//发布状态 1发布 2未发布 3 发布中 + private String csvFileUrlDPQP = ""; //轨迹文件下载的cos url,默认“” + private String csvFileMd5DPQP = ""; //轨迹文件md5,默认“” + private String txtFileUrlDPQP = ""; //打点文件下载的cos url,默认“” + private String txtFileMd5DPQP = ""; //轨迹文件md5,默认“” + private long publishTimeDPQP; //上传轨迹完成时间戳ms:用于MEC本地手动导入轨迹验证时不会被云端轨迹覆盖 + private long taskCreateTime; + private String brandDPQP; + private String carModelDPQP; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getLineId() { + return lineId; + } + + public void setLineId(int lineId) { + this.lineId = lineId; + } + + public String getLineName() { + return lineName; + } + + public void setLineName(String lineName) { + this.lineName = lineName; + } + + public int getSort() { + return sort; + } + + public void setSort(int sort) { + this.sort = sort; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public int getStartSiteId() { + return startSiteId; + } + + public void setStartSiteId(int startSiteId) { + this.startSiteId = startSiteId; + } + + public String getStartSiteName() { + return startSiteName; + } + + public void setStartSiteName(String startSiteName) { + this.startSiteName = startSiteName; + } + + public double getStartSiteLon() { + return startSiteLon; + } + + public void setStartSiteLon(double startSiteLon) { + this.startSiteLon = startSiteLon; + } + + public double getStartSiteLat() { + return startSiteLat; + } + + public void setStartSiteLat(double startSiteLat) { + this.startSiteLat = startSiteLat; + } + + public double getStartSiteWgs64Lon() { + return startSiteWgs64Lon; + } + + public void setStartSiteWgs64Lon(double startSiteWgs64Lon) { + this.startSiteWgs64Lon = startSiteWgs64Lon; + } + + public double getStartSiteWgs64Lat() { + return startSiteWgs64Lat; + } + + public void setStartSiteWgs64Lat(double startSiteWgs64Lat) { + this.startSiteWgs64Lat = startSiteWgs64Lat; + } + + public int getEndSiteId() { + return endSiteId; + } + + public void setEndSiteId(int endSiteId) { + this.endSiteId = endSiteId; + } + + public String getEndSiteName() { + return endSiteName; + } + + public void setEndSiteName(String endSiteName) { + this.endSiteName = endSiteName; + } + + public double getEndSiteLon() { + return endSiteLon; + } + + public void setEndSiteLon(double endSiteLon) { + this.endSiteLon = endSiteLon; + } + + public double getEndSiteLat() { + return endSiteLat; + } + + public void setEndSiteLat(double endSiteLat) { + this.endSiteLat = endSiteLat; + } + + public double getEndSiteWgs64Lon() { + return endSiteWgs64Lon; + } + + public void setEndSiteWgs64Lon(double endSiteWgs64Lon) { + this.endSiteWgs64Lon = endSiteWgs64Lon; + } + + public double getEndSiteWgs64Lat() { + return endSiteWgs64Lat; + } + + public void setEndSiteWgs64Lat(double endSiteWgs64Lat) { + this.endSiteWgs64Lat = endSiteWgs64Lat; + } + + public long getTaskCreateTime() { + return taskCreateTime; + } + + public void setTaskCreateTime(long taskCreateTime) { + this.taskCreateTime = taskCreateTime; + } + + public String getBrand() { + return brand; + } + + public void setBrand(String brand) { + this.brand = brand; + } + + public String getCarModel() { + return carModel; + } + + public void setCarModel(String carModel) { + this.carModel = carModel; + } + + public String getCsvFileUrl() { + return csvFileUrl; + } + + public void setCsvFileUrl(String csvFileUrl) { + this.csvFileUrl = csvFileUrl; + } + + public String getCsvFileMd5() { + return csvFileMd5; + } + + public void setCsvFileMd5(String csvFileMd5) { + this.csvFileMd5 = csvFileMd5; + } + + public String getCsvFileName() { + return csvFileName; + } + + public void setCsvFileName(String csvFileName) { + this.csvFileName = csvFileName; + } + + public String getTxtFileUrl() { + return txtFileUrl; + } + + public void setTxtFileUrl(String txtFileUrl) { + this.txtFileUrl = txtFileUrl; + } + + public String getTxtFileMd5() { + return txtFileMd5; + } + + public void setTxtFileMd5(String txtFileMd5) { + this.txtFileMd5 = txtFileMd5; + } + + public String getTxtFileName() { + return txtFileName; + } + + public void setTxtFileName(String txtFileName) { + this.txtFileName = txtFileName; + } + + public long getPublishTime() { + return publishTime; + } + + public void setPublishTime(long publishTime) { + this.publishTime = publishTime; + } + + public String getBrandDPQP() { + return brandDPQP; + } + + public void setBrandDPQP(String brandDPQP) { + this.brandDPQP = brandDPQP; + } + + public String getCarModelDPQP() { + return carModelDPQP; + } + + public void setCarModelDPQP(String carModelDPQP) { + this.carModelDPQP = carModelDPQP; + } + + public String getCsvFileUrlDPQP() { + return csvFileUrlDPQP; + } + + public void setCsvFileUrlDPQP(String csvFileUrlDPQP) { + this.csvFileUrlDPQP = csvFileUrlDPQP; + } + + public String getCsvFileMd5DPQP() { + return csvFileMd5DPQP; + } + + public void setCsvFileMd5DPQP(String csvFileMd5DPQP) { + this.csvFileMd5DPQP = csvFileMd5DPQP; + } + + public String getTxtFileUrlDPQP() { + return txtFileUrlDPQP; + } + + public void setTxtFileUrlDPQP(String txtFileUrlDPQP) { + this.txtFileUrlDPQP = txtFileUrlDPQP; + } + + public String getTxtFileMd5DPQP() { + return txtFileMd5DPQP; + } + + public void setTxtFileMd5DPQP(String txtFileMd5DPQP) { + this.txtFileMd5DPQP = txtFileMd5DPQP; + } + + public long getPublishTimeDPQP() { + return publishTimeDPQP; + } + + public void setPublishTimeDPQP(long publishTimeDPQP) { + this.publishTimeDPQP = publishTimeDPQP; + } + + +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ICleaningModeStateCallback.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ICleaningModeStateCallback.java new file mode 100644 index 0000000000..df0ed8bc1d --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ICleaningModeStateCallback.java @@ -0,0 +1,12 @@ +package com.mogo.och.sweeper.callback; + +import com.mogo.och.sweeper.constant.OperateStateEnum; + +import chassis.ChassisStatesOuterClass; + +/** + * 上装状态回调 + */ +public interface ICleaningModeStateCallback { + void cleaningModeState(OperateStateEnum cleaningModeState, ChassisStatesOuterClass.SweeperFuTianTaskSystemStates cleanSystemState,boolean isSelectPureSweepMode); +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperADASStatusCallback.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperADASStatusCallback.java new file mode 100644 index 0000000000..995e1723af --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperADASStatusCallback.java @@ -0,0 +1,11 @@ +package com.mogo.och.sweeper.callback; + +/** + * Created on 2021/9/8 + * + * Model->Presenter回调:ADAS相关(自动驾驶状态回调,到达终点等等) + */ +public interface ISweeperADASStatusCallback { + //自驾返回失败 + void onStartAdasFailure(); +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperControllerStatusCallback.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperControllerStatusCallback.java new file mode 100644 index 0000000000..7a831a7c0e --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperControllerStatusCallback.java @@ -0,0 +1,17 @@ +package com.mogo.och.sweeper.callback; + +import com.mogo.eagle.core.data.map.MogoLocation; + +/** + * Created on 2021/9/10 + * + * Model->Presenter回调:状态控制器监听(accOn、adas ui show、voice ui show、push ui show、v2x ui show等等) + */ +public interface ISweeperControllerStatusCallback { + // 是否vr map模式 + void onVRModeChanged(boolean isVRMode); + // 自车定位 + void onCarLocationChanged(MogoLocation location); + //开始开启自动驾驶 + void startOpenAutopilot(); +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperTaskCallback.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperTaskCallback.kt new file mode 100644 index 0000000000..377eb91145 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperTaskCallback.kt @@ -0,0 +1,46 @@ +package com.mogo.och.sweeper.callback + +import com.mogo.och.sweeper.bean.SweeperMainTaskBean +import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean +import com.mogo.och.sweeper.bean.SweeperSubTaskBean +import com.mogo.och.sweeper.bean.SweeperSubTaskDetailBean +import com.mogo.och.sweeper.constant.SubTaskTypeEnum +import com.mogo.och.sweeper.constant.TaskStatusEnum +import java.util.ArrayList + +/** + * @author: wangmingjun + * @date: 2021/10/22 + */ +interface ISweeperTaskCallback { + /** + * 获取主任务列表 + */ + fun setMainTaskList(mainTaskBeanList: MutableList?,refresh:Boolean) + + /** + * 获取子任务列表 + */ + fun setSubTaskBean(subTaskBean: SweeperSubTaskBean,isWorkingSubTask:Boolean) + + /** + * 更新子任务状态 + */ + fun updateSubTaskStatus(typeEnum: TaskStatusEnum, isLastSubTask: Boolean) + + /** + * 主任务重置 + */ + fun setMainTaskReset(isSuccess: Boolean) + + /** + * 获取子任务详情包括轨迹信息 + */ + fun setSubTakDetail(subTaskDetailBean: SweeperSubTaskDetailBean, subTaskTypeEnum: SubTaskTypeEnum) + + /** + * 设置轨迹坐标点集合 + */ + fun setRouteList(routeList: ArrayList) + +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperTaskDataToFragmentCallback.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperTaskDataToFragmentCallback.kt new file mode 100644 index 0000000000..2677042385 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperTaskDataToFragmentCallback.kt @@ -0,0 +1,15 @@ +package com.mogo.och.sweeper.callback + +import com.amap.api.maps.model.LatLng +import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean +import com.mogo.och.sweeper.database.bean.WeltDataBean +import java.util.ArrayList + +interface ISweeperTaskDataToFragmentCallback { + fun setRouteList(routeList: ArrayList) + fun setWeltData(weltDatas: ArrayList?, distance: String) + fun clearAllMarkerAndPolyline() + fun setProgress(progress:String) + fun setTaskListCoordinatesLatLng(coordinatesLatLng: ArrayList) + fun setCurrentTaskCoordinatesLatLng(coordinatesLatLng: LatLng) +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperTaskRouteCallback.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperTaskRouteCallback.kt new file mode 100644 index 0000000000..5711c8e6ab --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/ISweeperTaskRouteCallback.kt @@ -0,0 +1,8 @@ +package com.mogo.och.sweeper.callback + +import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean +import java.util.ArrayList + +interface ISweeperTaskRouteCallback { + fun setRouteList(routeList:ArrayList) +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/IWeltMapSwitchToSmallCallback.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/IWeltMapSwitchToSmallCallback.kt new file mode 100644 index 0000000000..1b3e66bfe7 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/callback/IWeltMapSwitchToSmallCallback.kt @@ -0,0 +1,5 @@ +package com.mogo.och.sweeper.callback + +interface IWeltMapSwitchToSmallCallback { + fun onWeltMapSwitchToSmall() +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/constant/OperateStateEnum.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/constant/OperateStateEnum.kt new file mode 100644 index 0000000000..fcb68755ba --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/constant/OperateStateEnum.kt @@ -0,0 +1,12 @@ +package com.mogo.och.sweeper.constant + +/** + * 上装面板操作状态 + */ +enum class OperateStateEnum(val code: Int) { + SYNCING_STATUS( 1),//清扫车底盘状态同步中 + STARTING_STATUS( 2),//上装中 + FAIL_STATUS( 3),//上装失败 + SUCCESS_STATUS(4),//上装成功 + NO_STATUS(-1);//暂无模式 +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/constant/SubTaskTypeEnum.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/constant/SubTaskTypeEnum.kt new file mode 100644 index 0000000000..9946b8b2ef --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/constant/SubTaskTypeEnum.kt @@ -0,0 +1,9 @@ +package com.mogo.och.sweeper.constant + +/** + * 任务类型 + */ +enum class SubTaskTypeEnum(val code: Int) { + AUTOPILOT_SUBTYPE(1),//自动驾驶子任务 + MANUAL_DRIVING_SUBTYPE(2),//人工驾驶 +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/constant/SweeperConst.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/constant/SweeperConst.kt new file mode 100644 index 0000000000..66b5ee3f23 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/constant/SweeperConst.kt @@ -0,0 +1,70 @@ +package com.mogo.och.sweeper.constant + +import com.mogo.commons.debug.DebugConfig + +/** + * Created on 2021/12/6 + */ +class SweeperConst { + companion object { + + // OCH arouter 路由path + const val PATH = "/driver/api" + + // 测试用的广播 + const val BROADCAST_TEST_SWEEPER_CONTROL_TYPE_EXTRA_KEY = "sceneType" + + // 上报心跳轮询ms + const val LOOP_PERIOD_60S = 60 * 1000L + + // 开始服务启动自动驾驶等待时间(埋点上传) + const val LOOP_PERIOD_15S = 15 * 1000L + const val LOOP_PERIOD_1S = 1 * 1000L + const val LOOP_DELAY = 100L + + // 下发给MEC轨迹信息间隔时间 10秒 + const val LOOP_PERIOD_10S = 10 * 1000L + + // 尝试下发给MEC轨迹最多10次 + const val LOOP_SEND_TRAJ_TIMES = 10 + + //起点UUID + const val SWEEPER_START_MAP_MAKER = "sweeper_start_map_maker"; + + //终点UUID + const val SWEEPER_END_MAP_MAKER = "sweeper_end_map_maker"; + + // 埋点key:接管后点击'自动驾驶'按钮启动 + const val EVENT_KEY_RESTART_AUTOPILOT = "event_key_och_sweeper_restart_autopilot" + + // 埋点key:开始服务开启自动驾驶(成功/失败) + const val EVENT_KEY_START_SERVICE = "event_key_och_sweeper_start_service" + const val EVENT_PARAM_SN = "sn" + const val EVENT_PARAM_TIME = "time" + const val EVENT_PARAM_START_NAME = "start_name" + const val EVENT_PARAM_END_NAME = "end_name" + const val EVENT_PARAM_LINE_ID = "line_id" + const val EVENT_PARAM_START_RESULT = "start_autopilot" // true/false + const val EVENT_PARAM_START_FAILURE_CODE = "start_autopilot_failure_code" // 启动自驾失败code + const val EVENT_PARAM_START_FAILURE_MSG = "start_autopilot_failure_msg" // 启动自驾失败原因 + const val EVENT_PARAM_PLATE_NUM = "plate_number" // 车牌号 + const val EVENT_PARAM_ENV_ONLINE = "env_online" // 是否线上环境:true/false + + // 埋点key:开启自动驾驶前已识别的异常,会导致无法开启自驾 + const val EVENT_KEY_AP_UNABLE_START_REASON = "event_key_och_bus_ap_unable_start_reason" + const val EVENT_PARAM_UNABLE_START_REASON = "unable_start_reason"; + + /** + * 订单起终点Marker类型 + */ + const val TYPE_MARKER_SWEEPER_ORDER = "TYPE_MARKER_SWEEPER_ORDER" + + const val TIMER_START_AUTOPILOT_INTERVAL = 20 * 1000L + + //围栏到站 暂定10米 + const val ARRIVE_AT_END_STATION_DISTANCE = 10 + + //非贴边 + const val NONWELT = -10000.0 + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/constant/TaskStatusEnum.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/constant/TaskStatusEnum.kt new file mode 100644 index 0000000000..5d9fd9839a --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/constant/TaskStatusEnum.kt @@ -0,0 +1,12 @@ +package com.mogo.och.sweeper.constant + +/** + * 当前任务操作菜单 + */ +enum class TaskStatusEnum(val code: Int) { + JUMP_OVER_SUBTASK( 1),//跳过子任务 + END_TASK( 2),//结束主任务 + CANCEL_TASK( 3),//取消 + START_SUBTASK(4),//开始子任务 + END_SUBTASK(5),//结束子任务 +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/database/MyDataBase.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/database/MyDataBase.java new file mode 100644 index 0000000000..69b363a9b8 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/database/MyDataBase.java @@ -0,0 +1,29 @@ +package com.mogo.och.sweeper.database; + +import com.mogo.commons.AbsMogoApplication; +import com.mogo.och.sweeper.database.bean.WeltDataBean; +import com.mogo.och.sweeper.database.dao.WeltDataDao; + +import androidx.room.Database; +import androidx.room.Room; +import androidx.room.RoomDatabase; + +//注解Database告诉系统这是Room数据库对象 +//entities指定该数据库有哪些表,多张表就逗号分隔 +//version指定数据库版本号,升级时需要用到 +//数据库继承自RoomDatabase +@Database(entities = {WeltDataBean.class}, version = 1) +public abstract class MyDataBase extends RoomDatabase { + private static final String DATABASE_NAME = "weltData_db"; + + //结合单例模式完成数据库实例创建 + public static MyDataBase getInstance() { + return SingleTon.instance; + } + + private static class SingleTon { + private static final MyDataBase instance = + Room.databaseBuilder(AbsMogoApplication.getApp().getApplicationContext(), MyDataBase.class, DATABASE_NAME).build(); + } + public abstract WeltDataDao getWeltDataDao(); +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/database/bean/WeltDataBean.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/database/bean/WeltDataBean.java new file mode 100644 index 0000000000..cee66c7e53 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/database/bean/WeltDataBean.java @@ -0,0 +1,127 @@ +package com.mogo.och.sweeper.database.bean; + +import java.io.Serializable; + +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.Index; +import androidx.room.PrimaryKey; + +@Entity(tableName = WeltDataBean.WeltDataTable, indices = {@Index(value = "id", unique = true)}) +public class WeltDataBean implements Serializable { + + public static final String WeltDataTable = "welt_data_table"; + //ColumnInfo用于指定该字段存储在表中的名字,并指定类型 + + @PrimaryKey(autoGenerate = true) + + @ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER) + + private int id; + + @ColumnInfo(name = "subTaskId", typeAffinity = ColumnInfo.INTEGER)//子任务id + + private int subTaskId; + + @ColumnInfo(name = "locLon", typeAffinity = ColumnInfo.REAL) + + private double locLon;//自车RTK定位经度 + + @ColumnInfo(name = "locLat", typeAffinity = ColumnInfo.REAL) + + private double locLat;//自车RTK定位纬度 + + @ColumnInfo(name = "weltDistance", typeAffinity = ColumnInfo.REAL) + + private double weltDistance;//贴边距离 + + @ColumnInfo(name = "cleanMode", typeAffinity = ColumnInfo.INTEGER) + + private int cleanMode;//清扫作业模式 1–纯扫 2--洗扫, 3--纯洗, 4--纯吸 + + @ColumnInfo(name = "cleanDirection", typeAffinity = ColumnInfo.INTEGER) + + private int cleanDirection;//清扫方向 1--两侧, 2--左侧, 3--右侧 + + @ColumnInfo(name = "cleanIntensity", typeAffinity = ColumnInfo.INTEGER) + + private int cleanIntensity;//清扫强度 1--两侧, 2--左侧, 3--右侧 + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getSubTaskId() { + return subTaskId; + } + + public void setSubTaskId(int subTaskId) { + this.subTaskId = subTaskId; + } + + public double getLocLon() { + return locLon; + } + + public void setLocLon(double locLon) { + this.locLon = locLon; + } + + public double getLocLat() { + return locLat; + } + + public void setLocLat(double locLat) { + this.locLat = locLat; + } + + public double getWeltDistance() { + return weltDistance; + } + + public void setWeltDistance(double weltDistance) { + this.weltDistance = weltDistance; + } + + public int getCleanMode() { + return cleanMode; + } + + public void setCleanMode(int cleanMode) { + this.cleanMode = cleanMode; + } + + public int getCleanDirection() { + return cleanDirection; + } + + public void setCleanDirection(int cleanDirection) { + this.cleanDirection = cleanDirection; + } + + public int getCleanIntensity() { + return cleanIntensity; + } + + public void setCleanIntensity(int cleanIntensity) { + this.cleanIntensity = cleanIntensity; + } + + @Override + public String toString() { + return "WeltDataBean{" + + "id=" + id + + ", subTaskId='" + subTaskId + '\'' + + ", locLon=" + locLon + + ", locLat=" + locLat + + ", weltDistance=" + weltDistance + + ", cleanMode=" + cleanMode + + ", cleanDirection=" + cleanDirection + + ", cleanIntensity=" + cleanIntensity + + '}'; + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/database/dao/WeltDataDao.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/database/dao/WeltDataDao.java new file mode 100644 index 0000000000..097be3af3e --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/database/dao/WeltDataDao.java @@ -0,0 +1,27 @@ +package com.mogo.och.sweeper.database.dao; + +import com.mogo.och.sweeper.database.bean.WeltDataBean; + +import java.util.List; + +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; + +import static com.mogo.och.sweeper.database.bean.WeltDataBean.WeltDataTable; + +@Dao +public interface WeltDataDao { + //插入数据 + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insert(WeltDataBean fileInfo); + + //删除所有数据 + @Query("DELETE FROM " + WeltDataTable) + int deleteAllWeltData(); + + //查询所有数据 + @Query("SELECT * FROM " + WeltDataTable) + List loadAllWeltDataInfo(); +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/event/WeltDataEvent.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/event/WeltDataEvent.java new file mode 100644 index 0000000000..f294bae32a --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/event/WeltDataEvent.java @@ -0,0 +1,58 @@ +package com.mogo.och.sweeper.event; + +import com.amap.api.maps.model.LatLng; +import com.mogo.och.sweeper.database.bean.WeltDataBean; + +import java.util.ArrayList; + +public class WeltDataEvent{ + private int type; //1.添加起点和终点 2.实时添加贴边数据 3.清除数据 4.任务进度 5:任务轨迹数据 + private ArrayList weltDataBeanList; + private ArrayList markers; + private String distance;//贴边数据 + private String progress;//任务进度 + + public WeltDataEvent(int type) { + this.type = type; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public ArrayList getWeltDataBeanList() { + return weltDataBeanList; + } + + public void setWeltDataBeanList(ArrayList weltDataBeanList) { + this.weltDataBeanList = weltDataBeanList; + } + + public ArrayList getMarkers() { + return markers; + } + + public void setMarkers(ArrayList markers) { + this.markers = markers; + } + + public String getDistance() { + return distance; + } + + public void setDistance(String distance) { + this.distance = distance; + } + + public String getProgress() { + return progress; + } + + public void setProgress(String progress) { + this.progress = progress; + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperTabFragment.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperTabFragment.java new file mode 100644 index 0000000000..5832c58081 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperTabFragment.java @@ -0,0 +1,604 @@ +package com.mogo.och.sweeper.fragment; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.amap.api.maps.model.LatLng; +import com.amap.api.navi.model.NaviLatLng; +import com.mogo.commons.AbsMogoApplication; +import com.mogo.commons.mvp.IView; +import com.mogo.commons.mvp.MvpFragment; +import com.mogo.commons.mvp.Presenter; +import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; +import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotRecordListenerManager; +import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager; +import com.mogo.eagle.core.function.call.hmi.CallerHmiManager; +import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager; +import com.mogo.eagle.core.function.hmi.ui.msgbox.DriverMsgBoxBubbleView; +import com.mogo.eagle.core.function.hmi.ui.msgbox.DriverMsgBoxButtonView; +import com.mogo.eagle.core.function.hmi.ui.msgbox.DriverMsgBoxListView; +import com.mogo.eagle.core.function.view.MapBizView; +import com.mogo.eagle.core.utilcode.mogo.view.OnPreventFastClickListener; +import com.mogo.eagle.core.utilcode.util.ThreadUtils; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; +import com.mogo.map.listener.IMogoMapListener; +import com.mogo.map.listener.MogoMapListenerHandler; +import com.mogo.map.marker.IMogoMarkerManager; +import com.mogo.map.uicontroller.IMogoMapUIController; +import com.mogo.map.uicontroller.VisualAngleMode; +import com.mogo.och.common.module.map.AmapNaviToDestinationModel; +import com.mogo.och.sweeper.R; +import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean; +import com.mogo.och.sweeper.callback.ISweeperTaskDataToFragmentCallback; +import com.mogo.och.sweeper.callback.IWeltMapSwitchToSmallCallback; +import com.mogo.och.sweeper.database.bean.WeltDataBean; +import com.mogo.och.sweeper.view.SweeperTrafficDataView; +import com.mogo.och.sweeper.view.WeltSmallMapView; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.constraintlayout.widget.Group; +import androidx.fragment.app.FragmentTransaction; + +/** + * 网约车基础Fragment,主要负责布局通用界面,处理站点面板和通话面板互斥情况 + *

+ * 部分业务放在了此处处理 + * + * @author tongchenfei + */ +public abstract class BaseSweeperTabFragment> extends MvpFragment implements IMogoMapListener, + View.OnClickListener, IWeltMapSwitchToSmallCallback, View.OnTouchListener { + + private static final String TAG = "BaseSweeperTabFragment"; + //地图放大缩小 + private ImageView mSwitchMapModeImage; + //设置信息面板 + protected ImageView mSettingBtn; + //安全员问题上报面板 + protected ImageView mCardBtn; + //道路状况上报面板 + protected ImageView mAICollectBtn; + //任务列表面板 + private FrameLayout flTaskListPanelContainer; + private MapBizView mapBizView; + private Group groupTestPanel; + //清扫车车辆基本信息 速度 档位 转向灯 红绿灯等 + private SweeperTrafficDataView mTrafficDataView; + //人工驾驶地图View组控制 + private Group mGroupNaviPanel; + //人工驾驶地图Fragment + private SweeperAmapNaviFragment mOchAmapNaviFragment; + //关闭人工驾驶小地图 + private ImageView mCloseNavIcon; + //刷新人工驾驶地图按钮 + private ImageView mRefreshNavi; + //作业任务贴边数据展示图 + private WeltSmallMapView mMapWeltView; + //任务作业全览图 + private WeltMapOverViewFragment mWeltMapOverViewFragment; + private FrameLayout mFlWeltMapOverView; + private DriverMsgBoxButtonView mViewDriverMsgBoxButton; + private DriverMsgBoxListView mViewDriverMsgBoxList; + private DriverMsgBoxBubbleView mViewDriverMsgBoxBubble; + private ArrayList mWeltDataBeanList;//存储贴边数据 + private ArrayList mSubTaskCoordinates;//存储当前大任务的所有子任务起点和终点 + // 当前子任务的终点坐标 + protected LatLng mCurrentTaskEndStation; + private ArrayList mRouteList;//存储任务的坐标轨迹 + private String mProgress; + private ISweeperTaskDataToFragmentCallback mTaskDataToFragmentCallback; + + @Override + protected int getLayoutId() { + return R.layout.sweeper_base_fragment; + } + + private View panelView; + + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + + @Override + protected void initViews() { + mapBizView = findViewById(R.id.mapBizView); + groupTestPanel = findViewById(R.id.groupTestPanel); + mGroupNaviPanel = findViewById(R.id.group_navi_panel); + flTaskListPanelContainer = findViewById(R.id.module_mogo_och_task_list_container); + mTrafficDataView = findViewById(R.id.sweeper_arc); + panelView = LayoutInflater.from(getContext()).inflate(getTaskListPanelViewId(), flTaskListPanelContainer); + mSwitchMapModeImage = findViewById(R.id.sweeper_switch_model_icon); + mSettingBtn = findViewById(R.id.sweeper_setting_model_icon); + mCardBtn = findViewById(R.id.sweeper_card_model_icon); + mAICollectBtn = findViewById(R.id.sweeper_collect_model_icon); + mCloseNavIcon = findViewById(R.id.sweeper_close_navi_icon); + mRefreshNavi = findViewById(R.id.sweeper_refresh_navi); + mMapWeltView = findViewById(R.id.sweeper_task_welt_small_map); + mFlWeltMapOverView = findViewById(R.id.sweeper_welt_map_overview); + initListener(); + //设置消息盒子 + setMessageBox(); + //设置左下角四个按钮监听事件 + setBottomBtnListener(); + // 模拟 不可自动驾驶,目前场景是刚开机,adas还未和工控机连接 + findViewById(R.id.btnAutopilotDisable).setOnClickListener(view -> + debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE) + ); + + // 模拟 可自动驾驶,工控机连接正常,且处于人工干预状态 + findViewById(R.id.btnAutopilotEnable).setOnClickListener(view -> + debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE) + ); + + // 模拟 自动驾驶能力,自动驾驶中,可能是停车,可能是行进,但是是机器在处理车的前进后退,不是人 + findViewById(R.id.btnAutopilotRunning).setOnClickListener(view -> + debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) + ); + // 模拟 结束子任务 + findViewById(R.id.btnEndTask).setOnClickListener(view -> + debugEndSubTask() + ); + mTrafficDataView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + debugTestBar(); + return false; + } + }); + } + + private void updateSwitchMapIcon() { + IMogoMapUIController controller = CallerMapUIServiceManager.INSTANCE.getMapUIController(); + if (controller != null) { + if (controller.getCurrentMapVisualAngle().isLongSight()) { + mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_big_selector); + } else if (controller.getCurrentMapVisualAngle().isMediumSight()) { + mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_small_selector); + } else { + mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_small_selector); + } + } + } + + /** + * 设置任务进度 + * + * @param progress + */ + protected void setTaskProgress(String progress) { + ThreadUtils.runOnUiThread(() -> { + mMapWeltView.setTaskProgress(progress); + mProgress = progress; + if (mTaskDataToFragmentCallback != null) { + mTaskDataToFragmentCallback.setProgress(progress); + } + }); + } + + @Override + protected void initViews(Bundle savedInstanceState) { + super.initViews(savedInstanceState); + mapBizView.onCreate(savedInstanceState); + mMapWeltView.onCreateView(savedInstanceState); + } + + /** + * 消息盒子 + */ + private void setMessageBox() { + mViewDriverMsgBoxButton = findViewById(R.id.viewDriverMsgBoxButton); + mViewDriverMsgBoxList = findViewById(R.id.viewDriverMsgBoxList); + mViewDriverMsgBoxBubble = findViewById(R.id.viewDriverMsgBoxBubble); + //消息盒子 + mViewDriverMsgBoxButton.setClickListener(show -> { + if (show) { + mViewDriverMsgBoxList.setVisibility(View.VISIBLE); + mViewDriverMsgBoxList.notifyData(); + mViewDriverMsgBoxBubble.setVisibility(View.GONE); + mViewDriverMsgBoxBubble.isShowData(false); + } else { + mViewDriverMsgBoxList.setVisibility(View.GONE); + mViewDriverMsgBoxBubble.setVisibility(View.VISIBLE); + mViewDriverMsgBoxBubble.isShowData(true); + } + }); + } + + @Override + public void onPause() { + super.onPause(); + mMapWeltView.onPause(); + } + + @Override + public void onResume() { + super.onResume(); + mapBizView.onResume(); + mMapWeltView.onResume(); + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + mapBizView.onSaveInstanceState(outState); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapBizView.onLowMemory(); + } + + @Override + public void onDestroyView() { + mapBizView.onDestroy(); + super.onDestroyView(); + CallerAutopilotRecordListenerManager.INSTANCE.removeListener(TAG); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + view.setOnTouchListener(this); + + } + + private void initListener() { + MogoMapListenerHandler.Companion.getMogoMapListenerHandler().registerHostMapListener(TAG, this); + mCloseNavIcon.setOnClickListener(this); + mRefreshNavi.setOnClickListener(this); + mMapWeltView.getSwitchToBig().setOnClickListener((v) -> { + showOrHideOverMapViewFragment(true); + }); + } + + /** + * 清扫车任务列表面板view,在{@link #initViews()}时候添加到container中 + * + * @return 站点面板view + */ + public abstract int getTaskListPanelViewId(); + + /** + * 模拟自动驾驶返回状态 + * + * @param status + */ + public abstract void debugAutoPilotStatus(int status); + + /** + * 迈速表实时更新 + * + * @param newSpeed + */ + public void updateSpeedView(float newSpeed) { + int speed = (int) (Math.abs(newSpeed) * 3.6F); // 倒车时工控机反馈定位信息中speed为负值 + if (mTrafficDataView != null) { + mTrafficDataView.updateSpeedWithValue(speed); + } + } + + /** + * 车辆基本信息View + * + * @return + */ + public SweeperTrafficDataView getTrafficDataView() { + return mTrafficDataView; + } + + @Override + public void onDestroy() { + super.onDestroy(); + mMapWeltView.onDestroy(); + MogoMapListenerHandler.Companion.getMogoMapListenerHandler().unregisterHostMapListener(TAG); + } + + @Override + public void onMapVisualAngleChanged(VisualAngleMode visualAngleMode) { + if (visualAngleMode.isMediumSight()) { + mSwitchMapModeImage.setVisibility(View.VISIBLE); + } else if (visualAngleMode.isLongSight()) { + mSwitchMapModeImage.setVisibility(View.VISIBLE); + } else if (visualAngleMode.isCloseSight()) { + mSwitchMapModeImage.setVisibility(View.GONE); + } + } + + /** + * sweeper调试面板打开关闭 + */ + public void debugTestBar() { + if (groupTestPanel.getVisibility() == View.VISIBLE) { + groupTestPanel.setVisibility(View.GONE); + } else { + groupTestPanel.setVisibility(View.VISIBLE); + } + } + + /** + * 底部四个按钮监听 + * 1.地图放大缩小 + * 2.设置面板 + * 3.安全员问题上报面板 + * 4.道路状况上报面板 + */ + private void setBottomBtnListener() { + updateSwitchMapIcon(); + mSwitchMapModeImage.setOnClickListener(new OnPreventFastClickListener() { + @Override + public void onClickImpl(View v) { + IMogoMapUIController controller = CallerMapUIServiceManager.INSTANCE.getMapUIController(); + IMogoMarkerManager markerManager = CallerMapUIServiceManager.INSTANCE.getMarkerManager(AbsMogoApplication.getApp()); + if (controller != null && markerManager != null) { + //切换地图的远近视图 + if (controller.getCurrentMapVisualAngle().isLongSight()) { + // 2.11.0去掉 +// MogoMarkerManager.getInstance(AbsMogoApplication.getApp()).visibleAllMarkers(); + controller.changeMapVisualAngle(VisualAngleMode.MODE_MEDIUM_SIGHT, null); + mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_small_selector); + } else if (controller.getCurrentMapVisualAngle().isMediumSight()) { + // 2.11.0去掉 +// MogoMarkerManager.getInstance(AbsMogoApplication.getApp()) +// .inVisibleWithoutMarkers(DataTypes.TYPE_MARKER_ADAS, BusConst.TYPE_MARKER_BUS_ORDER); + controller.changeMapVisualAngle(VisualAngleMode.MODE_LONG_SIGHT, null); + mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_big_selector); + } else { + // 2.11.0去掉 +// MogoMarkerManager.getInstance(AbsMogoApplication.getApp()).visibleAllMarkers(); + controller.changeMapVisualAngle(VisualAngleMode.MODE_MEDIUM_SIGHT, null); + mSwitchMapModeImage.setImageResource(R.drawable.sweeper_switch_map_big_selector); + } + } + } + }); + mSettingBtn.setOnClickListener(v -> { + // TODO: 2021/12/9 + CallerHmiManager.INSTANCE.showToolsView(); + }); + if (mCardBtn != null) { + CallerDevaToolsManager.INSTANCE.initBadCase(mCardBtn); + } + if (mAICollectBtn != null) { + CallerDevaToolsManager.INSTANCE.initAiCollect(mAICollectBtn); + } + } + + + /** + * 展示人工驾驶地图导航 + */ + protected void showAmapNaviToStationFragment(boolean isShow) { + FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); + if (isShow) { + mGroupNaviPanel.setVisibility(View.VISIBLE); + if (mOchAmapNaviFragment == null) { + mOchAmapNaviFragment=SweeperAmapNaviFragment.newInstance(); + } + if (mOchAmapNaviFragment.isHidden()) { + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .show(mOchAmapNaviFragment).commitAllowingStateLoss(); + return; + } + if (mOchAmapNaviFragment.isAdded()) { + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .show(mOchAmapNaviFragment).commitAllowingStateLoss(); + return; + } + transaction + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .add(R.id.module_mogo_och_navi_panel_container, mOchAmapNaviFragment) + .show(mOchAmapNaviFragment).commitAllowingStateLoss(); + } else { + AmapNaviToDestinationModel.getInstance(getContext()).destroyAmaNavi(); + if (mOchAmapNaviFragment != null) { + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE) + .hide(mOchAmapNaviFragment).commitAllowingStateLoss(); + } + mGroupNaviPanel.setVisibility(View.GONE); + } + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.sweeper_close_navi_icon) { + showAmapNaviToStationFragment(false); + } else if (id == R.id.sweeper_refresh_navi) { + refreshNavi(); + } + } + + public abstract void refreshNavi(); + + /** + * 设置作业任务全览图隐藏或者显示 + * + * @param isShow + */ + public void showOrHideOverMapViewFragment(boolean isShow) { + FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); + if (isShow) { + mFlWeltMapOverView.setVisibility(View.VISIBLE); + if (mWeltMapOverViewFragment == null) { + mWeltMapOverViewFragment = mWeltMapOverViewFragment.newInstance( + (IWeltMapSwitchToSmallCallback) this, + mCurrentTaskEndStation, + mWeltDataBeanList, + mSubTaskCoordinates, + mRouteList, + mProgress, + (SweeperFragment) this); + } + if (mWeltMapOverViewFragment.isHidden()) { + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .show(mWeltMapOverViewFragment).commitAllowingStateLoss(); + return; + } + if (mWeltMapOverViewFragment.isAdded()) { + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .show(mWeltMapOverViewFragment).commitAllowingStateLoss(); + return; + } + transaction + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .add(R.id.sweeper_welt_map_overview, mWeltMapOverViewFragment) + .show(mWeltMapOverViewFragment).commitAllowingStateLoss(); + } else { + mFlWeltMapOverView.setVisibility(View.GONE); + if (mWeltMapOverViewFragment != null) { + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE) + .hide(mWeltMapOverViewFragment).commitAllowingStateLoss(); + } + } + } + + @Override + public void onWeltMapSwitchToSmall() { + showOrHideOverMapViewFragment(false); + } + + /** + * 设置贴边数据到地图 + * + * @param weltDataBeans + */ + public void setWeltDataToMap(ArrayList weltDataBeans, Boolean isWeltData, String distance) { + mWeltDataBeanList = weltDataBeans; + ThreadUtils.getSinglePool().execute(new Runnable() { + @Override + public void run() { + if (mMapWeltView != null) { + mMapWeltView.setWeltData(weltDataBeans, isWeltData, distance); + } + if (mTaskDataToFragmentCallback != null) { + mTaskDataToFragmentCallback.setWeltData(weltDataBeans, distance); + } + } + }); + } + + public void setTaskListCoordinatesLatLng(ArrayList subTaskCoordinates) { + this.mSubTaskCoordinates = subTaskCoordinates; + if (mMapWeltView != null) { + mMapWeltView.setTaskListCoordinatesLatLng(subTaskCoordinates); + } + if (mTaskDataToFragmentCallback != null) { + mTaskDataToFragmentCallback.setTaskListCoordinatesLatLng(subTaskCoordinates); + } + } + + public void setCurrentTaskEndMarker(LatLng subTaskCoordinate) { + if (mMapWeltView != null) { + mMapWeltView.setCurrentTaskCoordinatesLatLng(subTaskCoordinate); + } + if (mTaskDataToFragmentCallback != null) { + mTaskDataToFragmentCallback.setCurrentTaskCoordinatesLatLng(subTaskCoordinate); + } + } + + /** + * 清除marker标记和任务路线数据 + */ + public void clearAllMarkerAndPolyline() { + if (mMapWeltView != null) { + mMapWeltView.clearAllMarkerAndPolyline(); + } + if (mTaskDataToFragmentCallback != null) { + mTaskDataToFragmentCallback.clearAllMarkerAndPolyline(); + } + } + + /** + * 导航去目的地 + */ + public void startNaviToStation(Boolean isVoicePlay, double startLat, double startLng, double endLat, double endLng) { + AmapNaviToDestinationModel.getInstance(getContext()).destroyAmaNavi(); + NaviLatLng startNaviLatLng = new NaviLatLng(startLat, startLng); + NaviLatLng endNaviLatLng = new NaviLatLng(endLat, endLng); + AmapNaviToDestinationModel.getInstance(getContext()).initAMapNavi(startNaviLatLng, endNaviLatLng); + AmapNaviToDestinationModel.getInstance(getContext()).setVoiceIsMute(isVoicePlay); + } + + /** + * 设置任务轨迹点数据 + */ + public void setTaskRouteList(ArrayList routeList) { + mRouteList = routeList; + ThreadUtils.getSinglePool().execute(new Runnable() { + @Override + public void run() { + mMapWeltView.setRouteList(routeList); + if (mTaskDataToFragmentCallback != null) { + mTaskDataToFragmentCallback.setRouteList(routeList); + } + } + }); + } + + public static String format(double value) { + BigDecimal bd = new BigDecimal(value); + bd = bd.setScale(2, RoundingMode.HALF_UP); + return bd.toString(); + } + + public void setTaskDataToFragmentCallback(ISweeperTaskDataToFragmentCallback mTaskDataToFragmentCallback) { + this.mTaskDataToFragmentCallback = mTaskDataToFragmentCallback; + } + + /** + * 结束子任务 + */ + public void debugEndSubTask() { + ArrayList resultArrayList = tempData(); + setTaskRouteList(resultArrayList); + UiThreadHandler.postDelayed(() -> { + ArrayList routeList =tempData1(); + ArrayList weltDataBeans = new ArrayList<>(); + ArrayList subTaskCoordinates=new ArrayList<>(); + for (int i = 0; i < routeList.size(); i++) { + WeltDataBean weltDataBean = new WeltDataBean(); + weltDataBean.setLocLon(routeList.get(i).longitude); + weltDataBean.setLocLat(routeList.get(i).latitude); + weltDataBean.setWeltDistance(Math.random() * 50); + weltDataBeans.add(weltDataBean); + subTaskCoordinates.add(new LatLng(routeList.get(i).latitude,routeList.get(i).longitude)); + } + setTaskListCoordinatesLatLng(subTaskCoordinates); + setWeltDataToMap(weltDataBeans, true, format(Math.random() * 50)); + }, 2000); + } + + private ArrayList tempData() { + ArrayList results = new ArrayList<>(); + results.add(getRoute(116.41732262522,39.974576894194)); + results.add(getRoute(116.43963532201855,39.9752190287537)); + results.add(getRoute(116.4440910789222,39.96469276598098)); + results.add(getRoute(116.45254030604285,39.958762580403544)); + results.add(getRoute(116.46168616811329,39.94668171374373)); + return results; + } + private ArrayList tempData1() { + ArrayList results = new ArrayList<>(); + results.add(getRoute(116.41732262522,39.974576894194)); + results.add(getRoute(116.43963532201855,39.9752190287537)); + results.add(getRoute(116.4440910789222,39.96469276598098)); + return results; + } + private SweeperRoutePlanningUpdateReqBean.Result getRoute(double longitude,double latitude){ + SweeperRoutePlanningUpdateReqBean.Result result = new SweeperRoutePlanningUpdateReqBean.Result(); + result.latitude = latitude; + result.longitude =longitude; + return result; + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperUIFragment.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperUIFragment.java new file mode 100644 index 0000000000..3ee40b9134 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/BaseSweeperUIFragment.java @@ -0,0 +1,50 @@ +package com.mogo.och.sweeper.fragment; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +/** + * @author: wangmingjun + * @date: 2021/9/9 + */ +public abstract class BaseSweeperUIFragment extends Fragment { + private View mRootView; + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (mRootView == null) { + mRootView = inflater.inflate(getLayoutId(), container, false); + } else { + ViewGroup viewGroup = (ViewGroup) mRootView.getParent(); + if (viewGroup != null) { + viewGroup.removeView(mRootView); + } + } + initViews(mRootView); + initViews(savedInstanceState); + return mRootView; + } + /** + * 布局资源 + * + * @return + */ + protected abstract int getLayoutId(); + + protected abstract void initViews(View view); + + protected void initViews(Bundle savedInstanceState) { + } + + @Override + public void onDestroy() { + super.onDestroy(); + mRootView = null; + } +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/SweeperAmapNaviFragment.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/SweeperAmapNaviFragment.java new file mode 100644 index 0000000000..a1460e31c7 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/SweeperAmapNaviFragment.java @@ -0,0 +1,230 @@ +package com.mogo.och.sweeper.fragment; + +import android.os.Bundle; +import android.view.View; + +import com.amap.api.navi.AMapNaviViewListener; +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; +import com.mogo.och.common.module.map.AmapNaviToDestinationModel; +import com.mogo.och.common.module.map.CommonAmapNaviVIew; +import com.mogo.och.common.module.map.ICommonNaviChangedCallback; +import com.mogo.och.sweeper.R; + +import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_TAXI; + +/** + * @author: wangmingjun + * @date: 2021/11/30 + */ +public class SweeperAmapNaviFragment extends BaseSweeperUIFragment implements AMapNaviViewListener { + + private CommonAmapNaviVIew mAMapNaviView; + private ICommonNaviChangedCallback mNaviToStartInfoCallback; + public static SweeperAmapNaviFragment newInstance() { + + Bundle args = new Bundle(); + + SweeperAmapNaviFragment fragment = new SweeperAmapNaviFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + protected int getLayoutId() { + return R.layout.sweeper_amap_navi_view; + } + + @Override + protected void initViews(View view) { + mAMapNaviView = view.findViewById(R.id.navi_view); + } + + @Override + protected void initViews(Bundle savedInstanceState) { + super.initViews(savedInstanceState); + if (mAMapNaviView != null) + mAMapNaviView.onCreate(savedInstanceState); + } + + @Override + public void onResume() { + super.onResume(); + if (mAMapNaviView != null) + mAMapNaviView.onResume(); + } + + @Override + public void onPause() { + super.onPause(); + if (mAMapNaviView != null) + mAMapNaviView.onPause(); + } + + @Override + public void onHiddenChanged(boolean hidden) { + super.onHiddenChanged(hidden); + if (hidden) { //不在最前端界面显示 + if (mAMapNaviView != null){ + mAMapNaviView.onPause(); + } + } else { //重新显示到最前端 + if (mAMapNaviView != null){ + mAMapNaviView.onResume(); + } + } + } + @Override + public void onDestroy() { + super.onDestroy(); + + AmapNaviToDestinationModel.getInstance(getContext()).setVoiceIsMute(false); + if (mAMapNaviView != null){ + mAMapNaviView.onDestroy(); + } + + if (mNaviToStartInfoCallback != null){ + mNaviToStartInfoCallback = null; + } + } + + @Override + public void onNaviSetting() { + //底部导航设置点击回调 + } + + @Override + public void onNaviCancel() { + } + + @Override + public void onNaviMapMode(int naviMode) { + //导航态车头模式,0:车头朝上状态;1:正北朝上模式。 + } + + @Override + public void onNaviTurnClick() { + //转弯view的点击回调 + } + + @Override + public void onNextRoadClick() { + //下一个道路View点击回调 + } + + + @Override + public void onScanViewButtonClick() { + //全览按钮点击回调 + } + + + @Override + public void onLockMap(boolean isLock) { + //锁地图状态发生变化时回调 + } + + @Override + public void onNaviViewLoaded() { + CallerLogger.INSTANCE.d(M_TAXI + "wlx", "导航页面加载成功"); + CallerLogger.INSTANCE.d(M_TAXI + "wlx", "请不要使用AMapNaviView.getMap().setOnMapLoadedListener();会overwrite导航SDK内部画线逻辑"); + } + + @Override + public void onMapTypeChanged(int i) { + + } + + @Override + public void onNaviViewShowMode(int i) { + + } + + @Override + public boolean onNaviBackClick() { + return false; + } + + /** + * 车道信息说明: + *

+ * 0xFF, 无对应车道 + * 0, 直行 + * 1, 左转 + * 2, 直行+左转 + * 3, 右转 + * 4, 直行+右转 + * 5, 左掉头 + * 6, 左转+右转 + * 7, 直行+左转+右转 + * 8, 右掉头 + * 9, 直行+左掉头 + * 10, 直行+右掉头 + * 11, 左转+左掉头 + * 12, 右转+右掉头 + * 13, 直行+扩展 + * 14, 左转+左掉头+扩展 + * 15, 保留 + * 16, 直行+左转+左掉头 + * 17, 右转+左掉头 + * 18, 左转+右转+左掉头 + * 19, 直行+右转+左掉头 + * 20, 左转+右掉头 + * 21, 公交车道 + * 22, 空车道 + * 23 可变车道 + */ + + String[] array = { + "直行车道" + , "左转车道" + , "左转或直行车道" + , "右转车道" + , "右转或直行车道" + , "左掉头车道" + , "左转或者右转车道" + , " 左转或右转或直行车道" + , "右转掉头车道" + , "直行或左转掉头车道" + , "直行或右转掉头车道" + , "左转或左掉头车道" + , "右转或右掉头车道" + , "直行并且车道扩展" + , "左转+左掉头+扩展" + , "不可以选择该车道" + , "直行+左转+左掉头车道" + , "右转+左掉头" + , "左转+右转+左掉头" + , "直行+右转+左掉头" + , "左转+右掉头" + , "公交车道" + , "空车道" + , "可变车道" + }; + + String[] actions = { + "直行" + , "左转" + , "左转或直行" + , "右转" + , "右转或这行" + , "左掉头" + , "左转或者右转" + , " 左转或右转或直行" + , "右转掉头" + , "直行或左转掉头" + , "直行或右转掉头" + , "左转或左掉头" + , "右转或右掉头" + , "直行并且车道扩展" + , "左转+左掉头+扩展" + , "不可以选择" + , "直行+左转+左掉头" + , "右转+左掉头" + , "左转+右转+左掉头" + , "直行+右转+左掉头" + , "左转+右掉头" + , "公交车道" + , "空车道" + , "可变车道" + }; +} diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/SweeperFragment.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/SweeperFragment.kt new file mode 100644 index 0000000000..de0eae391b --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/SweeperFragment.kt @@ -0,0 +1,527 @@ +package com.mogo.och.sweeper.fragment + +import android.graphics.Color +import android.os.Bundle +import android.view.View +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import chassis.ChassisStatesOuterClass +import com.amap.api.maps.model.LatLng +import com.mogo.commons.AbsMogoApplication +import com.mogo.eagle.core.data.map.MogoLocation +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import com.mogo.eagle.core.utilcode.util.ClickUtils +import com.mogo.eagle.core.utilcode.util.ToastUtils +import com.mogo.och.common.module.utils.CoordinateCalculateRouteUtil +import com.mogo.och.sweeper.R +import com.mogo.och.sweeper.bean.* +import com.mogo.och.sweeper.constant.SubTaskTypeEnum +import com.mogo.och.sweeper.constant.TaskStatusEnum +import com.mogo.och.sweeper.database.MyDataBase +import com.mogo.och.sweeper.presenter.SweeperPresenter +import com.mogo.och.sweeper.ui.adapter.TaskListAdapter +import com.mogo.och.sweeper.ui.dialog.SweeperManualDrivingDialog +import com.mogo.och.sweeper.ui.dialog.SweeperNoTitleCommonDialog +import com.mogo.och.sweeper.ui.popwindow.MenuPopWindow +import kotlinx.android.synthetic.main.fragment_och_sweeper.* +import kotlinx.android.synthetic.main.sweeper_current_task_info.view.* +import kotlinx.android.synthetic.main.sweeper_no_data_common_view.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlin.math.roundToInt + +/** + * 清扫车主界面 + */ +class SweeperFragment : BaseSweeperTabFragment(), MenuPopWindow.OnMenuItemOnClickListener { + + companion object { + const val TAG = "SweeperFragment" + } + + private var mAdapter: TaskListAdapter? = null + private var mCurrentSubPosition: Int = 0 //子任务下标 + private var mSubMutableList: MutableList? = null + private var mSubTaskBean: SweeperSubTaskBean? = null + private var mSubTaskType: SubTaskTypeEnum = SubTaskTypeEnum.AUTOPILOT_SUBTYPE //1:自动驾驶子任务 2:人工驾驶子任务 + private var mCleanSystemState: ChassisStatesOuterClass.SweeperFuTianTaskSystemStates? = null + private var mMainTask: SweeperMainTaskBean? = null + private var mLocation: MogoLocation? = null + private var mSubInfo: SubInfo? = null + + override fun getTagName(): String { + return "SweepersFragment" + } + + override fun initViews() { + super.initViews() + mAdapter = context?.let { TaskListAdapter() } + val linearLayoutManager = LinearLayoutManager(context) + linearLayoutManager.orientation = LinearLayoutManager.VERTICAL + rvTaskList?.layoutManager = linearLayoutManager + rvTaskList?.adapter = mAdapter + mAdapter?.setOnTaskItemClickListener(onTaskItemClickListener) + initListener() + sweeper_cl_work_mode.setTrafficDataView(trafficDataView) + sweeper_current_task_view.readyTaskBtn.setOnClickListener { + if (ClickUtils.isFastClick()) {//防止重复点击 + if (mSubTaskType.code == SubTaskTypeEnum.MANUAL_DRIVING_SUBTYPE.code) { + manualDriving(false) + } else { + //开始执行任务 + mSubInfo?.apply { + presenter?.startTask(isFirstSubTask(), isLastSubTask(), taskId, mSubTaskType, taskStatus) + } + } + } + } + } + + override fun createPresenter(): SweeperPresenter { + return SweeperPresenter(this) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + mPresenter?.getCurrentTask() + } + + override fun getTaskListPanelViewId(): Int { + return R.layout.fragment_och_sweeper + } + + /** + * 任务列表面板隐藏或显示 + * + * @return + */ + private fun setShowTaskListPanelView(isShow: Boolean) { + tvTaskConfirm.setTextColor(Color.parseColor("#66FFFFFF")) + tvTaskConfirm.isSelected = false + if (isShow) { + sweeper_current_task_list_view.visibility = View.VISIBLE + } else { + sweeper_current_task_list_view.visibility = View.GONE + } + } + + /** + * 当前任务面板隐藏或显示 + * + * @return + */ + private fun setShowCurrentTaskPanelView(isShow: Boolean) { + if (isShow) { + sweeper_current_task_view.visibility = View.VISIBLE + } else { + sweeper_current_task_view.visibility = View.GONE + } + } + + /** + * VR模式切换 + * + * @param isVRMode + */ + fun onVRModeChanged(isVRMode: Boolean) { + if (mRootView != null) { + mRootView.visibility = if (isVRMode) View.VISIBLE else View.GONE + } + } + + fun hideOchSweeper() {} + override fun debugAutoPilotStatus(status: Int) { + mPresenter?.debugAutoPilotStatus(status) + } + + /** + * 根据自动驾驶状态更新按钮 + */ + fun startAutoBtn(autopilotState: Int) { + sweeper_current_task_view.setStartAutoBtn(autopilotState) + } + + /** + * 任务按钮状态 + */ + fun setTaskBtn(isWorking: Boolean) { + sweeper_current_task_view.setEnableClickBtn(isWorking) + } + + /** + * 设置各种监听事件 + */ + private fun initListener() { + tvTaskConfirm.setOnClickListener { + mMainTask?.let { task -> + mCurrentSubPosition = 0 + mSubTaskBean = SweeperSubTaskBean(task.mainTaskId, task.mainTaskName, task.mainTaskStartTime, 1, mSubMutableList) + //获取当前子任务列表 + presenter?.getSubTaskList(task.mainTaskId, mSubTaskBean) + mAdapter?.selectPosition(-1) + } + } + //列表任务刷新 + ivTaskListRefresh.setOnClickListener { + mPresenter?.getMainTaskList(true) + } + //无任务时刷新 + ivNoTaskRefresh.setOnClickListener { + mPresenter?.getMainTaskList(true) + } + } + + private val onTaskItemClickListener = object : TaskListAdapter.TaskItemClickListener { + override fun onItemClick(position: Int, mainTask: SweeperMainTaskBean) { + mAdapter?.selectPosition(position) + tvTaskConfirm.isSelected = true + tvTaskConfirm.setTextColor(Color.parseColor("#FFFFFFFF")) + this@SweeperFragment.mMainTask = mainTask + } + + } + + override fun onMenuItemClick(itemType: TaskStatusEnum) { + when (itemType.code) { + TaskStatusEnum.JUMP_OVER_SUBTASK.code -> {//跳过任务 + mSubInfo?.let { + //如果当前只有一个子任务,则isFirst设置为false + presenter?.subTaskSkip(if (mSubMutableList?.size == 1) false else isFirstSubTask(), isLastSubTask(), it.taskId) + } + } + TaskStatusEnum.END_TASK.code -> {//结束主任务 + endMainTask() + } + } + } + + fun onSweeperFutianCleanSystemState(cleanSystemState: ChassisStatesOuterClass.SweeperFuTianTaskSystemStates) { + lifecycleScope.launch(Dispatchers.Main) { + mCleanSystemState = cleanSystemState + sweeper_cl_work_mode.setSweeperFutianCleanSystemState(mSubTaskType, cleanSystemState) + } + } + + /** + * 设置当前主任务列表数据 + */ + fun setMainTaskList(mainTaskBeanList: MutableList?, refresh: Boolean) { + setShowCurrentTaskPanelView(false) + setShowTaskListPanelView(true) + sweeper_cl_work_mode.visibility = View.GONE + if (mainTaskBeanList != null && mainTaskBeanList.isNotEmpty()) { + noTaskDataView.visibility = View.GONE + sweeperListCl.visibility = View.VISIBLE + mAdapter?.setTaskListData(mainTaskBeanList) + } else { + noTaskDataView.visibility = View.VISIBLE + sweeperListCl.visibility = View.GONE + } + if (refresh) { + ToastUtils.showLong("已刷新") + } + } + + /** + * 设置当前子任务列表数据 + */ + fun setSubTaskBean(subTaskBean: SweeperSubTaskBean, isWorkingSubTask: Boolean) { + this.mSubTaskBean = subTaskBean + this.mSubTaskBean?.let { + setShowCurrentTaskPanelView(true) + setShowTaskListPanelView(false) + sweeper_cl_work_mode.visibility = View.VISIBLE + mCurrentSubPosition = if (isWorkingSubTask) {//如果是正在执行的子任务 + it.sort - 1 + } else { + 0 + } + d(SceneConstant.M_SWEEPER + TAG, "setSubTaskBean mCurrentSubPosition:$mCurrentSubPosition") + sweeper_current_task_view.setData(sweeper_cl_work_mode, it, mCurrentSubPosition, this, presenter) + mSubMutableList = it.subList + setSubTaskData() + if (mSubTaskType.code == SubTaskTypeEnum.AUTOPILOT_SUBTYPE.code) {//自动驾驶子任务需要调用详情 + mSubInfo?.let { subInfo -> + presenter?.getSubTaskDetail(isFirstSubTask(), isLastSubTask(), subInfo.taskId, mSubTaskType, false)//加载子任务详情包括轨迹信息 + } + } + mMainTask = SweeperMainTaskBean(it.taskId, it.taskName, 0, it.taskStartTime) + clearAllMarkerAndPolyline() + addWeltData() + } + } + + /** + * 更新子任务状态 + */ + fun updateSubTaskStatus(typeEnum: TaskStatusEnum, isLastSubTask: Boolean) { + if (isLastSubTask) { + showAmapNaviToStationFragment(false) + clearAllMarkerAndPolyline() + //整个大任务结束,则删除它相关的贴边数据缓存 + lifecycleScope.launch(Dispatchers.IO) { + MyDataBase.getInstance().weltDataDao.deleteAllWeltData() + mPresenter?.clearRouteList() + } + setTaskProgress("0") + + val builder = SweeperManualDrivingDialog.Builder() + val endConfirmDialog = builder + .tips("任务已完成") + .confirmStr("确认") + .build(requireContext()) + endConfirmDialog?.setClickListener(object: SweeperManualDrivingDialog.ClickListener{ + override fun confirm() { + mPresenter?.getMainTaskList(false) + } + }) + endConfirmDialog?.show() + return + } + when (typeEnum.code) { + TaskStatusEnum.END_SUBTASK.code -> {//子任务结束 + mCurrentSubPosition++ + setSubTaskData() + d(SceneConstant.M_SWEEPER + TAG, "END_SUBTASK mCurrentSubPosition:$mCurrentSubPosition") + if (mSubTaskType.code == SubTaskTypeEnum.AUTOPILOT_SUBTYPE.code) {//自动驾驶子任务 + //关闭人工驾驶导航 + showAmapNaviToStationFragment(false) + mSubInfo?.apply { + presenter?.getSubTaskDetail(isFirstSubTask(), isLastSubTask(), taskId, mSubTaskType, true) + } + sweeper_current_task_view.setCurrentData(mCurrentSubPosition) + } else { + manualDriving(true) + } + } + TaskStatusEnum.JUMP_OVER_SUBTASK.code -> { //子任务跳过 + //是否是最后一个子任务结束 + mCurrentSubPosition++ + setSubTaskData() + d(SceneConstant.M_SWEEPER + TAG, "JUMP_OVER_SUBTASK mCurrentSubPosition:$mCurrentSubPosition") + showAmapNaviToStationFragment(false) + if (mSubTaskType.code == SubTaskTypeEnum.AUTOPILOT_SUBTYPE.code) {//自动驾驶子任务 + //关闭人工驾驶导航 + showAmapNaviToStationFragment(false) + mSubInfo?.apply { + presenter?.getSubTaskDetail(isFirstSubTask(), isLastSubTask(), taskId, mSubTaskType, true) + } + sweeper_current_task_view.setCurrentData(mCurrentSubPosition) + } else { + manualDriving(true) + } + } + TaskStatusEnum.START_SUBTASK.code -> { //子任务开始 + setTaskBtn(true) + sweeper_current_task_view.setTaskStatus(2) + if (mSubTaskType == SubTaskTypeEnum.MANUAL_DRIVING_SUBTYPE) { + sweeper_current_task_view.setCurrentData(mCurrentSubPosition) + } + } + } + setEndStationMarker() + } + + /** + * 主任务重置 + */ + fun setMainTaskReset(isSuccess: Boolean) { + if (isSuccess) { + //任务重置后,重新拉取任务列表数据 + mPresenter?.getMainTaskList(false) + //清除任务全览图的marker和路线 + clearAllMarkerAndPolyline() + showAmapNaviToStationFragment(false) + setTaskProgress("0") + //整个大任务结束,则删除它相关的贴边数据缓存 + lifecycleScope.launch(Dispatchers.IO) { + MyDataBase.getInstance().weltDataDao.deleteAllWeltData() + mPresenter?.clearRouteList() + } + } + } + + /** + * 设置当前选中的子任务信息 + */ + private fun setSubTaskData() { + mSubMutableList?.let { + mSubInfo = it[mCurrentSubPosition] + mSubTaskType = if (it[mCurrentSubPosition].taskType == SubTaskTypeEnum.AUTOPILOT_SUBTYPE.code) + SubTaskTypeEnum.AUTOPILOT_SUBTYPE else SubTaskTypeEnum.MANUAL_DRIVING_SUBTYPE + //设置当前子任务信息 + presenter?.setSubtask(isFirstSubTask(), isLastSubTask(), it[mCurrentSubPosition].taskId, it[mCurrentSubPosition].taskType) + } + /** + * 计算任务的进度 + */ + lifecycleScope.launch(Dispatchers.IO) { + mSubMutableList?.let { + var sum: Double = 0.0 + for (index in it.indices) { + sum += it[index].mileage + } + var completed: Double = 0.0 + for (index in it.indices) { + if (index < mCurrentSubPosition) { + // 已完成的子任务记入完成度,进行中的不计入 + completed += it[index].mileage + } + } + val progress = "${((completed / sum) * 100.0).roundToInt()}%" + setTaskProgress(progress) + } + + } + } + /** + * 结束主任务 + */ + private fun endMainTask() { + //结束任务 + val builder = SweeperNoTitleCommonDialog.Builder() + val endConfirmDialog = builder + .tips("是否结束任务?") + .confirmStr("确认") + .cancelStr("取消") + .build(requireContext()) + endConfirmDialog?.setClickListener(object : SweeperNoTitleCommonDialog.ClickListener { + override fun confirm() { + mMainTask?.let { + presenter?.mainTaskReset(it.mainTaskId) + } + } + + override fun cancel() { + endConfirmDialog?.dismiss() + } + }) + endConfirmDialog?.show() + } + + /** + * 人工驾驶子任务 + */ + private fun manualDriving(isCancelAutoPoilot: Boolean) { + if (isCancelAutoPoilot) { // 人工子任务 先取消自动驾驶 + CallerAutoPilotStatusListenerManager.updateAutopilotControlParameters(null) + CallerAutoPilotControlManager.cancelAutoPilot() + } + + mSubInfo?.apply { + val builder = SweeperManualDrivingDialog.Builder() + val endConfirmDialog = builder + .tips("前方子任务${taskName}请人工驾驶至(${endSiteName})") + .confirmStr("确认") + .build(requireContext()) + endConfirmDialog?.setClickListener(object : SweeperManualDrivingDialog.ClickListener { + override fun confirm() { + presenter?.startTask(isFirstSubTask(), isLastSubTask(), taskId, mSubTaskType, taskStatus) + val startPoint = + CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj(AbsMogoApplication.getApp(), startWgs84Lon, startWgs84Lat) + val endPoint = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj(AbsMogoApplication.getApp(), endWgs84Lon, endWgs84Lat) + startNaviToStation( + true, + startPoint.latitude, + startPoint.longitude, + endPoint.latitude, + endPoint.longitude + ) + showAmapNaviToStationFragment(true) + } + }) + endConfirmDialog?.show() + } + } + + /** + * 是否第一个子任务 + */ + fun isFirstSubTask(): Boolean { + return mCurrentSubPosition == 0 + } + + /** + * 是否最后一个子任务 + */ + fun isLastSubTask(): Boolean { + return mCurrentSubPosition == (mSubMutableList?.size?.minus(1)) + } + + /** + * 当前位置经纬度 + */ + fun setCurrentLocation(location: MogoLocation) { + this.mLocation = location + } + + override fun refreshNavi() { + mSubInfo?.apply { + mLocation?.let { + val endPoint = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj(AbsMogoApplication.getApp(), endWgs84Lon, endWgs84Lat) + startNaviToStation(true, it.latitude, it.longitude, endPoint.latitude, endPoint.longitude) + } + } + } + + private fun addWeltData() { + lifecycleScope.launch(Dispatchers.IO) { + mSubMutableList?.let { subList -> + if (subList.size <= 0) { + return@launch + } + val dataList = ArrayList() + for (index in subList.indices) { + val startPoint = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj( + AbsMogoApplication.getApp(), + subList[index].startWgs84Lon, + subList[index].startWgs84Lat + ) + val startLatLng = LatLng(startPoint.latitude, startPoint.longitude) + dataList.add(index,startLatLng) + val endPoint = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj( + AbsMogoApplication.getApp(), + subList[index].endWgs84Lon, + subList[index].endWgs84Lat + ) + val endLatLng = LatLng(endPoint.latitude, endPoint.longitude) + dataList.add(index+1,endLatLng) + } + setTaskListCoordinatesLatLng(dataList) + setEndStationMarker() + } + } + } + + private fun setEndStationMarker(){ + lifecycleScope.launch(Dispatchers.IO) { + mSubInfo?.let { + val endPoint = CoordinateCalculateRouteUtil.coordinateConverterWgsToGcj( + AbsMogoApplication.getApp(), + it.endWgs84Lon, + it.endWgs84Lat + ) + super.mCurrentTaskEndStation = endPoint + setCurrentTaskEndMarker(endPoint) + } + } + } + + + + //模拟结束子任务 + override fun debugEndSubTask() { + mPresenter?.onArriveTaskEnd(null) + //super.debugEndSubTask() + } + + /** + * 设置路线轨迹 + */ + override fun setTaskRouteList(routeList: ArrayList) { + super.setTaskRouteList(routeList) + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/WeltMapOverViewFragment.kt b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/WeltMapOverViewFragment.kt new file mode 100644 index 0000000000..a34f658856 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/fragment/WeltMapOverViewFragment.kt @@ -0,0 +1,129 @@ +package com.mogo.och.sweeper.fragment + +import android.os.Bundle +import com.amap.api.maps.model.LatLng +import com.mogo.commons.mvp.BaseFragment +import com.mogo.och.sweeper.R +import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean +import com.mogo.och.sweeper.callback.ISweeperTaskDataToFragmentCallback +import com.mogo.och.sweeper.callback.IWeltMapSwitchToSmallCallback +import com.mogo.och.sweeper.database.bean.WeltDataBean +import kotlinx.android.synthetic.main.fragment_welt_map_overview.* +import kotlinx.android.synthetic.main.sweeper_welt_map_overview.* + +/** + * 作业任务全览图 + */ +class WeltMapOverViewFragment() : BaseFragment(), ISweeperTaskDataToFragmentCallback { + private var mIWeltMapSwitchToSmallCallBack: IWeltMapSwitchToSmallCallback? = null + private var mFragment: SweeperFragment? = null + override fun getLayoutId(): Int = R.layout.fragment_welt_map_overview + override fun getTagName(): String { + return "WeltMapOverViewFragment" + } + + override fun initViews() { + + } + fun setWeltMapSwitchToSmallCallBack(iWeltMapSwitchToSmallCallback: IWeltMapSwitchToSmallCallback){ + this.mIWeltMapSwitchToSmallCallBack=iWeltMapSwitchToSmallCallback + } + fun setSweeperFragment(fragment: SweeperFragment){ + this.mFragment=fragment + mFragment?.setTaskDataToFragmentCallback(this) + } + override fun initViews(savedInstanceState: Bundle?) { + super.initViews(savedInstanceState) + weltMapOverView?.onCreateView(savedInstanceState) + sweeperSwitchToSmall.setOnClickListener { + mIWeltMapSwitchToSmallCallBack?.onWeltMapSwitchToSmall() + } + val bundle = arguments + if (bundle != null) { + val latLngs = bundle.getSerializable("subTaskCoordinates") as? ArrayList + val latLng = bundle.getParcelable("subTaskEndCoordinates") + val weltDataList = bundle.getSerializable("weltDataList") as? ArrayList + val routeList = bundle.getSerializable("routeList") as? ArrayList + val progress = bundle.getString("progress") + routeList?.let { + weltMapOverView?.setRouteList(it) + } + latLng?.let { + setCurrentTaskCoordinatesLatLng(it) + } + latLngs?.let { + setTaskListCoordinatesLatLng(it) + } + weltDataList?.let { + setWeltData(it,"0.0cm") + } + progress?.let { + weltMapOverView?.setProgress(progress) + } + } + + } + + companion object { + @JvmStatic + fun newInstance( + mIWeltMapSwitchToSmallCallBack: IWeltMapSwitchToSmallCallback, + mCurrentTaskEndStation:LatLng?, + weltDataList: ArrayList?, + latLngs: ArrayList?, + routeList: ArrayList?, + progress:String?, + sweeperFragment: SweeperFragment + ): WeltMapOverViewFragment { + val args = Bundle() + args.putSerializable("weltDataList", weltDataList) + args.putSerializable("subTaskCoordinates", latLngs) + args.putParcelable("subTaskEndCoordinates", mCurrentTaskEndStation) + args.putSerializable("routeList", routeList) + args.putString("progress", progress) + val fragment = WeltMapOverViewFragment() + fragment.setWeltMapSwitchToSmallCallBack(mIWeltMapSwitchToSmallCallBack) + fragment.setSweeperFragment(sweeperFragment) + fragment.arguments = args + return fragment + } + } + + override fun onPause() { + super.onPause() + weltMapOverView?.onPause() + } + + override fun onResume() { + super.onResume() + weltMapOverView?.onResume() + } + + override fun onDestroy() { + super.onDestroy() + weltMapOverView?.onDestroy() + } + override fun setTaskListCoordinatesLatLng(coordinatesLatLng: java.util.ArrayList) { + weltMapOverView?.setTaskListCoordinatesLatLng(coordinatesLatLng) + } + + override fun setCurrentTaskCoordinatesLatLng(coordinatesLatLng: LatLng) { + weltMapOverView?.setCurrentTaskCoordinatesLatLng(coordinatesLatLng) + } + + override fun clearAllMarkerAndPolyline() { + weltMapOverView?.clearAllMarkerAndPolyline() + } + + override fun setProgress(progress: String) { + weltMapOverView?.setProgress(progress) + } + + override fun setRouteList(routeList: java.util.ArrayList) { + weltMapOverView?.setRouteList(routeList) + } + + override fun setWeltData(weltDatas: java.util.ArrayList?, distance: String) { + weltMapOverView?.setWeltData(weltDatas,true,distance) + } +} \ No newline at end of file diff --git a/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/model/SweeperTaskModel.java b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/model/SweeperTaskModel.java new file mode 100644 index 0000000000..3022c92a28 --- /dev/null +++ b/OCH/sweeper/sweeper-cloud/src/main/java/com/mogo/och/sweeper/model/SweeperTaskModel.java @@ -0,0 +1,891 @@ +package com.mogo.och.sweeper.model; + +import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_SWEEPER; + +import android.content.Context; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.amap.api.maps.model.LatLng; +import com.elegant.network.utils.GsonUtil; +import com.mogo.aicloud.services.socket.IMogoOnMessageListener; +import com.mogo.commons.AbsMogoApplication; +import com.mogo.commons.module.status.IMogoStatusChangedListener; +import com.mogo.commons.module.status.MogoStatusManager; +import com.mogo.commons.module.status.StatusDescriptor; +import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters; +import com.mogo.eagle.core.data.config.FunctionBuildConfig; +import com.mogo.eagle.core.data.map.MogoLocation; +import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; +import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener; +import com.mogo.eagle.core.function.api.autopilot.IMoGoPlanningRottingListener; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager; +import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager; +import com.mogo.eagle.core.function.call.autopilot.CallerPlanningRottingListenerManager; +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; +import com.mogo.eagle.core.utilcode.util.CoordinateUtils; +import com.mogo.eagle.core.utilcode.util.NetworkUtils; +import com.mogo.eagle.core.utilcode.util.ToastUtils; +import com.mogo.och.common.module.biz.common.socketmessage.OCHSocketMessageManager; +import com.mogo.och.common.module.biz.common.socketmessage.data.OCHOperationalMessage; +import com.mogo.och.common.module.biz.network.OchCommonServiceCallback; +import com.mogo.och.common.module.callback.OchAdasStartFailureCallback; +import com.mogo.och.common.module.manager.OCHAdasAbilityManager; +import com.mogo.och.common.module.utils.CoordinateCalculateRouteUtil; +import com.mogo.och.common.module.utils.NumberFormatUtil; +import com.mogo.och.common.module.utils.PinYinUtil; +import com.mogo.och.common.module.utils.ToastUtilsOch; +import com.mogo.och.common.module.voice.VoiceNotice; +import com.mogo.och.sweeper.R; +import com.mogo.och.sweeper.bean.BaseResponse; +import com.mogo.och.sweeper.bean.SubInfo; +import com.mogo.och.sweeper.bean.SweeperMainTaskBean; +import com.mogo.och.sweeper.bean.SweeperRoutePlanningUpdateReqBean; +import com.mogo.och.sweeper.bean.SweeperSubTaskBean; +import com.mogo.och.sweeper.bean.SweeperSubTaskDetailBean; +import com.mogo.och.sweeper.callback.ISweeperADASStatusCallback; +import com.mogo.och.sweeper.callback.ISweeperControllerStatusCallback; +import com.mogo.och.sweeper.callback.ISweeperTaskCallback; +import com.mogo.och.sweeper.constant.SubTaskTypeEnum; +import com.mogo.och.sweeper.constant.SweeperConst; +import com.mogo.och.sweeper.constant.TaskStatusEnum; +import com.mogo.och.sweeper.net.SweeperServiceManager; +import com.mogo.och.sweeper.util.SweeperAnalyticsManager; +import com.mogo.och.sweeper.util.SweeperTrajectoryManager; + +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.exceptions.UndeliverableException; +import io.reactivex.functions.Consumer; +import io.reactivex.plugins.RxJavaPlugins; +import mogo.telematics.pad.MessagePad; + +/** + * @author congtaowang + * @since 2021/3/23 + *

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